diff options
885 files changed, 25271 insertions, 9760 deletions
diff --git a/Android.bp b/Android.bp index 709929139fad..72fc1030b63b 100644 --- a/Android.bp +++ b/Android.bp @@ -344,8 +344,8 @@ filegroup { 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 @@ java_library { "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 @@ java_library { } 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 @@ genrule { 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 @@ filegroup { java_library { name: "framework-annotations-lib", - srcs: [ ":framework-annotations" ], + srcs: [":framework-annotations"], sdk_version: "core_current", } @@ -1160,7 +1161,6 @@ cc_library { }, } - // 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 @@ filegroup { 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 @@ java_library { "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 @@ java_library { ":protolog-common-src", ], } + // protolog end diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index 30ed7de92614..175fb38bafc7 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 @@ clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp 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 168c7c2f13cd..5ded446ff81a 100644 --- a/apex/appsearch/framework/api/current.txt +++ b/apex/appsearch/framework/api/current.txt @@ -207,7 +207,6 @@ package android.app.appsearch { 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 @@ package android.app.appsearch { 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 @@ package android.app.appsearch { 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 @@ package android.app.appsearch { 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 6a5975ef7ff7..da446bf1e7c6 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 @@ public class AppSearchManager { 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 24cc60e5eef5..f379739a3778 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 @@ public final class AppSearchSession implements Closeable { 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 8dd9dc1be312..fb63e16aa6a8 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 @@ public class GlobalSearchSession implements Closeable { * 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 68ae23f9a9db..ba27762c7dfb 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 @@ interface IAppSearchManager { * @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 @@ interface IAppSearchManager { 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 c927e3412cbc..17266f82b603 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 @@ public final class GetByUriRequest { * 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 d792f450bc05..f34034b1c5c0 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 final class SearchResult { */ 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 @@ public final class SearchResult { 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 @@ public final class SearchResult { } /** 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 @@ public final class SearchResult { 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 f72f8e1bbc5d..7888c8d78cd8 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 @@ public final class SearchSpec { */ @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 426a903981b3..c05406358995 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 @@ import java.util.Set; */ 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 @@ public final class SetSchemaRequest { } /** + * 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 final class SetSchemaRequest { */ 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 @@ public final class SetSchemaRequest { * * <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 @@ public final class SetSchemaRequest { } /** + * 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 @@ public final class SetSchemaRequest { 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 @@ public final class SetSchemaRequest { 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 a45fa39bd58d..27c9ccb2cca6 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 @@ public class AppSearchManagerService extends SystemService { @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 @@ public class AppSearchManagerService extends SystemService { } 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 @@ public class AppSearchManagerService extends SystemService { 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 @@ public class AppSearchManagerService extends SystemService { 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 @@ public class AppSearchManagerService extends SystemService { 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 @@ public class AppSearchManagerService extends SystemService { verifyUserUnlocked(callingUserId); verifyCallingPackage(callingUid, packageName); AppSearchImpl impl = - mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId); + mImplInstanceManager.getAppSearchImpl(callingUserId); SearchResultPage searchResultPage = impl.query( packageName, @@ -311,7 +310,7 @@ public class AppSearchManagerService extends SystemService { verifyUserUnlocked(callingUserId); verifyCallingPackage(callingUid, packageName); AppSearchImpl impl = - mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId); + mImplInstanceManager.getAppSearchImpl(callingUserId); SearchResultPage searchResultPage = impl.globalQuery( queryExpression, @@ -342,7 +341,7 @@ public class AppSearchManagerService extends SystemService { try { verifyUserUnlocked(callingUserId); AppSearchImpl impl = - mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId); + mImplInstanceManager.getAppSearchImpl(callingUserId); SearchResultPage searchResultPage = impl.getNextPage(nextPageToken); invokeCallbackOnResult( callback, @@ -362,7 +361,7 @@ public class AppSearchManagerService extends SystemService { 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 @@ public class AppSearchManagerService extends SystemService { 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 @@ public class AppSearchManagerService extends SystemService { 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 @@ public class AppSearchManagerService extends SystemService { verifyUserUnlocked(callingUserId); verifyCallingPackage(callingUid, packageName); AppSearchImpl impl = - mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId); + mImplInstanceManager.getAppSearchImpl(callingUserId); impl.removeByQuery( packageName, databaseName, @@ -482,7 +481,7 @@ public class AppSearchManagerService extends SystemService { 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 @@ public class AppSearchManagerService extends SystemService { 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 @@ public class AppSearchManagerService extends SystemService { 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 82319d4f353b..8c953d12fd98 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 @@ public final class ImplInstanceManager { } /** - * 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 @@ public final class ImplInstanceManager { * @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 @@ public final class ImplInstanceManager { } } + + /** + * 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 @@ public final class ImplInstanceManager { 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 f422ebc2db7b..e9852aa1cd41 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 @@ public class SearchResultToProtoConverter { 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 2c9477a5d76b..41c70f072262 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 eb072afec696..3c5082ef937d 100644 --- a/apex/appsearch/testing/Android.bp +++ b/apex/appsearch/testing/Android.bp @@ -30,5 +30,8 @@ java_library { "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 d912c08e7d5f..440050faaa7d 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 @@ public interface GlobalSearchSessionShim extends Closeable { * 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 5e5717d11432..9bd57a1109de 100644 --- a/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java +++ b/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java @@ -17,6 +17,7 @@ package com.android.server; import android.annotation.Nullable; +import android.os.PowerWhitelistManager; import android.os.PowerWhitelistManager.ReasonCode; import android.os.PowerWhitelistManager.TempAllowListType; @@ -32,13 +33,20 @@ public interface DeviceIdleInternal { void exitIdle(String reason); - // duration in milliseconds + /** + * Same as {@link #addPowerSaveTempWhitelistApp(int, String, long, int, boolean, int, String)} + * with {@link PowerWhitelistManager#TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED}. + */ void addPowerSaveTempWhitelistApp(int callingUid, String packageName, - long duration, int userId, boolean sync, String reason); + long durationMs, int userId, boolean sync, @ReasonCode int reasonCode, + @Nullable String reason); + /** + * Put a package in the temp-allowlist. + */ void addPowerSaveTempWhitelistApp(int callingUid, String packageName, - long duration, int userId, boolean sync, @ReasonCode int reasonCode, - @Nullable String reason); + long durationMs, @TempAllowListType int tempAllowListType, int userId, boolean sync, + @ReasonCode int reasonCode, @Nullable String reason); /** * Called by ActivityManagerService to directly add UID to DeviceIdleController's temp @@ -49,10 +57,11 @@ public interface DeviceIdleInternal { * @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 ac28e828eb2e..119dcb63770d 100644 --- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java +++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java @@ -1942,30 +1942,29 @@ public class DeviceIdleController extends SystemService exitIdleInternal(reason); } - // 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); + long durationMs, int userId, boolean sync, @ReasonCode int reasonCode, + @Nullable String reason) { + addPowerSaveTempAllowlistAppInternal(callingUid, packageName, durationMs, + TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, + userId, sync, reasonCode, reason); } @Override public void addPowerSaveTempWhitelistApp(int callingUid, String packageName, - long duration, int userId, boolean sync, @ReasonCode int reasonCode, - @Nullable String reason) { - addPowerSaveTempAllowlistAppInternal(callingUid, packageName, duration, - userId, sync, reasonCode, reason); + long durationMs, @TempAllowListType int tempAllowListType, int userId, boolean sync, + @ReasonCode int reasonCode, @Nullable String reason) { + addPowerSaveTempAllowlistAppInternal(callingUid, packageName, durationMs, + tempAllowListType, userId, sync, reasonCode, reason); } - // duration in milliseconds @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, - reasonCode, reason); + public void addPowerSaveTempWhitelistAppDirect(int uid, long durationMs, + @TempAllowListType int tempAllowListType, boolean sync, @ReasonCode int reasonCode, + @Nullable String reason, int callingUid) { + addPowerSaveTempWhitelistAppDirectInternal(callingUid, uid, durationMs, + tempAllowListType, sync, reasonCode, reason); } // duration in milliseconds @@ -2707,7 +2706,8 @@ public class DeviceIdleController extends SystemService final long token = Binder.clearCallingIdentity(); try { addPowerSaveTempAllowlistAppInternal(callingUid, - packageName, duration, userId, true, reasonCode, reason); + packageName, duration, TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, + userId, true, reasonCode, reason); } finally { Binder.restoreCallingIdentity(token); } @@ -2739,12 +2739,22 @@ public class DeviceIdleController extends SystemService * app an exemption to access network and acquire wakelocks. */ void addPowerSaveTempAllowlistAppInternal(int callingUid, String packageName, - long duration, int userId, boolean sync, @ReasonCode int reasonCode, - @Nullable String reason) { + long durationMs, @TempAllowListType int tempAllowListType, 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, - TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, sync, reasonCode, reason); + addPowerSaveTempWhitelistAppDirectInternal(callingUid, uid, durationMs, + tempAllowListType, sync, reasonCode, reason); } catch (NameNotFoundException e) { } } @@ -2754,19 +2764,12 @@ public class DeviceIdleController extends SystemService * app an exemption to access network and acquire wakelocks. */ void addPowerSaveTempWhitelistAppDirectInternal(int callingUid, int uid, - long duration, @TempAllowListType int type, boolean sync, @ReasonCode int reasonCode, - @Nullable String reason) { + long duration, @TempAllowListType int tempAllowListType, boolean sync, + @ReasonCode int reasonCode, @Nullable String reason) { final long timeNow = SystemClock.elapsedRealtime(); 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; @@ -2787,8 +2790,8 @@ public class DeviceIdleController extends SystemService } catch (RemoteException e) { } postTempActiveTimeoutMessage(uid, duration); - updateTempWhitelistAppIdsLocked(uid, true, duration, type, reasonCode, - reason, callingUid); + updateTempWhitelistAppIdsLocked(uid, true, duration, tempAllowListType, + reasonCode, reason, callingUid); if (sync) { informWhitelistChanged = true; } else { 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 34ba753b3daa..862d8b7cac50 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 @@ import com.android.server.job.controllers.JobStatus; 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 0308d68d6a56..b958c3f694bf 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.ActivityManager; 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 @@ class JobConcurrencyManager { */ 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 @@ class JobConcurrencyManager { WORK_TYPE_FGS, WORK_TYPE_EJ, WORK_TYPE_BG, + WORK_TYPE_BGUSER_IMPORTANT, WORK_TYPE_BGUSER }) @Retention(RetentionPolicy.SOURCE) @@ -138,6 +145,8 @@ class JobConcurrencyManager { return "BG"; case WORK_TYPE_BGUSER: return "BGUSER"; + case WORK_TYPE_BGUSER_IMPORTANT: + return "BGUSER_IMPORTANT"; default: return "WORK(" + workType + ")"; } @@ -163,30 +172,40 @@ class JobConcurrencyManager { 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 @@ class JobConcurrencyManager { 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 @@ class JobConcurrencyManager { 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 @@ class JobConcurrencyManager { 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 @@ class JobConcurrencyManager { // 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 @@ class JobConcurrencyManager { + 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 @@ class JobConcurrencyManager { 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 @@ class JobConcurrencyManager { } } + @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 @@ class JobConcurrencyManager { } } + @GuardedBy("mLock") void onJobCompletedLocked(@NonNull JobServiceContext worker, @NonNull JobStatus jobStatus, @WorkType final int workType) { mWorkCountTracker.onJobFinished(workType); @@ -655,7 +716,7 @@ class JobConcurrencyManager { 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 @@ class JobConcurrencyManager { } } 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 @@ class JobConcurrencyManager { * 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 @@ class JobConcurrencyManager { // 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 @@ class JobConcurrencyManager { return s.toString(); } + @GuardedBy("mLock") void updateConfigLocked() { DeviceConfig.Properties properties = DeviceConfig.getProperties(DeviceConfig.NAMESPACE_JOB_SCHEDULER); @@ -1010,6 +1078,7 @@ class JobConcurrencyManager { 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 @@ class JobConcurrencyManager { 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 @@ class JobConcurrencyManager { 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 @@ class JobConcurrencyManager { 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 @@ class JobConcurrencyManager { 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 @@ class JobConcurrencyManager { 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 @@ class JobConcurrencyManager { 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 8bb03e911528..515cb747a99e 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 @@ public class JobSchedulerService extends com.android.server.SystemService * 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 @@ public class JobSchedulerService extends com.android.server.SystemService // 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 c9a184358925..9ef46df7dac5 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java @@ -34,6 +34,7 @@ import android.content.Intent; import android.content.ServiceConnection; import android.net.Uri; import android.os.Binder; +import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -77,9 +78,9 @@ public final class JobServiceContext implements ServiceConnection { private static final String TAG = "JobServiceContext"; /** Amount of time the JobScheduler waits for the initial service launch+bind. */ - private static final long OP_BIND_TIMEOUT_MILLIS = 18 * 1000; + private static final long OP_BIND_TIMEOUT_MILLIS = 18 * 1000 * Build.HW_TIMEOUT_MULTIPLIER; /** Amount of time the JobScheduler will wait for a response from an app for a message. */ - private static final long OP_TIMEOUT_MILLIS = 8 * 1000; + private static final long OP_TIMEOUT_MILLIS = 8 * 1000 * Build.HW_TIMEOUT_MULTIPLIER; private static final String[] VERB_STRINGS = { "VERB_BINDING", "VERB_STARTING", "VERB_EXECUTING", "VERB_STOPPING", "VERB_FINISHED" @@ -269,8 +270,6 @@ public final class JobServiceContext implements ServiceConnection { 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 @@ -355,15 +354,10 @@ public final class JobServiceContext implements ServiceConnection { /** 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; } @@ -381,8 +375,8 @@ public final class JobServiceContext implements ServiceConnection { } boolean isWithinExecutionGuaranteeTime() { - return mExecutionStartTimeElapsed + mMinExecutionGuaranteeMillis - < sElapsedRealtimeClock.millis(); + return sElapsedRealtimeClock.millis() + < mExecutionStartTimeElapsed + mMinExecutionGuaranteeMillis; } @GuardedBy("mLock") @@ -620,7 +614,7 @@ public final class JobServiceContext implements ServiceConnection { } @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, @@ -733,7 +727,7 @@ public final class JobServiceContext implements ServiceConnection { * _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]); @@ -817,7 +811,7 @@ public final class JobServiceContext implements ServiceConnection { * 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); @@ -843,18 +837,19 @@ public final class JobServiceContext implements ServiceConnection { * 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(), @@ -865,7 +860,7 @@ public final class JobServiceContext implements ServiceConnection { completedJob.hasContentTriggerConstraint()); try { mBatteryStats.noteJobFinish(mRunningJob.getBatteryName(), mRunningJob.getSourceUid(), - mParams.getStopReason()); + stopReason); } catch (RemoteException e) { // Whatever. } @@ -884,11 +879,11 @@ public final class JobServiceContext implements ServiceConnection { 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 eaf8f4d96331..aa8d98c01853 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 @@ public final class JobStore { 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 192f5e66255d..79ef321eaf07 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 @@ public final class DeviceIdleJobsController extends StateController { * 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 @@ public final class DeviceIdleJobsController extends StateController { 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 @@ public final class DeviceIdleJobsController extends StateController { } }; + /** 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 @@ public final class DeviceIdleJobsController extends StateController { 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 @@ public final class DeviceIdleJobsController extends StateController { 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 5bdeb38a1424..bad8dc1ad1cb 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 @@ public final class JobStatus { 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 @@ public final class JobStatus { | 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 @@ public final class JobStatus { 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 @@ public final class JobStatus { } this.requiredConstraints = requiredConstraints; mRequiredConstraintsOfInterest = requiredConstraints & CONSTRAINTS_OF_INTEREST; + addDynamicConstraints(dynamicConstraints); mReadyNotDozing = canRunInDoze(); if (standbyBucket == RESTRICTED_INDEX) { addDynamicConstraints(DYNAMIC_RESTRICTED_CONSTRAINTS); @@ -521,7 +536,7 @@ public final class JobStatus { 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 @@ public final class JobStatus { 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 @@ public final class JobStatus { rescheduling.getStandbyBucket(), rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis, newLatestRuntimeElapsedMillis, - lastSuccessfulRunTime, lastFailedRunTime, rescheduling.getInternalFlags()); + lastSuccessfulRunTime, lastFailedRunTime, rescheduling.getInternalFlags(), + rescheduling.mDynamicConstraints); } /** @@ -609,7 +625,7 @@ public final class JobStatus { standbyBucket, tag, 0, earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, 0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */, - /*innerFlags=*/ 0); + /*innerFlags=*/ 0, /* dynamicConstraints */ 0); } public void enqueueWorkLocked(JobWorkItem work) { @@ -1083,12 +1099,15 @@ public final class JobStatus { * 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 @@ public final class JobStatus { } /** + * 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/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java index dd1a0e2478dd..1a808c9b3c33 100644 --- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java @@ -2042,7 +2042,9 @@ public class AppStandbyController if (activityManager.isLowRamDevice() || ActivityManager.isSmallBatteryDevice()) { mAutoRestrictedBucketDelayMs = 12 * ONE_HOUR; } - + } else if (phase == PHASE_BOOT_COMPLETED) { + // mWellbeingApp needs to be initialized lazily after boot to allow for roles to be + // parsed and the wellbeing role-holder to be assigned final PackageManager packageManager = mContext.getPackageManager(); mWellbeingApp = packageManager.getWellbeingPackageName(); } diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp index 1d6f20dd4b27..3d129d8548eb 100644 --- a/apex/media/framework/Android.bp +++ b/apex/media/framework/Android.bp @@ -120,7 +120,6 @@ filegroup { "java/android/media/ApplicationMediaCapabilities.java", "java/android/media/MediaFeature.java", "java/android/media/MediaTranscodeManager.java", - "java/android/media/MediaTranscodingException.java", ], path: "java", } diff --git a/apex/media/framework/api/current.txt b/apex/media/framework/api/current.txt index 1beef40b9e4f..80698f7cedc9 100644 --- a/apex/media/framework/api/current.txt +++ b/apex/media/framework/api/current.txt @@ -210,12 +210,6 @@ package android.media { method public int getNotificationId(); } - public class MediaTranscodingException extends java.lang.Exception { - } - - public static final class MediaTranscodingException.ServiceNotAvailableException extends android.media.MediaTranscodingException { - } - public final class Session2Command implements android.os.Parcelable { ctor public Session2Command(int); ctor public Session2Command(@NonNull String, @Nullable android.os.Bundle); diff --git a/apex/media/framework/api/system-current.txt b/apex/media/framework/api/system-current.txt index ae604f6eaf3d..af2d2f75b823 100644 --- a/apex/media/framework/api/system-current.txt +++ b/apex/media/framework/api/system-current.txt @@ -2,7 +2,7 @@ package android.media { public final class MediaTranscodeManager { - method @NonNull public android.media.MediaTranscodeManager.TranscodingSession enqueueRequest(@NonNull android.media.MediaTranscodeManager.TranscodingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaTranscodeManager.OnTranscodingFinishedListener) throws java.io.FileNotFoundException, android.media.MediaTranscodingException.ServiceNotAvailableException; + method @Nullable public android.media.MediaTranscodeManager.TranscodingSession enqueueRequest(@NonNull android.media.MediaTranscodeManager.TranscodingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaTranscodeManager.OnTranscodingFinishedListener); field public static final int PRIORITY_REALTIME = 1; // 0x1 field public static final int TRANSCODING_TYPE_VIDEO = 1; // 0x1 } diff --git a/apex/media/framework/java/android/media/MediaTranscodeManager.java b/apex/media/framework/java/android/media/MediaTranscodeManager.java index ca5aeb88bf33..b29bed978a21 100644 --- a/apex/media/framework/java/android/media/MediaTranscodeManager.java +++ b/apex/media/framework/java/android/media/MediaTranscodeManager.java @@ -1338,19 +1338,16 @@ public final class MediaTranscodeManager { * could be retried only once. After that, Client need to enqueue a new request if they want * to try again. * - * @throws MediaTranscodingException.ServiceNotAvailableException if the service - * is temporarily unavailable due to internal service rebooting. Client could retry - * again after receiving this exception. + * @return true if successfully resubmit the job to service. False otherwise. * @throws UnsupportedOperationException if the retry could not be fulfilled. * @hide */ - public void retry() throws MediaTranscodingException.ServiceNotAvailableException { - retryInternal(true /*setHasRetried*/); + public boolean retry() { + return retryInternal(true /*setHasRetried*/); } // TODO(hkuang): Add more test for it. - private void retryInternal(boolean setHasRetried) - throws MediaTranscodingException.ServiceNotAvailableException { + private boolean retryInternal(boolean setHasRetried) { synchronized (mLock) { if (mStatus == STATUS_PENDING || mStatus == STATUS_RUNNING) { throw new UnsupportedOperationException( @@ -1364,8 +1361,8 @@ public final class MediaTranscodeManager { // Get the client interface. ITranscodingClient client = mManager.getTranscodingClient(); if (client == null) { - throw new MediaTranscodingException.ServiceNotAvailableException( - "Service rebooting. Try again later"); + Log.e(TAG, "Service rebooting. Try again later"); + return false; } synchronized (mManager.mPendingTranscodingSessions) { @@ -1383,13 +1380,13 @@ public final class MediaTranscodeManager { // Adds the new session back into pending sessions. mManager.mPendingTranscodingSessions.put(mSessionId, this); } catch (RemoteException re) { - throw new MediaTranscodingException.ServiceNotAvailableException( - "Failed to resubmit request to Transcoding service"); + return false; } mStatus = STATUS_PENDING; mHasRetried = setHasRetried ? true : false; } } + return true; } /** @@ -1529,24 +1526,20 @@ public final class MediaTranscodeManager { * <p> Upon successfully accepting the request, MediaTranscodeManager will return a * {@link TranscodingSession} to the client. Client should use {@link TranscodingSession} to * track the progress and get the result. + * <p> MediaTranscodeManager will return null if fails to accept the request due to service + * rebooting. Client could retry again after receiving null. * * @param transcodingRequest The TranscodingRequest to enqueue. * @param listenerExecutor Executor on which the listener is notified. * @param listener Listener to get notified when the transcoding session is finished. * @return A TranscodingSession for this operation. - * @throws FileNotFoundException if the source Uri or destination Uri could not be opened. * @throws UnsupportedOperationException if the request could not be fulfilled. - * @throws MediaTranscodingException.ServiceNotAvailableException if the service - * is temporarily unavailable due to internal service rebooting. Client could retry - * again after receiving this exception. */ - @NonNull + @Nullable public TranscodingSession enqueueRequest( @NonNull TranscodingRequest transcodingRequest, @NonNull @CallbackExecutor Executor listenerExecutor, - @NonNull OnTranscodingFinishedListener listener) - throws FileNotFoundException, - MediaTranscodingException.ServiceNotAvailableException { + @NonNull OnTranscodingFinishedListener listener) { Log.i(TAG, "enqueueRequest called."); Objects.requireNonNull(transcodingRequest, "transcodingRequest must not be null"); Objects.requireNonNull(listenerExecutor, "listenerExecutor must not be null"); @@ -1568,14 +1561,14 @@ public final class MediaTranscodeManager { // Try to register with the service again. IMediaTranscodingService service = getService(false /*retry*/); if (service == null) { - throw new MediaTranscodingException.ServiceNotAvailableException( - "Service rebooting. Try again later"); + Log.w(TAG, "Service rebooting. Try again later"); + return null; } mTranscodingClient = registerClient(service); // If still fails, throws an exception to tell client to try later. if (mTranscodingClient == null) { - throw new MediaTranscodingException.ServiceNotAvailableException( - "Service rebooting. Try again later"); + Log.w(TAG, "Service rebooting. Try again later"); + return null; } } @@ -1595,9 +1588,12 @@ public final class MediaTranscodeManager { mPendingTranscodingSessions.put(session.getSessionId(), session); return session; } - } catch (RemoteException | ServiceSpecificException ex) { + } catch (RemoteException ex) { + Log.w(TAG, "Service rebooting. Try again later"); + return null; + } catch (ServiceSpecificException ex) { throw new UnsupportedOperationException( - "Failed to submit request to Transcoding service"); + "Failed to submit request to Transcoding service. Error: " + ex); } } } diff --git a/apex/media/framework/java/android/media/MediaTranscodingException.java b/apex/media/framework/java/android/media/MediaTranscodingException.java deleted file mode 100644 index 50cc9c4bae24..000000000000 --- a/apex/media/framework/java/android/media/MediaTranscodingException.java +++ /dev/null @@ -1,38 +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.media; - -/** - * Base class for MediaTranscoding exceptions - */ -public class MediaTranscodingException extends Exception { - private MediaTranscodingException(String detailMessage) { - super(detailMessage); - } - - /** - * Exception thrown when the service is rebooting and MediaTranscodeManager is temporarily - * unavailable for accepting new request. It's likely that retrying will be successful. - */ - public static final class ServiceNotAvailableException extends - MediaTranscodingException { - /** @hide */ - public ServiceNotAvailableException(String detailMessage) { - super(detailMessage); - } - } -} diff --git a/core/api/current.txt b/core/api/current.txt index a9303a7fa1a8..9f2961e1e535 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -1072,6 +1072,7 @@ package android { 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 @@ -1258,6 +1259,7 @@ package android { field public static final int segmentedButtonStyle = 16843568; // 0x1010330 field public static final int selectAllOnFocus = 16843102; // 0x101015e field public static final int selectable = 16843238; // 0x10101e6 + field public static final int selectableAsDefault = 16844352; // 0x1010640 field public static final int selectableItemBackground = 16843534; // 0x101030e field public static final int selectableItemBackgroundBorderless = 16843868; // 0x101045c field @Deprecated public static final int selectedDateVerticalBar = 16843591; // 0x1010347 @@ -5311,6 +5313,14 @@ package android.app { 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); @@ -5809,6 +5819,8 @@ package android.app { method @Nullable public android.graphics.drawable.Icon getIcon(); method @Nullable public android.app.PendingIntent getIntent(); method @Nullable public String getShortcutId(); + method public boolean isBubbleSuppressable(); + method public boolean isBubbleSuppressed(); method public boolean isNotificationSuppressed(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.Notification.BubbleMetadata> CREATOR; @@ -5825,6 +5837,7 @@ package android.app { method @NonNull public android.app.Notification.BubbleMetadata.Builder setDesiredHeightResId(@DimenRes int); method @NonNull public android.app.Notification.BubbleMetadata.Builder setIcon(@NonNull android.graphics.drawable.Icon); method @NonNull public android.app.Notification.BubbleMetadata.Builder setIntent(@NonNull android.app.PendingIntent); + method @NonNull public android.app.Notification.BubbleMetadata.Builder setSuppressBubble(boolean); method @NonNull public android.app.Notification.BubbleMetadata.Builder setSuppressNotification(boolean); } @@ -7112,6 +7125,7 @@ package android.app.admin { 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 +7148,7 @@ package android.app.admin { 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 +7184,7 @@ package android.app.admin { 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 +8387,6 @@ package android.appwidget { 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 +8396,12 @@ package android.appwidget { 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 +9730,7 @@ package android.companion { } 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 +10340,7 @@ package android.content { 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 +10391,7 @@ package android.content { 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 +10503,7 @@ package android.content { 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 +10564,19 @@ package android.content { 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); @@ -11693,6 +11723,7 @@ package android.content.pm { field public static final int FLAG_STATE_NOT_NEEDED = 16; // 0x10 field public static final int LAUNCH_MULTIPLE = 0; // 0x0 field public static final int LAUNCH_SINGLE_INSTANCE = 3; // 0x3 + field public static final int LAUNCH_SINGLE_INSTANCE_PER_TASK = 4; // 0x4 field public static final int LAUNCH_SINGLE_TASK = 2; // 0x2 field public static final int LAUNCH_SINGLE_TOP = 1; // 0x1 field public static final int PERSIST_ACROSS_REBOOTS = 2; // 0x2 @@ -11936,6 +11967,14 @@ package android.content.pm { field public static final String ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED = "android.content.pm.action.CAN_INTERACT_ACROSS_PROFILES_CHANGED"; } + public class DataLoaderParams { + method @NonNull public static final android.content.pm.DataLoaderParams forIncremental(@NonNull android.content.ComponentName, @NonNull String); + method @NonNull public static final android.content.pm.DataLoaderParams forStreaming(@NonNull android.content.ComponentName, @NonNull String); + method @NonNull public final String getArguments(); + method @NonNull public final android.content.ComponentName getComponentName(); + method @NonNull public final int getType(); + } + public final class FeatureGroupInfo implements android.os.Parcelable { ctor public FeatureGroupInfo(); ctor public FeatureGroupInfo(android.content.pm.FeatureGroupInfo); @@ -12164,6 +12203,10 @@ package android.content.pm { field public static final String ACTION_SESSION_COMMITTED = "android.content.pm.action.SESSION_COMMITTED"; field public static final String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS"; field public static final String ACTION_SESSION_UPDATED = "android.content.pm.action.SESSION_UPDATED"; + field public static final int DATA_LOADER_TYPE_INCREMENTAL = 2; // 0x2 + field public static final int DATA_LOADER_TYPE_NONE = 0; // 0x0 + field public static final int DATA_LOADER_TYPE_STREAMING = 1; // 0x1 + field public static final String EXTRA_DATA_LOADER_TYPE = "android.content.pm.extra.DATA_LOADER_TYPE"; field public static final String EXTRA_OTHER_PACKAGE_NAME = "android.content.pm.extra.OTHER_PACKAGE_NAME"; field public static final String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME"; field public static final String EXTRA_SESSION = "android.content.pm.extra.SESSION"; @@ -12171,6 +12214,9 @@ package android.content.pm { field public static final String EXTRA_STATUS = "android.content.pm.extra.STATUS"; field public static final String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE"; field public static final String EXTRA_STORAGE_PATH = "android.content.pm.extra.STORAGE_PATH"; + field public static final int LOCATION_DATA_APP = 0; // 0x0 + field public static final int LOCATION_MEDIA_DATA = 2; // 0x2 + field public static final int LOCATION_MEDIA_OBB = 1; // 0x1 field public static final int STATUS_FAILURE = 1; // 0x1 field public static final int STATUS_FAILURE_ABORTED = 3; // 0x3 field public static final int STATUS_FAILURE_BLOCKED = 2; // 0x2 @@ -12178,6 +12224,7 @@ package android.content.pm { field public static final int STATUS_FAILURE_INCOMPATIBLE = 7; // 0x7 field public static final int STATUS_FAILURE_INVALID = 4; // 0x4 field public static final int STATUS_FAILURE_STORAGE = 6; // 0x6 + field public static final int STATUS_PENDING_STREAMING = -2; // 0xfffffffe field public static final int STATUS_PENDING_USER_ACTION = -1; // 0xffffffff field public static final int STATUS_SUCCESS = 0; // 0x0 } @@ -12185,10 +12232,12 @@ package android.content.pm { public static class PackageInstaller.Session implements java.io.Closeable { method public void abandon(); method public void addChildSessionId(int); + method public void addFile(int, @NonNull String, long, @NonNull byte[], @Nullable byte[]); method public void close(); method public void commit(@NonNull android.content.IntentSender); method public void fsync(@NonNull java.io.OutputStream) throws java.io.IOException; method @NonNull public int[] getChildSessionIds(); + method @Nullable public android.content.pm.DataLoaderParams getDataLoaderParams(); method @NonNull public String[] getNames() throws java.io.IOException; method public int getParentSessionId(); method public boolean isMultiPackage(); @@ -12262,6 +12311,7 @@ package android.content.pm { method public void setAppLabel(@Nullable CharSequence); method public void setAppPackageName(@Nullable String); method public void setAutoRevokePermissionsMode(boolean); + method public void setDataLoaderParams(@NonNull android.content.pm.DataLoaderParams); method public void setInstallLocation(int); method public void setInstallReason(int); method public void setInstallScenario(int); @@ -12882,18 +12932,18 @@ package android.content.pm { } 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 +12951,10 @@ package android.content.pm { 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 @@ -17771,6 +17821,7 @@ package android.hardware.camera2 { 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; @@ -18375,9 +18426,20 @@ package android.hardware.camera2 { 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(); } } @@ -18426,9 +18488,11 @@ package android.hardware.camera2.params { 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 { @@ -18471,6 +18535,20 @@ package android.hardware.camera2.params { 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(); @@ -18483,6 +18561,7 @@ package android.hardware.camera2.params { 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(); @@ -20122,14 +20201,15 @@ package android.media { method public void adjustStreamVolume(int, int, int); method public void adjustSuggestedStreamVolume(int, int, int); method public void adjustVolume(int, int); - method public void clearDeviceForCommunication(); + method public void clearCommunicationDevice(); method public void dispatchMediaKeyEvent(android.view.KeyEvent); method public int generateAudioSessionId(); method @NonNull public java.util.List<android.media.AudioPlaybackConfiguration> getActivePlaybackConfigurations(); method @NonNull public java.util.List<android.media.AudioRecordingConfiguration> getActiveRecordingConfigurations(); method public int getAllowedCapturePolicy(); method public int getAudioHwSyncForSession(int); - method @Nullable public android.media.AudioDeviceInfo getDeviceForCommunication(); + method @NonNull public java.util.List<android.media.AudioDeviceInfo> getAvailableCommunicationDevices(); + method @Nullable public android.media.AudioDeviceInfo getCommunicationDevice(); method public android.media.AudioDeviceInfo[] getDevices(int); method public java.util.List<android.media.MicrophoneInfo> getMicrophones() throws java.io.IOException; method public int getMode(); @@ -20171,7 +20251,7 @@ package android.media { method public void setAllowedCapturePolicy(int); method @Deprecated public void setBluetoothA2dpOn(boolean); method public void setBluetoothScoOn(boolean); - method public boolean setDeviceForCommunication(@NonNull android.media.AudioDeviceInfo); + method public boolean setCommunicationDevice(@NonNull android.media.AudioDeviceInfo); method public void setMicrophoneMute(boolean); method public void setMode(int); method public void setParameters(String); @@ -21908,16 +21988,17 @@ package android.media { 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 { @@ -26748,7 +26829,22 @@ package android.net.vcn { 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); } } @@ -34673,6 +34769,7 @@ package android.provider { field public static final String ACTION_APP_NOTIFICATION_SETTINGS = "android.settings.APP_NOTIFICATION_SETTINGS"; field public static final String ACTION_APP_SEARCH_SETTINGS = "android.settings.APP_SEARCH_SETTINGS"; field public static final String ACTION_APP_USAGE_SETTINGS = "android.settings.action.APP_USAGE_SETTINGS"; + field public static final String ACTION_AUTO_ROTATE_SETTINGS = "android.settings.AUTO_ROTATE_SETTINGS"; field public static final String ACTION_BATTERY_SAVER_SETTINGS = "android.settings.BATTERY_SAVER_SETTINGS"; field public static final String ACTION_BIOMETRIC_ENROLL = "android.settings.BIOMETRIC_ENROLL"; field public static final String ACTION_BLUETOOTH_SETTINGS = "android.settings.BLUETOOTH_SETTINGS"; @@ -41497,29 +41594,29 @@ package android.telephony { 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 @@ -41533,7 +41630,7 @@ package android.telephony { 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 @@ -41542,90 +41639,6 @@ package android.telephony { 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(); @@ -41642,7 +41655,7 @@ package android.telephony { method public void writeToParcel(@NonNull android.os.Parcel, int); field public static final int BAND_UNKNOWN = 0; // 0x0 field public static final int CELL_BANDWIDTH_UNKNOWN = 0; // 0x0 - field public static final int CHANNEL_NUMBER_UNKNOWN = -1; // 0xffffffff + field public static final int CHANNEL_NUMBER_UNKNOWN = 2147483647; // 0x7fffffff field public static final int CONNECTION_PRIMARY_SERVING = 1; // 0x1 field public static final int CONNECTION_SECONDARY_SERVING = 2; // 0x2 field public static final int CONNECTION_UNKNOWN = -1; // 0xffffffff @@ -42100,6 +42113,94 @@ package android.telephony { 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(); @@ -42212,7 +42313,7 @@ package android.telephony { 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); @@ -42236,7 +42337,7 @@ package android.telephony { 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>); @@ -45899,11 +46000,14 @@ package android.util { 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 { @@ -50817,6 +50921,7 @@ package android.view.autofill { public final class AutofillManager { method public void cancel(); + method public void clearAutofillRequestCallback(); method public void commit(); method public void disableAutofillServices(); method @Nullable public android.content.ComponentName getAutofillServiceComponentName(); @@ -50842,12 +50947,14 @@ package android.view.autofill { method public void registerCallback(@Nullable android.view.autofill.AutofillManager.AutofillCallback); method public void requestAutofill(@NonNull android.view.View); method public void requestAutofill(@NonNull android.view.View, int, @NonNull android.graphics.Rect); + method public void setAutofillRequestCallback(@NonNull java.util.concurrent.Executor, @NonNull android.view.autofill.AutofillRequestCallback); method public void setUserData(@Nullable android.service.autofill.UserData); method public void unregisterCallback(@Nullable android.view.autofill.AutofillManager.AutofillCallback); field public static final String EXTRA_ASSIST_STRUCTURE = "android.view.autofill.extra.ASSIST_STRUCTURE"; 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 { @@ -50859,6 +50966,10 @@ package android.view.autofill { field public static final int EVENT_INPUT_UNAVAILABLE = 3; // 0x3 } + public interface AutofillRequestCallback { + method public void onFillRequest(@Nullable android.view.inputmethod.InlineSuggestionsRequest, @NonNull android.os.CancellationSignal, @NonNull android.service.autofill.FillCallback); + } + public final class AutofillValue implements android.os.Parcelable { method public int describeContents(); method public static android.view.autofill.AutofillValue forDate(long); @@ -51000,6 +51111,7 @@ package android.view.displayhash { 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 @@ -52181,9 +52293,8 @@ package android.view.textservice { } public final class TextServicesManager { - method @Nullable public android.view.textservice.SpellCheckerInfo getCurrentSpellChecker(); - method @Nullable public android.view.textservice.SpellCheckerSubtype getCurrentSpellCheckerSubtype(boolean); - method @Nullable public java.util.List<android.view.textservice.SpellCheckerInfo> getEnabledSpellCheckersList(); + method @Nullable public android.view.textservice.SpellCheckerInfo getCurrentSpellCheckerInfo(); + method @Nullable public java.util.List<android.view.textservice.SpellCheckerInfo> getEnabledSpellCheckerInfos(); method public boolean isSpellCheckerEnabled(); method @Nullable public android.view.textservice.SpellCheckerSession newSpellCheckerSession(@Nullable android.os.Bundle, @Nullable java.util.Locale, @NonNull android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener, boolean); method @Nullable public android.view.textservice.SpellCheckerSession newSpellCheckerSession(@Nullable android.os.Bundle, @Nullable java.util.Locale, @NonNull android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener, boolean, int); @@ -54794,7 +54905,7 @@ package android.widget { 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); @@ -54803,6 +54914,7 @@ package android.widget { method public int describeContents(); method public int getLayoutId(); method public String getPackage(); + method @IdRes public int getViewId(); method @Deprecated public boolean onLoadClass(Class); method public void reapply(android.content.Context, android.view.View); method public void removeAllViews(@IdRes int); @@ -54863,6 +54975,7 @@ package android.widget { method public void setTextViewText(@IdRes int, CharSequence); method public void setTextViewTextSize(@IdRes int, int, float); method public void setUri(@IdRes int, String, android.net.Uri); + method public void setViewId(@IdRes int); method public void setViewLayoutHeight(@IdRes int, float, int); method public void setViewLayoutHeightDimen(@IdRes int, @DimenRes int); method public void setViewLayoutMargin(@IdRes int, int, float, int); diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index d6786f8a3f8e..194a6d31cc43 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -35,7 +35,8 @@ package android.app { } 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 @RequiresPermission(android.Manifest.permission.GET_INTENT_SENDER_INTENT) public boolean intentFilterEquals(@Nullable android.app.PendingIntent); + 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 +145,6 @@ package android.media.session { 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); @@ -209,6 +209,10 @@ package android.net { package android.os { + public final class BatteryStatsManager { + method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void reportNetworkInterfaceForTransports(@NonNull String, @NonNull int[]) throws java.lang.RuntimeException; + } + public class Binder implements android.os.IBinder { method public final void markVintfStability(); } diff --git a/core/api/system-current.txt b/core/api/system-current.txt index f01724316c5f..a06704144327 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -228,6 +228,7 @@ package android { 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"; @@ -246,6 +247,7 @@ package android { field public static final String SEND_SMS_NO_CONFIRMATION = "android.permission.SEND_SMS_NO_CONFIRMATION"; field public static final String SERIAL_PORT = "android.permission.SERIAL_PORT"; field public static final String SET_ACTIVITY_WATCHER = "android.permission.SET_ACTIVITY_WATCHER"; + field public static final String SET_CLIP_SOURCE = "android.permission.SET_CLIP_SOURCE"; field public static final String SET_HARMFUL_APP_WARNINGS = "android.permission.SET_HARMFUL_APP_WARNINGS"; field public static final String SET_MEDIA_KEY_LISTENER = "android.permission.SET_MEDIA_KEY_LISTENER"; field public static final String SET_ORIENTATION = "android.permission.SET_ORIENTATION"; @@ -358,6 +360,8 @@ package android { 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_systemWellbeing = 17039408; // 0x1040030 + field public static final int config_systemWifiCoexManager = 17039407; // 0x104002f } public static final class R.style { @@ -2117,6 +2121,10 @@ package android.content { method @NonNull public final android.os.UserHandle getSendingUser(); } + public class ClipboardManager extends android.text.ClipboardManager { + method @RequiresPermission(android.Manifest.permission.SET_CLIP_SOURCE) public void setPrimaryClipAsPackage(@NonNull android.content.ClipData, @NonNull String); + } + public abstract class ContentProvider implements android.content.ComponentCallbacks2 { method public int checkUriPermission(@NonNull android.net.Uri, int, int); } @@ -2183,6 +2191,14 @@ package android.content { 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(); @@ -2366,14 +2382,6 @@ package android.content.pm { method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_PROFILES) public void startActivity(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle); } - public class DataLoaderParams { - method @NonNull public static final android.content.pm.DataLoaderParams forIncremental(@NonNull android.content.ComponentName, @NonNull String); - method @NonNull public static final android.content.pm.DataLoaderParams forStreaming(@NonNull android.content.ComponentName, @NonNull String); - method @NonNull public final String getArguments(); - method @NonNull public final android.content.ComponentName getComponentName(); - method @NonNull public final int getType(); - } - public final class InstallationFile { method public long getLengthBytes(); method public int getLocation(); @@ -2472,19 +2480,10 @@ package android.content.pm { public class PackageInstaller { method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setPermissionsResult(int, boolean); - field public static final int DATA_LOADER_TYPE_INCREMENTAL = 2; // 0x2 - field public static final int DATA_LOADER_TYPE_NONE = 0; // 0x0 - field public static final int DATA_LOADER_TYPE_STREAMING = 1; // 0x1 - field public static final String EXTRA_DATA_LOADER_TYPE = "android.content.pm.extra.DATA_LOADER_TYPE"; - field public static final int LOCATION_DATA_APP = 0; // 0x0 - field public static final int LOCATION_MEDIA_DATA = 2; // 0x2 - field public static final int LOCATION_MEDIA_OBB = 1; // 0x1 } public static class PackageInstaller.Session implements java.io.Closeable { - method public void addFile(int, @NonNull String, long, @NonNull byte[], @Nullable byte[]); method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void commitTransferred(@NonNull android.content.IntentSender); - method @Nullable public android.content.pm.DataLoaderParams getDataLoaderParams(); method public void removeFile(int, @NonNull String); } @@ -2506,7 +2505,6 @@ package android.content.pm { public static class PackageInstaller.SessionParams implements android.os.Parcelable { method @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) public void setAllocateAggressive(boolean); method @Deprecated public void setAllowDowngrade(boolean); - method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setDataLoaderParams(@NonNull android.content.pm.DataLoaderParams); method public void setDontKillApp(boolean); method public void setEnableRollback(boolean); method public void setEnableRollback(boolean, int); @@ -2688,7 +2686,7 @@ package android.content.pm { field public static final int PROTECTION_FLAG_RETAIL_DEMO = 16777216; // 0x1000000 field public static final int PROTECTION_FLAG_ROLE = 67108864; // 0x4000000 field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000 - field public static final int PROTECTION_FLAG_WELLBEING = 131072; // 0x20000 + field @Deprecated public static final int PROTECTION_FLAG_WELLBEING = 131072; // 0x20000 field @Nullable public final String backgroundPermission; field @StringRes public int requestRes; } @@ -2702,7 +2700,7 @@ package android.content.pm { } 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); } @@ -2898,8 +2896,6 @@ package android.graphics.fonts { public class FontManager { method @NonNull public android.text.FontConfig getFontConfig(); method @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFamily(@NonNull android.graphics.fonts.FontFamilyUpdateRequest, @IntRange(from=0) int); - method @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFile(@NonNull android.graphics.fonts.FontFileUpdateRequest, @IntRange(from=0) int); - method @Deprecated @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFile(@NonNull android.os.ParcelFileDescriptor, @NonNull byte[], @IntRange(from=0) int); field public static final int RESULT_ERROR_DOWNGRADING = -5; // 0xfffffffb field public static final int RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE = -1; // 0xffffffff field public static final int RESULT_ERROR_FAILED_UPDATE_CONFIG = -6; // 0xfffffffa @@ -3449,6 +3445,10 @@ package android.hardware.lights { 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 { @@ -4326,7 +4326,7 @@ package android.location { public final class CorrelationVector implements android.os.Parcelable { method public int describeContents(); - method @IntRange(from=0) public int getFrequencyOffsetMetersPerSecond(); + method @FloatRange(from=0.0f) public double getFrequencyOffsetMetersPerSecond(); method @NonNull public int[] getMagnitude(); method @FloatRange(from=0.0f) public double getSamplingStartMeters(); method @FloatRange(from=0.0f, fromInclusive=false) public double getSamplingWidthMeters(); @@ -4337,7 +4337,7 @@ package android.location { public static final class CorrelationVector.Builder { ctor public CorrelationVector.Builder(); method @NonNull public android.location.CorrelationVector build(); - method @NonNull public android.location.CorrelationVector.Builder setFrequencyOffsetMetersPerSecond(@IntRange(from=0) int); + method @NonNull public android.location.CorrelationVector.Builder setFrequencyOffsetMetersPerSecond(@FloatRange(from=0.0f) double); method @NonNull public android.location.CorrelationVector.Builder setMagnitude(@NonNull int[]); method @NonNull public android.location.CorrelationVector.Builder setSamplingStartMeters(@FloatRange(from=0.0f) double); method @NonNull public android.location.CorrelationVector.Builder setSamplingWidthMeters(@FloatRange(from=0.0f, fromInclusive=false) double); @@ -7223,26 +7223,6 @@ package android.net { ctor public NetworkStats.Entry(@Nullable String, int, int, int, int, int, int, long, long, long, long, long); } - public final class OemNetworkPreferences implements android.os.Parcelable { - method public int describeContents(); - method @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getNetworkPreferences(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.OemNetworkPreferences> CREATOR; - field public static final int OEM_NETWORK_PREFERENCE_OEM_PAID = 1; // 0x1 - field public static final int OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK = 2; // 0x2 - field public static final int OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY = 3; // 0x3 - field public static final int OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY = 4; // 0x4 - field public static final int OEM_NETWORK_PREFERENCE_UNINITIALIZED = 0; // 0x0 - } - - public static final class OemNetworkPreferences.Builder { - ctor public OemNetworkPreferences.Builder(); - ctor public OemNetworkPreferences.Builder(@NonNull android.net.OemNetworkPreferences); - method @NonNull public android.net.OemNetworkPreferences.Builder addNetworkPreference(@NonNull String, int); - method @NonNull public android.net.OemNetworkPreferences build(); - method @NonNull public android.net.OemNetworkPreferences.Builder clearNetworkPreference(@NonNull String); - } - public class RssiCurve implements android.os.Parcelable { ctor public RssiCurve(int, int, byte[]); ctor public RssiCurve(int, int, byte[], int); @@ -9193,6 +9173,15 @@ package android.se.omapi { } +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 { @@ -11072,51 +11061,16 @@ package android.telephony { 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 @@ -11126,50 +11080,6 @@ package android.telephony { 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(); @@ -11507,6 +11417,88 @@ package android.telephony { 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); @@ -12991,7 +12983,7 @@ package android.telephony.ims { method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public boolean isRcsVolteSingleRegistrationCapable() throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyRcsAutoConfigurationReceived(@NonNull byte[], boolean); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerProvisioningChangedCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.Callback) throws android.telephony.ims.ImsException; - method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public void registerRcsProvisioningChangedCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.RcsProvisioningCallback) throws android.telephony.ims.ImsException; + method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public void registerRcsProvisioningCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.RcsProvisioningCallback) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningIntValue(int, int); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setProvisioningStatusForCapability(int, int, boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningStringValue(int, @NonNull String); @@ -12999,7 +12991,7 @@ package android.telephony.ims { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setRcsProvisioningStatusForCapability(int, boolean); method @RequiresPermission(android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void triggerRcsReconfiguration(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback); - method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public void unregisterRcsProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.RcsProvisioningCallback); + method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public void unregisterRcsProvisioningCallback(@NonNull android.telephony.ims.ProvisioningManager.RcsProvisioningCallback); field @RequiresPermission(android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public static final String ACTION_RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE = "android.telephony.ims.action.RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE"; field public static final String EXTRA_STATUS = "android.telephony.ims.extra.STATUS"; field public static final String EXTRA_SUBSCRIPTION_ID = "android.telephony.ims.extra.SUBSCRIPTION_ID"; @@ -13296,10 +13288,12 @@ package android.telephony.ims { 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 e4757e6204b7..5f14be22358a 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -259,6 +259,10 @@ package android.app { 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,8 @@ package android.app { } 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 @RequiresPermission("android.permission.GET_INTENT_SENDER_INTENT") public boolean intentFilterEquals(@Nullable android.app.PendingIntent); + 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 } @@ -654,6 +659,10 @@ package android.content { field @Nullable public android.util.ArraySet<android.content.ComponentName> whitelistedActivitiesForAugmentedAutofill; } + public class ClipboardManager extends android.text.ClipboardManager { + method @Nullable @RequiresPermission(android.Manifest.permission.SET_CLIP_SOURCE) public String getPrimaryClipSource(); + } + public final class ContentCaptureOptions implements android.os.Parcelable { ctor public ContentCaptureOptions(int); ctor public ContentCaptureOptions(int, int, int, int, int, @Nullable android.util.ArraySet<android.content.ComponentName>); @@ -953,8 +962,6 @@ package android.graphics.fonts { public class FontManager { method @NonNull public android.text.FontConfig getFontConfig(); method @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFamily(@NonNull android.graphics.fonts.FontFamilyUpdateRequest, @IntRange(from=0) int); - method @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFile(@NonNull android.graphics.fonts.FontFileUpdateRequest, @IntRange(from=0) int); - method @Deprecated @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFile(@NonNull android.os.ParcelFileDescriptor, @NonNull byte[], @IntRange(from=0) int); field public static final int RESULT_ERROR_DOWNGRADING = -5; // 0xfffffffb field public static final int RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE = -1; // 0xffffffff field public static final int RESULT_ERROR_FAILED_UPDATE_CONFIG = -6; // 0xfffffffa diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index e7751b861037..0b5958695dff 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -17,6 +17,8 @@ package android.app; import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN; +import static android.app.ConfigurationController.createNewConfigAndUpdateIfNotNull; +import static android.app.ConfigurationController.freeTextLayoutCachesIfNeeded; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.app.servertransaction.ActivityLifecycleItem.ON_CREATE; @@ -79,7 +81,6 @@ import android.content.res.AssetManager; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.content.res.Resources; -import android.content.res.Resources.Theme; import android.content.res.loader.ResourcesLoader; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDebug; @@ -162,7 +163,6 @@ import android.util.SuperNotCalledException; import android.util.UtilConfig; import android.util.proto.ProtoOutputStream; import android.view.Choreographer; -import android.view.ContextThemeWrapper; import android.view.Display; import android.view.DisplayAdjustments; import android.view.DisplayAdjustments.FixedRotationAdjustments; @@ -228,7 +228,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.TimeZone; @@ -251,7 +250,8 @@ final class RemoteServiceException extends AndroidRuntimeException { * * {@hide} */ -public final class ActivityThread extends ClientTransactionHandler { +public final class ActivityThread extends ClientTransactionHandler + implements ActivityThreadInternal { /** @hide */ public static final String TAG = "ActivityThread"; private static final android.graphics.Bitmap.Config THUMBNAIL_FORMAT = Bitmap.Config.RGB_565; @@ -363,13 +363,15 @@ public final class ActivityThread extends ClientTransactionHandler { @UnsupportedAppUsage AppBindData mBoundApplication; Profiler mProfiler; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553, + publicAlternatives = "Use {@code Context#getResources()#getConfiguration()#densityDpi} " + + "instead.") int mCurDefaultDisplayDpi; @UnsupportedAppUsage boolean mDensityCompatMode; - @UnsupportedAppUsage + @UnsupportedAppUsage(trackingBug = 176961850, maxTargetSdk = Build.VERSION_CODES.R, + publicAlternatives = "Use {@code Context#getResources()#getConfiguration()} instead.") Configuration mConfiguration; - Configuration mCompatConfiguration; @UnsupportedAppUsage Application mInitialApplication; @UnsupportedAppUsage @@ -420,7 +422,8 @@ public final class ActivityThread extends ClientTransactionHandler { @GuardedBy("mResourcesManager") final ArrayList<ActivityClientRecord> mRelaunchingActivities = new ArrayList<>(); @GuardedBy("mResourcesManager") - @UnsupportedAppUsage + @UnsupportedAppUsage(trackingBug = 176961850, maxTargetSdk = Build.VERSION_CODES.R, + publicAlternatives = "Use {@code Context#getResources()#getConfiguration()} instead.") Configuration mPendingConfiguration = null; // An executor that performs multi-step transactions. private final TransactionExecutor mTransactionExecutor = new TransactionExecutor(this); @@ -516,6 +519,9 @@ public final class ActivityThread extends ClientTransactionHandler { private IContentCaptureOptionsCallback.Stub mContentCaptureOptionsCallback = null; + /** A client side controller to handle process level configuration changes. */ + private ConfigurationController mConfigurationController; + /** Activity client record, used for bookkeeping for the real {@link Activity} instance. */ public static final class ActivityClientRecord { @UnsupportedAppUsage @@ -2058,7 +2064,7 @@ public final class ActivityThread extends ClientTransactionHandler { Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case CONFIGURATION_CHANGED: - handleConfigurationChanged((Configuration) msg.obj); + mConfigurationController.handleConfigurationChanged((Configuration) msg.obj); break; case CLEAN_UP_CONTEXT: ContextCleanupInfo cci = (ContextCleanupInfo)msg.obj; @@ -2539,6 +2545,7 @@ public final class ActivityThread extends ClientTransactionHandler { return mExecutor; } + @Override @UnsupportedAppUsage public Application getApplication() { return mInitialApplication; @@ -2549,6 +2556,7 @@ public final class ActivityThread extends ClientTransactionHandler { return mBoundApplication.processName; } + @Override @UnsupportedAppUsage public ContextImpl getSystemContext() { synchronized (this) { @@ -2559,6 +2567,7 @@ public final class ActivityThread extends ClientTransactionHandler { } } + @Override public ContextImpl getSystemUiContext() { synchronized (this) { if (mSystemUiContext == null) { @@ -3217,15 +3226,16 @@ public final class ActivityThread extends ClientTransactionHandler { @VisibleForTesting(visibility = PACKAGE) public Configuration getConfiguration() { - return mConfiguration; + return mConfigurationController.getConfiguration(); } @Override public void updatePendingConfiguration(Configuration config) { - synchronized (mResourcesManager) { - if (mPendingConfiguration == null || mPendingConfiguration.isOtherSeqNewer(config)) { - mPendingConfiguration = config; - } + final Configuration updatedConfig = + mConfigurationController.updatePendingConfiguration(config); + // This is only done to maintain @UnsupportedAppUsage and should be removed someday. + if (updatedConfig != null) { + mPendingConfiguration = updatedConfig; } } @@ -3233,6 +3243,7 @@ public final class ActivityThread extends ClientTransactionHandler { * Returns {@code true} if the {@link android.app.ActivityManager.ProcessState} of the current * process is cached. */ + @Override @VisibleForTesting public boolean isCachedProcessState() { synchronized (mAppThread) { @@ -3269,10 +3280,8 @@ public final class ActivityThread extends ClientTransactionHandler { // non-cached. Except the case where there is a launching activity because the // LaunchActivityItem will handle it. if (wasCached && !isCachedProcessState() && mNumLaunchingActivities.get() == 0) { - final Configuration pendingConfig; - synchronized (mResourcesManager) { - pendingConfig = mPendingConfiguration; - } + final Configuration pendingConfig = + mConfigurationController.getPendingConfiguration(false /* clearPending */); if (pendingConfig == null) { return; } @@ -3498,7 +3507,8 @@ public final class ActivityThread extends ClientTransactionHandler { if (activity != null) { CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager()); - Configuration config = new Configuration(mCompatConfiguration); + Configuration config = + new Configuration(mConfigurationController.getCompatConfiguration()); if (r.overrideConfig != null) { config.updateFrom(r.overrideConfig); } @@ -3711,7 +3721,7 @@ public final class ActivityThread extends ClientTransactionHandler { } // Make sure we are running with the most recent config. - handleConfigurationChanged(null, null); + mConfigurationController.handleConfigurationChanged(null, null); if (localLOGV) Slog.v( TAG, "Handling launch of " + r); @@ -3729,7 +3739,7 @@ public final class ActivityThread extends ClientTransactionHandler { final Activity a = performLaunchActivity(r, customIntent); if (a != null) { - r.createdConfig = new Configuration(mConfiguration); + r.createdConfig = new Configuration(mConfigurationController.getConfiguration()); reportSizeConfigurations(r); if (!r.activity.mFinished && pendingActions != null) { pendingActions.setOldState(r.state); @@ -4962,10 +4972,10 @@ public final class ActivityThread extends ClientTransactionHandler { r.setState(ON_PAUSE); } - // TODO(b/127877792): Make LocalActivityManager call performStopActivityInner. We cannot remove + // TODO(b/176961850): Make LocalActivityManager call performStopActivityInner. We cannot remove // this since it's a high usage hidden API. /** Called from {@link LocalActivityManager}. */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 127877792, + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 176961850, publicAlternatives = "{@code N/A}") final void performStopActivity(IBinder token, boolean saveState, String reason) { ActivityClientRecord r = mActivities.get(token); @@ -5193,8 +5203,7 @@ public final class ActivityThread extends ClientTransactionHandler { if (apk != null) { apk.setCompatibilityInfo(data.info); } - handleConfigurationChanged(mConfiguration, data.info); - WindowManagerGlobal.getInstance().reportNewConfiguration(mConfiguration); + mConfigurationController.handleConfigurationChanged(data.info); } private void deliverResults(ActivityClientRecord r, List<ResultInfo> results, String reason) { @@ -5451,7 +5460,6 @@ public final class ActivityThread extends ClientTransactionHandler { unscheduleGcIdler(); mSomeActivitiesChanged = true; - Configuration changedConfig = null; int configChanges = 0; // First: make sure we have the most recent configuration and most @@ -5480,20 +5488,20 @@ public final class ActivityThread extends ClientTransactionHandler { if (DEBUG_CONFIGURATION) Slog.v(TAG, "Relaunching activity " + tmp.token + " with configChanges=0x" + Integer.toHexString(configChanges)); - - if (mPendingConfiguration != null) { - changedConfig = mPendingConfiguration; - mPendingConfiguration = null; - } } + Configuration changedConfig = mConfigurationController.getPendingConfiguration( + true /* clearPending */); + mPendingConfiguration = null; + if (tmp.createdConfig != null) { // If the activity manager is passing us its current config, // assume that is really what we want regardless of what we // may have pending. - if (mConfiguration == null - || (tmp.createdConfig.isOtherSeqNewer(mConfiguration) - && mConfiguration.diff(tmp.createdConfig) != 0)) { + final Configuration config = mConfigurationController.getConfiguration(); + if (config == null + || (tmp.createdConfig.isOtherSeqNewer(config) + && config.diff(tmp.createdConfig) != 0)) { if (changedConfig == null || tmp.createdConfig.isOtherSeqNewer(changedConfig)) { changedConfig = tmp.createdConfig; @@ -5506,9 +5514,12 @@ public final class ActivityThread extends ClientTransactionHandler { // If there was a pending configuration change, execute it first. if (changedConfig != null) { - mCurDefaultDisplayDpi = changedConfig.densityDpi; - updateDefaultDensity(); - handleConfigurationChanged(changedConfig, null); + mConfigurationController.updateDefaultDensity(changedConfig.densityDpi); + mConfigurationController.handleConfigurationChanged(changedConfig, null); + + // These are only done to maintain @UnsupportedAppUsage and should be removed someday. + mCurDefaultDisplayDpi = mConfigurationController.getCurDefaultDisplayDpi(); + mConfiguration = mConfigurationController.getConfiguration(); } ActivityClientRecord r = mActivities.get(tmp.token); @@ -5596,7 +5607,8 @@ public final class ActivityThread extends ClientTransactionHandler { // Initialize a relaunch request. final MergedConfiguration mergedConfiguration = new MergedConfiguration( - r.createdConfig != null ? r.createdConfig : mConfiguration, + r.createdConfig != null + ? r.createdConfig : mConfigurationController.getConfiguration(), r.overrideConfig); final ActivityRelaunchItem activityRelaunchItem = ActivityRelaunchItem.obtain( null /* pendingResults */, null /* pendingIntents */, 0 /* configChanges */, @@ -5672,7 +5684,8 @@ public final class ActivityThread extends ClientTransactionHandler { } } - ArrayList<ComponentCallbacks2> collectComponentCallbacks(boolean includeActivities) { + @Override + public ArrayList<ComponentCallbacks2> collectComponentCallbacks(boolean includeActivities) { ArrayList<ComponentCallbacks2> callbacks = new ArrayList<ComponentCallbacks2>(); @@ -5732,44 +5745,6 @@ public final class ActivityThread extends ClientTransactionHandler { } /** - * Creates a new Configuration only if override would modify base. Otherwise returns base. - * @param base The base configuration. - * @param override The update to apply to the base configuration. Can be null. - * @return A Configuration representing base with override applied. - */ - private static Configuration createNewConfigAndUpdateIfNotNull(@NonNull Configuration base, - @Nullable Configuration override) { - if (override == null) { - return base; - } - Configuration newConfig = new Configuration(base); - newConfig.updateFrom(override); - return newConfig; - } - - /** - * Decides whether to update a component's configuration and whether to inform it. - * @param cb The component callback to notify of configuration change. - * @param newConfig The new configuration. - */ - private void performConfigurationChanged(ComponentCallbacks2 cb, Configuration newConfig) { - // ContextThemeWrappers may override the configuration for that context. We must check and - // apply any overrides defined. - Configuration contextThemeWrapperOverrideConfig = null; - if (cb instanceof ContextThemeWrapper) { - final ContextThemeWrapper contextThemeWrapper = (ContextThemeWrapper) cb; - contextThemeWrapperOverrideConfig = contextThemeWrapper.getOverrideConfiguration(); - } - - // Apply the ContextThemeWrapper override if necessary. - // NOTE: Make sure the configurations are not modified, as they are treated as immutable - // in many places. - final Configuration configToReport = createNewConfigAndUpdateIfNotNull( - newConfig, contextThemeWrapperOverrideConfig); - cb.onConfigurationChanged(configToReport); - } - - /** * Decides whether to update an Activity's configuration and whether to inform it. * @param activity The activity to notify of configuration change. * @param newConfig The new configuration. @@ -5887,128 +5862,15 @@ public final class ActivityThread extends ClientTransactionHandler { } } - final Configuration applyCompatConfiguration(int displayDensity) { - Configuration config = mConfiguration; - if (mCompatConfiguration == null) { - mCompatConfiguration = new Configuration(); - } - mCompatConfiguration.setTo(mConfiguration); - if (mResourcesManager.applyCompatConfigurationLocked(displayDensity, - mCompatConfiguration)) { - config = mCompatConfiguration; - } - return config; - } - @Override public void handleConfigurationChanged(Configuration config) { - if (isCachedProcessState()) { - updatePendingConfiguration(config); - // If the process is in a cached state, delay the handling until the process is no - // longer cached. - return; - } - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "configChanged"); - mCurDefaultDisplayDpi = config.densityDpi; - handleConfigurationChanged(config, null /* compat */); - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - } - - private void handleConfigurationChanged(Configuration config, CompatibilityInfo compat) { - - int configDiff; - boolean equivalent; - - final Theme systemTheme = getSystemContext().getTheme(); - final Theme systemUiTheme = getSystemUiContext().getTheme(); - - synchronized (mResourcesManager) { - if (mPendingConfiguration != null) { - if (!mPendingConfiguration.isOtherSeqNewer(config)) { - config = mPendingConfiguration; - mCurDefaultDisplayDpi = config.densityDpi; - updateDefaultDensity(); - } - mPendingConfiguration = null; - } - - if (config == null) { - // TODO (b/135719017): Temporary log for debugging IME service. - if (Build.IS_DEBUGGABLE && mHasImeComponent) { - Log.w(TAG, "handleConfigurationChanged for IME app but config is null"); - } - return; - } - - // This flag tracks whether the new configuration is fundamentally equivalent to the - // existing configuration. This is necessary to determine whether non-activity callbacks - // should receive notice when the only changes are related to non-public fields. - // We do not gate calling {@link #performActivityConfigurationChanged} based on this - // flag as that method uses the same check on the activity config override as well. - equivalent = mConfiguration != null && (0 == mConfiguration.diffPublicOnly(config)); - - if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle configuration changed: " - + config); - - final Resources appResources = mInitialApplication.getResources(); - if (appResources.hasOverrideDisplayAdjustments()) { - // The value of Display#getRealSize will be adjusted by FixedRotationAdjustments, - // but Display#getSize refers to DisplayAdjustments#mConfiguration. So the rotated - // configuration also needs to set to the adjustments for consistency. - appResources.getDisplayAdjustments().getConfiguration().updateFrom(config); - } - mResourcesManager.applyConfigurationToResourcesLocked(config, compat, - appResources.getDisplayAdjustments()); - updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(), - mResourcesManager.getConfiguration().getLocales()); - - if (mConfiguration == null) { - mConfiguration = new Configuration(); - } - if (!mConfiguration.isOtherSeqNewer(config) && compat == null) { - // TODO (b/135719017): Temporary log for debugging IME service. - if (Build.IS_DEBUGGABLE && mHasImeComponent) { - Log.w(TAG, "handleConfigurationChanged for IME app but config seq is obsolete " - + ", config=" + config - + ", mConfiguration=" + mConfiguration); - } - return; - } + mConfigurationController.handleConfigurationChanged(config); - configDiff = mConfiguration.updateFrom(config); - config = applyCompatConfiguration(mCurDefaultDisplayDpi); - HardwareRenderer.sendDeviceConfigurationForDebugging(config); - - if ((systemTheme.getChangingConfigurations() & configDiff) != 0) { - systemTheme.rebase(); - } - - if ((systemUiTheme.getChangingConfigurations() & configDiff) != 0) { - systemUiTheme.rebase(); - } - } - - final ArrayList<ComponentCallbacks2> callbacks = - collectComponentCallbacks(false /* includeActivities */); - - freeTextLayoutCachesIfNeeded(configDiff); - - if (callbacks != null) { - final int N = callbacks.size(); - for (int i=0; i<N; i++) { - ComponentCallbacks2 cb = callbacks.get(i); - if (!equivalent) { - performConfigurationChanged(cb, config); - } else { - // TODO (b/135719017): Temporary log for debugging IME service. - if (Build.IS_DEBUGGABLE && cb instanceof InputMethodService) { - Log.w(TAG, "performConfigurationChanged didn't callback to IME " - + ", configDiff=" + configDiff - + ", mConfiguration=" + mConfiguration); - } - } - } - } + // These are only done to maintain @UnsupportedAppUsage and should be removed someday. + mCurDefaultDisplayDpi = mConfigurationController.getCurDefaultDisplayDpi(); + mConfiguration = mConfigurationController.getConfiguration(); + mPendingConfiguration = mConfigurationController.getPendingConfiguration( + false /* clearPending */); } /** @@ -6093,25 +5955,15 @@ public final class ActivityThread extends ClientTransactionHandler { // so that we actually call through to all components. // TODO(adamlesinski): Change this to make use of ActivityManager's upcoming ability to // store configurations per-process. + final Configuration config = mConfigurationController.getConfiguration(); Configuration newConfig = new Configuration(); - newConfig.assetsSeq = (mConfiguration != null ? mConfiguration.assetsSeq : 0) + 1; - handleConfigurationChanged(newConfig, null); + newConfig.assetsSeq = (config != null ? config.assetsSeq : 0) + 1; + mConfigurationController.handleConfigurationChanged(newConfig, null /* compat */); // Preserve windows to avoid black flickers when overlays change. relaunchAllActivities(true /* preserveWindows */, "handleApplicationInfoChanged"); } - static void freeTextLayoutCachesIfNeeded(int configDiff) { - if (configDiff != 0) { - // Ask text layout engine to free its caches if there is a locale change - boolean hasLocaleConfigChange = ((configDiff & ActivityInfo.CONFIG_LOCALE) != 0); - if (hasLocaleConfigChange) { - Canvas.freeTextLayoutCaches(); - if (DEBUG_CONFIGURATION) Slog.v(TAG, "Cleared TextLayout Caches"); - } - } - } - /** * Sets the supplied {@code overrideConfig} as pending for the {@code activityToken}. Calling * this method prevents any calls to @@ -6188,7 +6040,7 @@ public final class ActivityThread extends ClientTransactionHandler { + ", config=" + overrideConfig); } final Configuration reportedConfig = performConfigurationChangedForActivity(r, - mCompatConfiguration, + mConfigurationController.getCompatConfiguration(), movedToDifferentDisplay ? displayId : r.activity.getDisplayId()); // Notify the ViewRootImpl instance about configuration changes. It may have initiated this // update to make sure that resources are updated before updating itself. @@ -6483,16 +6335,6 @@ public final class ActivityThread extends ClientTransactionHandler { Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } - private void updateDefaultDensity() { - final int densityDpi = mCurDefaultDisplayDpi; - if (!mDensityCompatMode - && densityDpi != Configuration.DENSITY_DPI_UNDEFINED - && densityDpi != DisplayMetrics.DENSITY_DEVICE) { - DisplayMetrics.DENSITY_DEVICE = densityDpi; - Bitmap.setDefaultDensity(densityDpi); - } - } - /** * Returns the correct library directory for the current ABI. * <p> @@ -6519,27 +6361,6 @@ public final class ActivityThread extends ClientTransactionHandler { return insInfo.nativeLibraryDir; } - /** - * The LocaleList set for the app's resources may have been shuffled so that the preferred - * Locale is at position 0. We must find the index of this preferred Locale in the - * original LocaleList. - */ - private void updateLocaleListFromAppContext(Context context, LocaleList newLocaleList) { - final Locale bestLocale = context.getResources().getConfiguration().getLocales().get(0); - final int newLocaleListSize = newLocaleList.size(); - for (int i = 0; i < newLocaleListSize; i++) { - if (bestLocale.equals(newLocaleList.get(i))) { - LocaleList.setDefault(newLocaleList, i); - return; - } - } - - // The app may have overridden the LocaleList with its own Locale - // (not present in the available list). Push the chosen Locale - // to the front of the list. - LocaleList.setDefault(new LocaleList(bestLocale, newLocaleList)); - } - @UnsupportedAppUsage private void handleBindApplication(AppBindData data) { // Register the UI Thread as a sensitive thread to the runtime. @@ -6560,8 +6381,9 @@ public final class ActivityThread extends ClientTransactionHandler { AppSpecializationHooks.handleCompatChangesBeforeBindingApplication(); mBoundApplication = data; - mConfiguration = new Configuration(data.config); - mCompatConfiguration = new Configuration(data.config); + mConfigurationController.setConfiguration(data.config); + mConfigurationController.setCompatConfiguration(data.config); + mConfiguration = mConfigurationController.getConfiguration(); mProfiler = new Profiler(); String agent = null; @@ -6641,7 +6463,7 @@ public final class ActivityThread extends ClientTransactionHandler { mCurDefaultDisplayDpi = data.config.densityDpi; // This calls mResourcesManager so keep it within the synchronized block. - applyCompatConfiguration(mCurDefaultDisplayDpi); + mConfigurationController.applyCompatConfiguration(); } data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo); @@ -6658,7 +6480,7 @@ public final class ActivityThread extends ClientTransactionHandler { mDensityCompatMode = true; Bitmap.setDefaultDensity(DisplayMetrics.DENSITY_DEFAULT); } - updateDefaultDensity(); + mConfigurationController.updateDefaultDensity(data.config.densityDpi); // mCoreSettings is only updated from the main thread, while this function is only called // from main thread as well, so no need to lock here. @@ -6735,8 +6557,7 @@ public final class ActivityThread extends ClientTransactionHandler { } final ContextImpl appContext = ContextImpl.createAppContext(this, data.info); - updateLocaleListFromAppContext(appContext, - mResourcesManager.getConfiguration().getLocales()); + mConfigurationController.updateLocaleListFromAppContext(appContext); // Initialize the default http proxy in this process. Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Setup proxies"); @@ -7611,6 +7432,7 @@ public final class ActivityThread extends ClientTransactionHandler { @UnsupportedAppUsage private void attach(boolean system, long startSeq) { sCurrentActivityThread = this; + mConfigurationController = new ConfigurationController(this); mSystemThread = system; if (!system) { android.ddm.DdmHandleAppName.setAppName("<pre-initialized>", @@ -7662,8 +7484,7 @@ public final class ActivityThread extends ClientTransactionHandler { } } - ViewRootImpl.ConfigChangedCallback configChangedCallback - = (Configuration globalConfig) -> { + ViewRootImpl.ConfigChangedCallback configChangedCallback = (Configuration globalConfig) -> { synchronized (mResourcesManager) { // TODO (b/135719017): Temporary log for debugging IME service. if (Build.IS_DEBUGGABLE && mHasImeComponent) { @@ -7676,14 +7497,15 @@ public final class ActivityThread extends ClientTransactionHandler { if (mResourcesManager.applyConfigurationToResourcesLocked(globalConfig, null /* compat */, mInitialApplication.getResources().getDisplayAdjustments())) { - updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(), - mResourcesManager.getConfiguration().getLocales()); + mConfigurationController.updateLocaleListFromAppContext( + mInitialApplication.getApplicationContext()); // This actually changed the resources! Tell everyone about it. - if (mPendingConfiguration == null - || mPendingConfiguration.isOtherSeqNewer(globalConfig)) { - mPendingConfiguration = globalConfig; + final Configuration updatedConfig = + mConfigurationController.updatePendingConfiguration(globalConfig); + if (updatedConfig != null) { sendMessage(H.CONFIGURATION_CHANGED, globalConfig); + mPendingConfiguration = updatedConfig; } } } @@ -8019,6 +7841,16 @@ public final class ActivityThread extends ClientTransactionHandler { return false; } + @Override + public boolean isInDensityCompatMode() { + return mDensityCompatMode; + } + + @Override + public boolean hasImeComponent() { + return mHasImeComponent; + } + // ------------------ Regular JNI ------------------------ private native void nPurgePendingResources(); private native void nDumpGraphicsInfo(FileDescriptor fd); diff --git a/core/java/android/app/ActivityThreadInternal.java b/core/java/android/app/ActivityThreadInternal.java new file mode 100644 index 000000000000..d91933c0f817 --- /dev/null +++ b/core/java/android/app/ActivityThreadInternal.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 android.app; + +import android.content.ComponentCallbacks2; + +import java.util.ArrayList; + +/** + * ActivityThread internal interface. + * It is a subset of ActivityThread and used for communicating with + * {@link ConfigurationController}. + */ +interface ActivityThreadInternal { + ContextImpl getSystemContext(); + + ContextImpl getSystemUiContext(); + + boolean isInDensityCompatMode(); + + boolean hasImeComponent(); + + boolean isCachedProcessState(); + + Application getApplication(); + + ArrayList<ComponentCallbacks2> collectComponentCallbacks(boolean includeActivities); +} diff --git a/core/java/android/app/ConfigurationController.java b/core/java/android/app/ConfigurationController.java new file mode 100644 index 000000000000..0dbe3ba1c4fb --- /dev/null +++ b/core/java/android/app/ConfigurationController.java @@ -0,0 +1,343 @@ +/* + * 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.app; + +import static android.app.ActivityThread.DEBUG_CONFIGURATION; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ComponentCallbacks2; +import android.content.Context; +import android.content.pm.ActivityInfo; +import android.content.res.CompatibilityInfo; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.HardwareRenderer; +import android.inputmethodservice.InputMethodService; +import android.os.Build; +import android.os.LocaleList; +import android.os.Trace; +import android.util.DisplayMetrics; +import android.util.Log; +import android.util.Slog; +import android.view.ContextThemeWrapper; +import android.view.WindowManagerGlobal; + +import com.android.internal.annotations.GuardedBy; + +import java.util.ArrayList; +import java.util.Locale; + +/** + * A client side controller to handle process level configuration changes. + * @hide + */ +class ConfigurationController { + private static final String TAG = "ConfigurationController"; + + private final ActivityThreadInternal mActivityThread; + + private final ResourcesManager mResourcesManager = ResourcesManager.getInstance(); + + @GuardedBy("mResourcesManager") + private @Nullable Configuration mPendingConfiguration; + private @Nullable Configuration mCompatConfiguration; + private @Nullable Configuration mConfiguration; + + ConfigurationController(@NonNull ActivityThreadInternal activityThread) { + mActivityThread = activityThread; + } + + /** Update the pending configuration. */ + Configuration updatePendingConfiguration(@NonNull Configuration config) { + synchronized (mResourcesManager) { + if (mPendingConfiguration == null || mPendingConfiguration.isOtherSeqNewer(config)) { + mPendingConfiguration = config; + return mPendingConfiguration; + } + } + return null; + } + + /** Get the pending configuration. */ + Configuration getPendingConfiguration(boolean clearPending) { + Configuration outConfig = null; + synchronized (mResourcesManager) { + if (mPendingConfiguration != null) { + outConfig = mPendingConfiguration; + if (clearPending) { + mPendingConfiguration = null; + } + } + } + return outConfig; + } + + /** Set the compatibility configuration. */ + void setCompatConfiguration(@NonNull Configuration config) { + mCompatConfiguration = new Configuration(config); + } + + /** Get the compatibility configuration. */ + Configuration getCompatConfiguration() { + return mCompatConfiguration; + } + + /** Apply the global compatibility configuration. */ + final Configuration applyCompatConfiguration() { + Configuration config = mConfiguration; + final int displayDensity = config.densityDpi; + if (mCompatConfiguration == null) { + mCompatConfiguration = new Configuration(); + } + mCompatConfiguration.setTo(mConfiguration); + if (mResourcesManager.applyCompatConfigurationLocked(displayDensity, + mCompatConfiguration)) { + config = mCompatConfiguration; + } + return config; + } + + /** Set the configuration. */ + void setConfiguration(@NonNull Configuration config) { + mConfiguration = new Configuration(config); + } + + /** Get current configuration. */ + Configuration getConfiguration() { + return mConfiguration; + } + + /** + * Update the configuration to latest. + * @param config The new configuration. + */ + void handleConfigurationChanged(@NonNull Configuration config) { + if (mActivityThread.isCachedProcessState()) { + updatePendingConfiguration(config); + // If the process is in a cached state, delay the handling until the process is no + // longer cached. + return; + } + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "configChanged"); + handleConfigurationChanged(config, null /* compat */); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); + } + + /** + * Update the configuration to latest. + * @param compat The new compatibility information. + */ + void handleConfigurationChanged(@NonNull CompatibilityInfo compat) { + handleConfigurationChanged(mConfiguration, compat); + WindowManagerGlobal.getInstance().reportNewConfiguration(mConfiguration); + } + + /** + * Update the configuration to latest. + * @param config The new configuration. + * @param compat The new compatibility information. + */ + void handleConfigurationChanged(@Nullable Configuration config, + @Nullable CompatibilityInfo compat) { + int configDiff; + boolean equivalent; + + final Resources.Theme systemTheme = mActivityThread.getSystemContext().getTheme(); + final Resources.Theme systemUiTheme = mActivityThread.getSystemUiContext().getTheme(); + + synchronized (mResourcesManager) { + if (mPendingConfiguration != null) { + if (!mPendingConfiguration.isOtherSeqNewer(config)) { + config = mPendingConfiguration; + updateDefaultDensity(config.densityDpi); + } + mPendingConfiguration = null; + } + + final boolean hasIme = mActivityThread.hasImeComponent(); + if (config == null) { + // TODO (b/135719017): Temporary log for debugging IME service. + if (Build.IS_DEBUGGABLE && hasIme) { + Log.w(TAG, "handleConfigurationChanged for IME app but config is null"); + } + return; + } + + // This flag tracks whether the new configuration is fundamentally equivalent to the + // existing configuration. This is necessary to determine whether non-activity callbacks + // should receive notice when the only changes are related to non-public fields. + // We do not gate calling {@link #performActivityConfigurationChanged} based on this + // flag as that method uses the same check on the activity config override as well. + equivalent = mConfiguration != null && (0 == mConfiguration.diffPublicOnly(config)); + + if (DEBUG_CONFIGURATION) { + Slog.v(TAG, "Handle configuration changed: " + config); + } + + final Application app = mActivityThread.getApplication(); + final Resources appResources = app.getResources(); + if (appResources.hasOverrideDisplayAdjustments()) { + // The value of Display#getRealSize will be adjusted by FixedRotationAdjustments, + // but Display#getSize refers to DisplayAdjustments#mConfiguration. So the rotated + // configuration also needs to set to the adjustments for consistency. + appResources.getDisplayAdjustments().getConfiguration().updateFrom(config); + } + mResourcesManager.applyConfigurationToResourcesLocked(config, compat, + appResources.getDisplayAdjustments()); + updateLocaleListFromAppContext(app.getApplicationContext()); + + if (mConfiguration == null) { + mConfiguration = new Configuration(); + } + if (!mConfiguration.isOtherSeqNewer(config) && compat == null) { + // TODO (b/135719017): Temporary log for debugging IME service. + if (Build.IS_DEBUGGABLE && hasIme) { + Log.w(TAG, "handleConfigurationChanged for IME app but config seq is obsolete " + + ", config=" + config + + ", mConfiguration=" + mConfiguration); + } + return; + } + + configDiff = mConfiguration.updateFrom(config); + config = applyCompatConfiguration(); + HardwareRenderer.sendDeviceConfigurationForDebugging(config); + + if ((systemTheme.getChangingConfigurations() & configDiff) != 0) { + systemTheme.rebase(); + } + + if ((systemUiTheme.getChangingConfigurations() & configDiff) != 0) { + systemUiTheme.rebase(); + } + } + + final ArrayList<ComponentCallbacks2> callbacks = + mActivityThread.collectComponentCallbacks(false /* includeActivities */); + + freeTextLayoutCachesIfNeeded(configDiff); + + if (callbacks != null) { + final int size = callbacks.size(); + for (int i = 0; i < size; i++) { + ComponentCallbacks2 cb = callbacks.get(i); + if (!equivalent) { + performConfigurationChanged(cb, config); + } else { + // TODO (b/135719017): Temporary log for debugging IME service. + if (Build.IS_DEBUGGABLE && cb instanceof InputMethodService) { + Log.w(TAG, "performConfigurationChanged didn't callback to IME " + + ", configDiff=" + configDiff + + ", mConfiguration=" + mConfiguration); + } + } + } + } + } + + /** + * Decides whether to update a component's configuration and whether to inform it. + * @param cb The component callback to notify of configuration change. + * @param newConfig The new configuration. + */ + void performConfigurationChanged(@NonNull ComponentCallbacks2 cb, + @NonNull Configuration newConfig) { + // ContextThemeWrappers may override the configuration for that context. We must check and + // apply any overrides defined. + Configuration contextThemeWrapperOverrideConfig = null; + if (cb instanceof ContextThemeWrapper) { + final ContextThemeWrapper contextThemeWrapper = (ContextThemeWrapper) cb; + contextThemeWrapperOverrideConfig = contextThemeWrapper.getOverrideConfiguration(); + } + + // Apply the ContextThemeWrapper override if necessary. + // NOTE: Make sure the configurations are not modified, as they are treated as immutable + // in many places. + final Configuration configToReport = createNewConfigAndUpdateIfNotNull( + newConfig, contextThemeWrapperOverrideConfig); + cb.onConfigurationChanged(configToReport); + } + + /** Update default density. */ + void updateDefaultDensity(int densityDpi) { + if (!mActivityThread.isInDensityCompatMode() + && densityDpi != Configuration.DENSITY_DPI_UNDEFINED + && densityDpi != DisplayMetrics.DENSITY_DEVICE) { + DisplayMetrics.DENSITY_DEVICE = densityDpi; + Bitmap.setDefaultDensity(densityDpi); + } + } + + /** Get current default display dpi. This is only done to maintain @UnsupportedAppUsage. */ + int getCurDefaultDisplayDpi() { + return mConfiguration.densityDpi; + } + + /** + * The LocaleList set for the app's resources may have been shuffled so that the preferred + * Locale is at position 0. We must find the index of this preferred Locale in the + * original LocaleList. + */ + void updateLocaleListFromAppContext(@NonNull Context context) { + final Locale bestLocale = context.getResources().getConfiguration().getLocales().get(0); + final LocaleList newLocaleList = mResourcesManager.getConfiguration().getLocales(); + final int newLocaleListSize = newLocaleList.size(); + for (int i = 0; i < newLocaleListSize; i++) { + if (bestLocale.equals(newLocaleList.get(i))) { + LocaleList.setDefault(newLocaleList, i); + return; + } + } + + // The app may have overridden the LocaleList with its own Locale + // (not present in the available list). Push the chosen Locale + // to the front of the list. + LocaleList.setDefault(new LocaleList(bestLocale, newLocaleList)); + } + + /** + * Creates a new Configuration only if override would modify base. Otherwise returns base. + * @param base The base configuration. + * @param override The update to apply to the base configuration. Can be null. + * @return A Configuration representing base with override applied. + */ + static Configuration createNewConfigAndUpdateIfNotNull(@NonNull Configuration base, + @Nullable Configuration override) { + if (override == null) { + return base; + } + Configuration newConfig = new Configuration(base); + newConfig.updateFrom(override); + return newConfig; + } + + /** Ask test layout engine to free its caches if there is a locale change. */ + static void freeTextLayoutCachesIfNeeded(int configDiff) { + if (configDiff != 0) { + boolean hasLocaleConfigChange = ((configDiff & ActivityInfo.CONFIG_LOCALE) != 0); + if (hasLocaleConfigChange) { + Canvas.freeTextLayoutCaches(); + if (DEBUG_CONFIGURATION) { + Slog.v(TAG, "Cleared TextLayout Caches"); + } + } + } + } +} diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index bc798136f2e3..d040938803f6 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -31,6 +31,7 @@ import android.content.ContentCaptureOptions; 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 @@ class ContextImpl extends Context { @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 @@ class ContextImpl extends Context { /** @hide */ @Override public @Nullable String getAttributionTag() { - return mAttributionTag; + return mParams.getAttributionTag(); + } + + @Override + public @Nullable ContextParams getParams() { + return mParams; } @Override @@ -2046,6 +2051,11 @@ class ContextImpl extends Context { 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 @@ class ContextImpl extends Context { 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 @@ class ContextImpl extends Context { 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 @@ class ContextImpl extends Context { 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 @@ class ContextImpl extends Context { 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 @@ class ContextImpl extends Context { 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 @@ class ContextImpl extends Context { 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 @@ class ContextImpl extends Context { 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 @@ class ContextImpl extends Context { 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 @@ class ContextImpl extends Context { compatInfo, mClassLoader, loaders); } + @NonNull @Override - public @NonNull Context createAttributionContext(@Nullable String attributionTag) { - return new ContextImpl(this, mMainThread, mPackageInfo, attributionTag, mSplitName, + 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 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 @@ class ContextImpl extends Context { 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 @@ class ContextImpl extends Context { @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 @@ class ContextImpl extends Context { */ 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 @@ class ContextImpl extends Context { 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 @@ class ContextImpl extends Context { } } - 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 @@ class ContextImpl extends Context { } 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 @@ class ContextImpl extends Context { } 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 ac1fa1ec6837..47de04078b45 100644 --- a/core/java/android/app/GameManager.java +++ b/core/java/android/app/GameManager.java @@ -18,8 +18,11 @@ package android.app; 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.RemoteException; 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 @@ public final class GameManager { /** * 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 3a8172ea98b8..ef0dcabbe111 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -706,7 +706,7 @@ interface IActivityManager { 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/app/IGameManager.aidl b/core/java/android/app/IGameManager.aidl new file mode 100644 index 000000000000..3730de82f94a --- /dev/null +++ b/core/java/android/app/IGameManager.aidl @@ -0,0 +1,28 @@ +/* + * 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.app; + +/** + * 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/Notification.java b/core/java/android/app/Notification.java index bc24e9767944..b00cfcb0d020 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -92,7 +92,6 @@ import android.util.proto.ProtoOutputStream; import android.view.ContextThemeWrapper; import android.view.Gravity; import android.view.View; -import android.view.ViewGroup; import android.view.contentcapture.ContentCaptureContext; import android.widget.ProgressBar; import android.widget.RemoteViews; @@ -4970,8 +4969,6 @@ public class Notification implements Parcelable contentView.setTextViewText(R.id.title, null); contentView.setViewVisibility(R.id.text, View.GONE); contentView.setTextViewText(R.id.text, null); - contentView.setViewVisibility(R.id.text_line_1, View.GONE); - contentView.setTextViewText(R.id.text_line_1, null); } /** @@ -5015,14 +5012,10 @@ public class Notification implements Parcelable contentView.setViewVisibility(R.id.title, View.VISIBLE); contentView.setTextViewText(R.id.title, processTextSpans(p.title)); setTextViewColorPrimary(contentView, R.id.title, p); - contentView.setViewLayoutWidth(R.id.title, showProgress - ? ViewGroup.LayoutParams.WRAP_CONTENT - : ViewGroup.LayoutParams.MATCH_PARENT, - TypedValue.COMPLEX_UNIT_PX); - } - if (p.text != null && p.text.length() != 0) { - int textId = showProgress ? com.android.internal.R.id.text_line_1 - : com.android.internal.R.id.text; + } + if (p.text != null && p.text.length() != 0 + && (!showProgress || p.mAllowTextWithProgress)) { + int textId = com.android.internal.R.id.text; contentView.setTextViewText(textId, processTextSpans(p.text)); setTextViewColorSecondary(contentView, textId, p); contentView.setViewVisibility(textId, View.VISIBLE); @@ -5188,16 +5181,13 @@ public class Notification implements Parcelable final boolean ind = ex.getBoolean(EXTRA_PROGRESS_INDETERMINATE); if (!p.mHideProgress && (max != 0 || ind)) { contentView.setViewVisibility(com.android.internal.R.id.progress, View.VISIBLE); - contentView.setProgressBar( - R.id.progress, max, progress, ind); - contentView.setProgressBackgroundTintList( - R.id.progress, ColorStateList.valueOf(mContext.getColor( - R.color.notification_progress_background_color))); - if (getRawColor(p) != COLOR_DEFAULT) { - int color = getAccentColor(p); - ColorStateList colorStateList = ColorStateList.valueOf(color); - contentView.setProgressTintList(R.id.progress, colorStateList); - contentView.setProgressIndeterminateTintList(R.id.progress, colorStateList); + contentView.setProgressBar(R.id.progress, max, progress, ind); + contentView.setProgressBackgroundTintList(R.id.progress, + mContext.getColorStateList(R.color.notification_progress_background_color)); + if (mTintWithThemeAccent || getRawColor(p) != COLOR_DEFAULT) { + ColorStateList progressTint = ColorStateList.valueOf(getAccentColor(p)); + contentView.setProgressTintList(R.id.progress, progressTint); + contentView.setProgressIndeterminateTintList(R.id.progress, progressTint); } return true; } else { @@ -5220,7 +5210,7 @@ public class Notification implements Parcelable } else { // views in states with a header (big states) result.mHeadingExtraMarginSet.applyToView(contentView, R.id.notification_header); - result.mTitleMarginSet.applyToView(contentView, R.id.line1); + result.mTitleMarginSet.applyToView(contentView, R.id.title); } } @@ -5749,7 +5739,6 @@ public class Notification implements Parcelable } if (mStyle != null) { result = mStyle.makeBigContentView(); - hideLine1Text(result); if (fullyCustomViewRequiresDecoration(true /* fromStyle */)) { result = minimallyDecoratedBigContentView(result); } @@ -5758,6 +5747,7 @@ public class Notification implements Parcelable if (bigContentViewRequired()) { StandardTemplateParams p = mParams.reset() .viewType(StandardTemplateParams.VIEW_TYPE_BIG) + .allowTextWithProgress(true) .fillTextsFrom(this); result = applyStandardTemplateWithActions(getBigBaseLayoutResource(), p, null /* result */); @@ -5832,12 +5822,6 @@ public class Notification implements Parcelable return createContentView(); } - private void hideLine1Text(RemoteViews result) { - if (result != null) { - result.setViewVisibility(R.id.text_line_1, View.GONE); - } - } - /** * Adapt the Notification header if this view is used as an expanded view. * @@ -6270,6 +6254,9 @@ public class Notification implements Parcelable if (rawColor == COLOR_DEFAULT) { ensureColors(p); color = ContrastColorUtil.resolveDefaultColor(mContext, background, mInNightMode); + if (mTintWithThemeAccent) { + color = obtainThemeColor(R.attr.colorAccent, color); + } } else { color = ContrastColorUtil.resolveContrastColor(mContext, rawColor, background, mInNightMode); @@ -7031,9 +7018,9 @@ public class Notification implements Parcelable result); if (mBigContentTitle != null && mBigContentTitle.equals("")) { - contentView.setViewVisibility(R.id.line1, View.GONE); + contentView.setViewVisibility(R.id.title, View.GONE); } else { - contentView.setViewVisibility(R.id.line1, View.VISIBLE); + contentView.setViewVisibility(R.id.title, View.VISIBLE); } return contentView; @@ -9100,7 +9087,7 @@ public class Notification implements Parcelable private void handleImage(RemoteViews contentView) { if (mBuilder.mN.hasLargeIcon()) { - contentView.setViewLayoutMarginDimen(R.id.line1, RemoteViews.MARGIN_END, 0); + contentView.setViewLayoutMarginDimen(R.id.title, RemoteViews.MARGIN_END, 0); contentView.setViewLayoutMarginDimen(R.id.text, RemoteViews.MARGIN_END, 0); } } @@ -9409,6 +9396,7 @@ public class Notification implements Parcelable StandardTemplateParams p = mBuilder.mParams.reset() .viewType(StandardTemplateParams.VIEW_TYPE_BIG) .allowActionIcons(true) + .allowTextWithProgress(true) .hideLargeIcon(true) .text(text) .summaryText(mBuilder.processLegacyText(mVerificationText)); @@ -9919,6 +9907,22 @@ public class Notification implements Parcelable */ public static final int FLAG_SUPPRESS_NOTIFICATION = 0x00000002; + /** + * Indicates whether the bubble should be visually suppressed from the bubble stack if the + * user is viewing the same content outside of the bubble. For example, the user has a + * bubble with Alice and then opens up the main app and navigates to Alice's page. + * + * @hide + */ + public static final int FLAG_SHOULD_SUPPRESS_BUBBLE = 0x00000004; + + /** + * Indicates whether the bubble is visually suppressed from the bubble stack. + * + * @hide + */ + public static final int FLAG_SUPPRESS_BUBBLE = 0x00000008; + private BubbleMetadata(PendingIntent expandIntent, PendingIntent deleteIntent, Icon icon, int height, @DimenRes int heightResId, String shortcutId) { mPendingIntent = expandIntent; @@ -10061,6 +10065,32 @@ public class Notification implements Parcelable return (mFlags & FLAG_SUPPRESS_NOTIFICATION) != 0; } + /** + * Indicates whether the bubble should be visually suppressed from the bubble stack if the + * user is viewing the same content outside of the bubble. For example, the user has a + * bubble with Alice and then opens up the main app and navigates to Alice's page. + * + * To match the activity and the bubble notification, the bubble notification should + * have a locus id set that matches a locus id set on the activity. + * + * @return whether this bubble should be suppressed when the same content is visible + * outside of the bubble. + * + * @see BubbleMetadata.Builder#setSuppressBubble(boolean) + */ + public boolean isBubbleSuppressable() { + return (mFlags & FLAG_SHOULD_SUPPRESS_BUBBLE) != 0; + } + + /** + * Indicates whether the bubble is currently visually suppressed from the bubble stack. + * + * @see BubbleMetadata.Builder#setSuppressBubble(boolean) + */ + public boolean isBubbleSuppressed() { + return (mFlags & FLAG_SUPPRESS_BUBBLE) != 0; + } + public static final @android.annotation.NonNull Parcelable.Creator<BubbleMetadata> CREATOR = new Parcelable.Creator<BubbleMetadata>() { @@ -10403,6 +10433,23 @@ public class Notification implements Parcelable } /** + * Indicates whether the bubble should be visually suppressed from the bubble stack if + * the user is viewing the same content outside of the bubble. For example, the user has + * a bubble with Alice and then opens up the main app and navigates to Alice's page. + * + * To match the activity and the bubble notification, the bubble notification should + * have a locus id set that matches a locus id set on the activity. + * + * {@link Notification.Builder#setLocusId(LocusId)} + * {@link Activity#setLocusContext(LocusId, Bundle)} + */ + @NonNull + public BubbleMetadata.Builder setSuppressBubble(boolean suppressBubble) { + setFlag(FLAG_SHOULD_SUPPRESS_BUBBLE, suppressBubble); + return this; + } + + /** * Sets an intent to send when this bubble is explicitly removed by the user. * * <p>Setting a delete intent is optional.</p> @@ -12073,6 +12120,7 @@ public class Notification implements Parcelable boolean mHideSnoozeButton; boolean mPromotePicture; boolean mAllowActionIcons; + boolean mAllowTextWithProgress; CharSequence title; CharSequence text; CharSequence headerTextSecondary; @@ -12091,6 +12139,7 @@ public class Notification implements Parcelable mHideSnoozeButton = false; mPromotePicture = false; mAllowActionIcons = false; + mAllowTextWithProgress = false; title = null; text = null; summaryText = null; @@ -12135,6 +12184,11 @@ public class Notification implements Parcelable return this; } + final StandardTemplateParams allowTextWithProgress(boolean allowTextWithProgress) { + this.mAllowTextWithProgress = allowTextWithProgress; + return this; + } + final StandardTemplateParams hideSnoozeButton(boolean hideSnoozeButton) { this.mHideSnoozeButton = hideSnoozeButton; return this; diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java index 549bd4b9fe6a..11adc5a60fb3 100644 --- a/core/java/android/app/PendingIntent.java +++ b/core/java/android/app/PendingIntent.java @@ -26,7 +26,6 @@ import android.annotation.IntDef; 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.IIntentSender; 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 com.android.internal.os.IResultReceiver; 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,41 @@ public final class PendingIntent implements Parcelable { * @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(); + } + } + + /** + * Comparison operator on two PendingIntent objects, such that true is returned when they + * represent {@link Intent}s that are equal as per {@link Intent#filterEquals}. + * + * @param other The other PendingIntent to compare against. + * @return True if action, data, type, class, and categories on two intents are the same. + * + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @TestApi + @RequiresPermission(android.Manifest.permission.GET_INTENT_SENDER_INTENT) + public boolean intentFilterEquals(@Nullable PendingIntent other) { + if (other == null) { + return false; + } + try { + return ActivityManager.getService().getIntentForIntentSender(other.mTarget) + .filterEquals(getIntent()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java index 9019ddf941d9..6ad5eea8b602 100644 --- a/core/java/android/app/TaskInfo.java +++ b/core/java/android/app/TaskInfo.java @@ -24,6 +24,7 @@ import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Intent; +import android.content.LocusId; import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.graphics.Point; @@ -123,6 +124,13 @@ public class TaskInfo { public ActivityManager.TaskDescription taskDescription; /** + * The locusId of the task. + * @hide + */ + @Nullable + public LocusId mTopActivityLocusId; + + /** * True if the task can go in the split-screen primary stack. * @hide */ @@ -381,6 +389,7 @@ public class TaskInfo { isVisible = source.readBoolean(); topActivityToken = source.readStrongBinder(); topActivityInSizeCompat = source.readBoolean(); + mTopActivityLocusId = source.readTypedObject(LocusId.CREATOR); } /** @@ -417,6 +426,7 @@ public class TaskInfo { dest.writeBoolean(isVisible); dest.writeStrongBinder(topActivityToken); dest.writeBoolean(topActivityInSizeCompat); + dest.writeTypedObject(mTopActivityLocusId, flags); } @Override @@ -443,6 +453,7 @@ public class TaskInfo { + " isVisible=" + isVisible + " topActivityToken=" + topActivityToken + " topActivityInSizeCompat=" + topActivityInSizeCompat + + " locusId= " + mTopActivityLocusId + "}"; } } diff --git a/core/java/android/app/WallpaperColors.java b/core/java/android/app/WallpaperColors.java index 0a8a73404a7b..6b2e649b0c69 100644 --- a/core/java/android/app/WallpaperColors.java +++ b/core/java/android/app/WallpaperColors.java @@ -32,6 +32,7 @@ import android.util.Size; import com.android.internal.graphics.ColorUtils; import com.android.internal.graphics.palette.CelebiQuantizer; import com.android.internal.graphics.palette.Palette; +import com.android.internal.graphics.palette.VariationalKMeansQuantizer; import com.android.internal.util.ContrastColorUtil; import java.io.FileOutputStream; @@ -178,11 +179,20 @@ public final class WallpaperColors implements Parcelable { optimalSize.getHeight(), true /* filter */); } - final Palette palette = Palette - .from(bitmap, new CelebiQuantizer()) - .maximumColorCount(256) - .resizeBitmapArea(MAX_WALLPAPER_EXTRACTION_AREA) - .generate(); + final Palette palette; + if (ActivityManager.isLowRamDeviceStatic()) { + palette = Palette + .from(bitmap, new VariationalKMeansQuantizer()) + .maximumColorCount(5) + .resizeBitmapArea(MAX_WALLPAPER_EXTRACTION_AREA) + .generate(); + } else { + palette = Palette + .from(bitmap, new CelebiQuantizer()) + .maximumColorCount(256) + .resizeBitmapArea(MAX_WALLPAPER_EXTRACTION_AREA) + .generate(); + } // Remove insignificant colors and sort swatches by population final ArrayList<Palette.Swatch> swatches = new ArrayList<>(palette.getSwatches()); swatches.sort((a, b) -> b.getPopulation() - a.getPopulation()); diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index b919bfc92e79..ccf41e5f3063 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -2997,6 +2997,7 @@ public class DevicePolicyManager { */ // 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 @@ public class DevicePolicyManager { } /** + * 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 ac1592d2d2a1..25ca59963d4b 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -479,6 +479,8 @@ interface IDevicePolicyManager { 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/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java index fc54c716d4ec..d79fac58cf12 100644 --- a/core/java/android/appwidget/AppWidgetHostView.java +++ b/core/java/android/appwidget/AppWidgetHostView.java @@ -39,6 +39,7 @@ import android.os.Parcelable; 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 android.widget.TextView; import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.concurrent.Executor; /** @@ -93,7 +93,7 @@ public class AppWidgetHostView extends FrameLayout { 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 @@ public class AppWidgetHostView extends FrameLayout { } } + 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 @@ public class AppWidgetHostView extends FrameLayout { * 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 @@ public class AppWidgetHostView extends FrameLayout { 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 @@ public class AppWidgetHostView extends FrameLayout { } /** - * 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 @@ public class AppWidgetHostView extends FrameLayout { 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 @@ public class AppWidgetHostView extends FrameLayout { // 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 38919f61d9df..a88aed7f20a3 100644 --- a/core/java/android/appwidget/AppWidgetManager.java +++ b/core/java/android/appwidget/AppWidgetManager.java @@ -219,7 +219,7 @@ public class AppWidgetManager { 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 102c98ff9329..b07d6d5b1bc3 100644 --- a/core/java/android/companion/AssociationRequest.java +++ b/core/java/android/companion/AssociationRequest.java @@ -60,10 +60,16 @@ public final class AssociationRequest implements Parcelable { /** * 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 @@ public final class AssociationRequest implements Parcelable { */ 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 @@ public final class AssociationRequest implements Parcelable { markUsed(); return new AssociationRequest( mSingleDevice, emptyIfNull(mDeviceFilters), - mDeviceProfile, null, null); + mDeviceProfile, null, null, -1L); } } @@ -228,6 +245,8 @@ public final class AssociationRequest implements Parcelable { * 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 @@ public final class AssociationRequest implements Parcelable { @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 @@ public final class AssociationRequest implements Parcelable { 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 @@ public final class AssociationRequest implements Parcelable { 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 @@ public final class AssociationRequest implements Parcelable { "deviceFilters = " + mDeviceFilters + ", " + "deviceProfile = " + mDeviceProfile + ", " + "callingPackage = " + mCallingPackage + ", " + - "deviceProfilePrivilegesDescription = " + mDeviceProfilePrivilegesDescription + + "deviceProfilePrivilegesDescription = " + mDeviceProfilePrivilegesDescription + ", " + + "creationTime = " + mCreationTime + " }"; } @@ -316,7 +348,8 @@ public final class AssociationRequest implements Parcelable { && 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 @@ public final class AssociationRequest implements Parcelable { _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 @@ public final class AssociationRequest implements Parcelable { 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 @@ public final class AssociationRequest implements Parcelable { 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 @@ public final class AssociationRequest implements Parcelable { 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 @@ public final class AssociationRequest implements Parcelable { }; @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 59646f106db5..b441b364cec8 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 @@ public final class CompanionDeviceManager { * <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 @@ public final class CompanionDeviceManager { * * @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/ClipboardManager.java b/core/java/android/content/ClipboardManager.java index 7f73238a41e3..cadbd609ff0b 100644 --- a/core/java/android/content/ClipboardManager.java +++ b/core/java/android/content/ClipboardManager.java @@ -16,9 +16,13 @@ package android.content; +import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; import android.annotation.SystemService; +import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.os.Handler; import android.os.RemoteException; @@ -109,6 +113,31 @@ public class ClipboardManager extends android.text.ClipboardManager { } /** + * Sets the current primary clip on the clipboard, attributed to the specified {@code + * sourcePackage}. The primary clip is the clip that is involved in normal cut and paste + * operations. + * + * @param clip The clipped data item to set. + * @param sourcePackage The package name of the app that is the source of the clip data. + * @throws IllegalArgumentException if the clip is null or contains no items. + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.SET_CLIP_SOURCE) + public void setPrimaryClipAsPackage(@NonNull ClipData clip, @NonNull String sourcePackage) { + try { + Objects.requireNonNull(clip); + Objects.requireNonNull(sourcePackage); + clip.prepareToLeaveProcess(true); + mService.setPrimaryClipAsPackage( + clip, mContext.getOpPackageName(), mContext.getUserId(), sourcePackage); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Clears any current primary clip on the clipboard. * * @see #setPrimaryClip(ClipData) @@ -234,6 +263,23 @@ public class ClipboardManager extends android.text.ClipboardManager { } } + /** + * Returns the package name of the source of the current primary clip, or null if there is no + * primary clip or if a source is not available. + * + * @hide + */ + @TestApi + @Nullable + @RequiresPermission(Manifest.permission.SET_CLIP_SOURCE) + public String getPrimaryClipSource() { + try { + return mService.getPrimaryClipSource(mContext.getOpPackageName(), mContext.getUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + @UnsupportedAppUsage void reportPrimaryClipChanged() { Object[] listeners; diff --git a/core/java/android/content/ContentCaptureOptions.java b/core/java/android/content/ContentCaptureOptions.java index c296bb52e73d..77072890a1eb 100644 --- a/core/java/android/content/ContentCaptureOptions.java +++ b/core/java/android/content/ContentCaptureOptions.java @@ -134,7 +134,8 @@ public final class ContentCaptureOptions implements Parcelable { final String packageName = at.getApplication().getPackageName(); - if (!"android.contentcaptureservice.cts".equals(packageName)) { + if (!"android.contentcaptureservice.cts".equals(packageName) + && !"android.translation.cts".equals(packageName)) { Log.e(TAG, "forWhitelistingItself(): called by " + packageName); throw new SecurityException("Thou shall not pass!"); } diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index 230c985d1dc8..8ea417f900db 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -769,7 +769,7 @@ public abstract class ContentResolver implements ContentInterface { // Always log queries which take 500ms+; shorter queries are // sampled accordingly. private static final boolean ENABLE_CONTENT_SAMPLE = false; - private static final int SLOW_THRESHOLD_MILLIS = 500; + private static final int SLOW_THRESHOLD_MILLIS = 500 * Build.HW_TIMEOUT_MULTIPLIER; private final Random mRandom = new Random(); // guarded by itself /** @hide */ @@ -783,7 +783,8 @@ public abstract class ContentResolver implements ContentInterface { * before we decide it must be hung. * @hide */ - public static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS = 10 * 1000; + public static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS = + 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER; /** * How long we wait for an provider to be published. Should be longer than @@ -791,10 +792,11 @@ public abstract class ContentResolver implements ContentInterface { * @hide */ public static final int CONTENT_PROVIDER_READY_TIMEOUT_MILLIS = - CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS + 10 * 1000; + CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS + 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER; // Timeout given a ContentProvider that has already been started and connected to. - private static final int CONTENT_PROVIDER_TIMEOUT_MILLIS = 3 * 1000; + private static final int CONTENT_PROVIDER_TIMEOUT_MILLIS = + 3 * 1000 * Build.HW_TIMEOUT_MULTIPLIER; // Should be >= {@link #CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS}, because that's how // long ActivityManagerService is giving a content provider to get published if a new process diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 02e86cd4a863..df5c58c2634f 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -888,6 +888,14 @@ public abstract class Context { 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(); @@ -5523,8 +5531,6 @@ public abstract class Context { * {@link GameManager}. * * @see #getSystemService(String) - * - * @hide */ public static final String GAME_SERVICE = "game"; @@ -6377,6 +6383,19 @@ public abstract class Context { } /** + * 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 000000000000..17ec2a847d4f --- /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 b71fb2712c24..609f417a8008 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -172,6 +172,11 @@ public class ContextWrapper extends Context { } @Override + public @Nullable ContextParams getParams() { + return mBase.getParams(); + } + + @Override public ApplicationInfo getApplicationInfo() { return mBase.getApplicationInfo(); } @@ -1045,6 +1050,12 @@ public class ContextWrapper extends Context { } @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/IClipboard.aidl b/core/java/android/content/IClipboard.aidl index 0d5a46016f19..102b8e798a5c 100644 --- a/core/java/android/content/IClipboard.aidl +++ b/core/java/android/content/IClipboard.aidl @@ -27,6 +27,8 @@ import android.content.IOnPrimaryClipChangedListener; */ interface IClipboard { void setPrimaryClip(in ClipData clip, String callingPackage, int userId); + void setPrimaryClipAsPackage(in ClipData clip, String callingPackage, int userId, + String sourcePackage); void clearPrimaryClip(String callingPackage, int userId); ClipData getPrimaryClip(String pkg, int userId); ClipDescription getPrimaryClipDescription(String callingPackage, int userId); @@ -40,4 +42,6 @@ interface IClipboard { * Returns true if the clipboard contains text; false otherwise. */ boolean hasClipboardText(String callingPackage, int userId); + + String getPrimaryClipSource(String callingPackage, int userId); } diff --git a/core/java/android/content/OWNERS b/core/java/android/content/OWNERS index 144856b68e7f..d0d406a0c9e6 100644 --- a/core/java/android/content/OWNERS +++ b/core/java/android/content/OWNERS @@ -4,4 +4,7 @@ per-file ContextWrapper.java = * 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/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index b1ca12cde857..1660c9d23002 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -74,12 +74,28 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { */ public static final int LAUNCH_SINGLE_INSTANCE = 3; /** + * Constant corresponding to <code>singleInstancePerTask</code> in + * the {@link android.R.attr#launchMode} attribute. + */ + public static final int LAUNCH_SINGLE_INSTANCE_PER_TASK = 4; + + /** @hide */ + @IntDef(prefix = "LAUNCH_", value = { + LAUNCH_MULTIPLE, + LAUNCH_SINGLE_TOP, + LAUNCH_SINGLE_TASK, + LAUNCH_SINGLE_INSTANCE, + LAUNCH_SINGLE_INSTANCE_PER_TASK + }) + @Retention(RetentionPolicy.SOURCE) + public @interface LaunchMode { + } + + /** * The launch mode style requested by the activity. From the - * {@link android.R.attr#launchMode} attribute, one of - * {@link #LAUNCH_MULTIPLE}, - * {@link #LAUNCH_SINGLE_TOP}, {@link #LAUNCH_SINGLE_TASK}, or - * {@link #LAUNCH_SINGLE_INSTANCE}. + * {@link android.R.attr#launchMode} attribute. */ + @LaunchMode public int launchMode; /** diff --git a/core/java/android/content/pm/DataLoaderParams.java b/core/java/android/content/pm/DataLoaderParams.java index a791026d44cd..93db1e16aea0 100644 --- a/core/java/android/content/pm/DataLoaderParams.java +++ b/core/java/android/content/pm/DataLoaderParams.java @@ -17,17 +17,11 @@ package android.content.pm; import android.annotation.NonNull; -import android.annotation.SystemApi; import android.content.ComponentName; /** * This class represents the parameters used to configure a Data Loader. - * - * WARNING: This is a system API to aid internal development. - * Use at your own risk. It will change or be removed without warning. - * @hide */ -@SystemApi public class DataLoaderParams { @NonNull private final DataLoaderParamsParcel mData; diff --git a/core/java/android/content/pm/IShortcutService.aidl b/core/java/android/content/pm/IShortcutService.aidl index b34574811bca..c91334a5470f 100644 --- a/core/java/android/content/pm/IShortcutService.aidl +++ b/core/java/android/content/pm/IShortcutService.aidl @@ -21,32 +21,34 @@ import android.content.IntentSender; 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 @@ interface IShortcutService { 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/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 42cbe3586db3..5afec0644920 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -235,9 +235,7 @@ public class PackageInstaller { * See the individual types documentation for details. * * @see Intent#getIntExtra(String, int) - * {@hide} */ - @SystemApi public static final String EXTRA_DATA_LOADER_TYPE = "android.content.pm.extra.DATA_LOADER_TYPE"; /** @@ -245,7 +243,6 @@ public class PackageInstaller { * Caller should make sure DataLoader is able to prepare image and reinitiate the operation. * * @see #EXTRA_SESSION_ID - * {@hide} */ public static final int STATUS_PENDING_STREAMING = -2; @@ -348,44 +345,33 @@ public class PackageInstaller { * Default value, non-streaming installation session. * * @see #EXTRA_DATA_LOADER_TYPE - * {@hide} */ - @SystemApi public static final int DATA_LOADER_TYPE_NONE = DataLoaderType.NONE; /** * Streaming installation using data loader. * * @see #EXTRA_DATA_LOADER_TYPE - * {@hide} */ - @SystemApi public static final int DATA_LOADER_TYPE_STREAMING = DataLoaderType.STREAMING; /** * Streaming installation using Incremental FileSystem. * * @see #EXTRA_DATA_LOADER_TYPE - * {@hide} */ - @SystemApi public static final int DATA_LOADER_TYPE_INCREMENTAL = DataLoaderType.INCREMENTAL; /** * Target location for the file in installation session is /data/app/<packageName>-<id>. * This is the intended location for APKs. - * Requires permission to install packages. - * {@hide} */ - @SystemApi public static final int LOCATION_DATA_APP = InstallationFileLocation.DATA_APP; /** * Target location for the file in installation session is * /data/media/<userid>/Android/obb/<packageName>. This is the intended location for OBBs. - * {@hide} */ - @SystemApi public static final int LOCATION_MEDIA_OBB = InstallationFileLocation.MEDIA_OBB; /** @@ -393,9 +379,7 @@ public class PackageInstaller { * /data/media/<userid>/Android/data/<packageName>. * This is the intended location for application data. * Can only be used by an app itself running under specific user. - * {@hide} */ - @SystemApi public static final int LOCATION_MEDIA_DATA = InstallationFileLocation.MEDIA_DATA; /** @hide */ @@ -1167,12 +1151,7 @@ public class PackageInstaller { /** * @return data loader params or null if the session is not using one. - * - * WARNING: This is a system API to aid internal development. - * Use at your own risk. It will change or be removed without warning. - * {@hide} */ - @SystemApi public @Nullable DataLoaderParams getDataLoaderParams() { try { DataLoaderParamsParcel data = mSession.getDataLoaderParams(); @@ -1206,12 +1185,7 @@ public class PackageInstaller { * @throws SecurityException if called after the session has been * sealed or abandoned * @throws IllegalStateException if called for non-callback session - * - * WARNING: This is a system API to aid internal development. - * Use at your own risk. It will change or be removed without warning. - * {@hide} */ - @SystemApi public void addFile(@FileLocation int location, @NonNull String name, long lengthBytes, @NonNull byte[] metadata, @Nullable byte[] signature) { try { @@ -2041,13 +2015,7 @@ public class PackageInstaller { * Set the data loader params for the session. * This also switches installation into data provider mode and disallow direct writes into * staging folder. - * - * WARNING: This is a system API to aid internal development. - * Use at your own risk. It will change or be removed without warning. - * {@hide} */ - @SystemApi - @RequiresPermission(Manifest.permission.INSTALL_PACKAGES) public void setDataLoaderParams(@NonNull DataLoaderParams dataLoaderParams) { this.dataLoaderParams = dataLoaderParams; } diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index bf8d1f6ab07b..5e08399f8abb 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -214,6 +214,7 @@ public class PackageParser { public static final String METADATA_SUPPORTS_SIZE_CHANGES = "android.supports_size_changes"; public static final String METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY = "android.activity_window_layout_affinity"; + public static final String METADATA_ACTIVITY_LAUNCH_MODE = "android.activity.launch_mode"; /** * Bit mask of all the valid bits that can be set in recreateOnConfigChanges. diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java index 83baca668d55..691c69c2459a 100644 --- a/core/java/android/content/pm/PermissionInfo.java +++ b/core/java/android/content/pm/PermissionInfo.java @@ -200,6 +200,8 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable { * to the <code>wellbeing</code> value of * {@link android.R.attr#protectionLevel}. * + * @deprecated this protectionLevel is obsolete. Permissions previously granted through this + * protectionLevel have been migrated to use <code>role</code> instead * @hide */ @SystemApi @@ -307,7 +309,6 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable { PROTECTION_FLAG_OEM, PROTECTION_FLAG_VENDOR_PRIVILEGED, PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER, - PROTECTION_FLAG_WELLBEING, PROTECTION_FLAG_DOCUMENTER, PROTECTION_FLAG_CONFIGURATOR, PROTECTION_FLAG_INCIDENT_REPORT_APPROVER, @@ -560,9 +561,6 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable { if ((level & PermissionInfo.PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER) != 0) { protLevel.append("|textClassifier"); } - if ((level & PermissionInfo.PROTECTION_FLAG_WELLBEING) != 0) { - protLevel.append("|wellbeing"); - } if ((level & PermissionInfo.PROTECTION_FLAG_DOCUMENTER) != 0) { protLevel.append("|documenter"); } diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java index d3bac79aa2b9..f584ff33fa50 100644 --- a/core/java/android/content/pm/ShortcutManager.java +++ b/core/java/android/content/pm/ShortcutManager.java @@ -24,6 +24,7 @@ import android.annotation.SystemApi; 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.ServiceManager; 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 @@ public class ShortcutManager { * * @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 @@ public class ShortcutManager { * * @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 @@ public class ShortcutManager { * * @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 @@ public class ShortcutManager { * * @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 @@ public class ShortcutManager { * * @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 @@ public class ShortcutManager { * * @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 @@ public class ShortcutManager { * * @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 @@ public class ShortcutManager { * @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 @@ public class ShortcutManager { * * @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 @@ public class ShortcutManager { * @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 @@ public class ShortcutManager { 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/TEST_MAPPING b/core/java/android/content/pm/TEST_MAPPING index 953400e10e15..8bc3734e060d 100644 --- a/core/java/android/content/pm/TEST_MAPPING +++ b/core/java/android/content/pm/TEST_MAPPING @@ -31,6 +31,14 @@ "include-filter": "android.content.pm.cts" } ] + }, + { + "name": "CtsIncrementalInstallHostTestCases", + "options": [ + { + "include-filter": "android.incrementalinstall.cts.IncrementalFeatureTest" + } + ] } ], "postsubmit": [ diff --git a/core/java/android/content/pm/parsing/component/ParsedActivity.java b/core/java/android/content/pm/parsing/component/ParsedActivity.java index 2ea24f71371b..6f478accedd7 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 @@ public class ParsedActivity extends ParsedMainComponent { 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 @@ public class ParsedActivity extends ParsedMainComponent { // 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/parsing/component/ParsedActivityUtils.java b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java index f821e081fc66..0f4aa061b72d 100644 --- a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java +++ b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java @@ -16,6 +16,7 @@ package android.content.pm.parsing.component; +import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE_PER_TASK; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.content.pm.parsing.component.ComponentParseUtils.flag; @@ -23,6 +24,7 @@ import android.annotation.NonNull; import android.app.ActivityTaskManager; import android.content.Intent; import android.content.pm.ActivityInfo; +import android.content.pm.PackageParser; import android.content.pm.parsing.ParsingPackage; import android.content.pm.parsing.ParsingPackageUtils; import android.content.pm.parsing.ParsingUtils; @@ -402,6 +404,16 @@ public class ParsedActivityUtils { } } + if (!isAlias && activity.launchMode != LAUNCH_SINGLE_INSTANCE_PER_TASK + && activity.metaData != null && activity.metaData.containsKey( + PackageParser.METADATA_ACTIVITY_LAUNCH_MODE)) { + final String launchMode = activity.metaData.getString( + PackageParser.METADATA_ACTIVITY_LAUNCH_MODE); + if (launchMode != null && launchMode.equals("singleInstancePerTask")) { + activity.launchMode = LAUNCH_SINGLE_INSTANCE_PER_TASK; + } + } + ParseResult<ActivityInfo.WindowLayout> layoutResult = resolveActivityWindowLayout(activity, input); if (layoutResult.isError()) { diff --git a/core/java/android/content/res/ApkAssets.java b/core/java/android/content/res/ApkAssets.java index de48ed75746d..f3783e4a1328 100644 --- a/core/java/android/content/res/ApkAssets.java +++ b/core/java/android/content/res/ApkAssets.java @@ -26,8 +26,6 @@ import android.text.TextUtils; import com.android.internal.annotations.GuardedBy; -import libcore.util.NativeAllocationRegistry; - import java.io.FileDescriptor; import java.io.IOException; import java.lang.annotation.Retention; @@ -104,11 +102,11 @@ public final class ApkAssets { public @interface FormatType {} @GuardedBy("this") - private final long mNativePtr; + private long mNativePtr; // final, except cleared in finalizer. @Nullable @GuardedBy("this") - private final StringBlock mStringBlock; + private final StringBlock mStringBlock; // null or closed if mNativePtr = 0. @PropertyFlags private final int mFlags; @@ -116,19 +114,6 @@ public final class ApkAssets { @Nullable private final AssetsProvider mAssets; - @GuardedBy("this") - @Nullable - private final Runnable mRunNativeCleanup; - - // Use a Holder to allow static initialization of ApkAssets in the boot image, and - // possibly to avoid some initialization ordering issues. - private static class NoImagePreloadHolder { - // TODO(175425996): Make size estimate more accurate - public static final NativeAllocationRegistry REGISTRY = - NativeAllocationRegistry.createMalloced(ApkAssets.class.getClassLoader(), - nativeGetFinalizer()); - } - /** * Creates a new ApkAssets instance from the given path on disk. * @@ -303,8 +288,6 @@ public final class ApkAssets { mFlags = flags; mNativePtr = nativeLoad(format, path, flags, assets); mStringBlock = new StringBlock(nativeGetStringBlock(mNativePtr), true /*useSparse*/); - mRunNativeCleanup = NoImagePreloadHolder.REGISTRY.registerNativeAllocation( - this, mNativePtr); mAssets = assets; } @@ -316,8 +299,6 @@ public final class ApkAssets { mFlags = flags; mNativePtr = nativeLoadFd(format, fd, friendlyName, flags, assets); mStringBlock = new StringBlock(nativeGetStringBlock(mNativePtr), true /*useSparse*/); - mRunNativeCleanup = NoImagePreloadHolder.REGISTRY.registerNativeAllocation( - this, mNativePtr); mAssets = assets; } @@ -329,8 +310,6 @@ public final class ApkAssets { mFlags = flags; mNativePtr = nativeLoadFdOffsets(format, fd, friendlyName, offset, length, flags, assets); mStringBlock = new StringBlock(nativeGetStringBlock(mNativePtr), true /*useSparse*/); - mRunNativeCleanup = NoImagePreloadHolder.REGISTRY.registerNativeAllocation( - this, mNativePtr); mAssets = assets; } @@ -338,7 +317,6 @@ public final class ApkAssets { mFlags = flags; mNativePtr = nativeLoadEmpty(flags, assets); mStringBlock = null; - mRunNativeCleanup = null; mAssets = assets; } @@ -433,16 +411,22 @@ public final class ApkAssets { return "ApkAssets{path=" + getDebugName() + "}"; } + @Override + protected void finalize() throws Throwable { + close(); + } + /** * Closes this class and the contained {@link #mStringBlock}. */ public void close() { synchronized (this) { - if (mStringBlock != null) { - mStringBlock.close(); - } - if (mRunNativeCleanup != null) { - mRunNativeCleanup.run(); + if (mNativePtr != 0) { + if (mStringBlock != null) { + mStringBlock.close(); + } + nativeDestroy(mNativePtr); + mNativePtr = 0; } } } @@ -457,6 +441,7 @@ public final class ApkAssets { private static native long nativeLoadFdOffsets(@FormatType int format, @NonNull FileDescriptor fd, @NonNull String friendlyName, long offset, long length, @PropertyFlags int flags, @Nullable AssetsProvider asset) throws IOException; + private static native void nativeDestroy(long ptr); private static native @NonNull String nativeGetAssetPath(long ptr); private static native @NonNull String nativeGetDebugName(long ptr); private static native long nativeGetStringBlock(long ptr); @@ -465,5 +450,4 @@ public final class ApkAssets { private static native @Nullable OverlayableInfo nativeGetOverlayableInfo(long ptr, String overlayableName) throws IOException; private static native boolean nativeDefinesOverlayable(long ptr) throws IOException; - private static native final long nativeGetFinalizer(); } diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java index bbde8b103ef3..d7225ccd9ca6 100644 --- a/core/java/android/content/res/CompatibilityInfo.java +++ b/core/java/android/content/res/CompatibilityInfo.java @@ -110,6 +110,7 @@ public class CompatibilityInfo implements Parcelable { public final float applicationInvertedScale; @UnsupportedAppUsage + @Deprecated public CompatibilityInfo(ApplicationInfo appInfo, int screenLayout, int sw, boolean forceCompat) { this(appInfo, screenLayout, sw, forceCompat, 1f); diff --git a/core/java/android/graphics/fonts/FontManager.java b/core/java/android/graphics/fonts/FontManager.java index 429eef95f952..7bf692f1d318 100644 --- a/core/java/android/graphics/fonts/FontManager.java +++ b/core/java/android/graphics/fonts/FontManager.java @@ -25,7 +25,6 @@ import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; import android.content.Context; -import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.text.FontConfig; @@ -205,9 +204,13 @@ public class FontManager { } /** - * Update a system installed font file. + * Update or add system font families. + * + * <p>This method will update existing font families or add new font families. The updated + * font family definitions will be used when creating {@link android.graphics.Typeface} objects + * with using {@link android.graphics.Typeface#create(String, int)} specifying the family name, + * or through XML resources. * - * <p> * To protect devices, system font updater relies on a Linux Kernel feature called fs-verity. * If the device does not support fs-verity, {@link #RESULT_ERROR_FONT_UPDATER_DISABLED} will be * returned. @@ -233,69 +236,6 @@ public class FontManager { * {@link #RESULT_ERROR_VERSION_MISMATCH} will be returned. Get the latest font configuration by * calling {@link #getFontConfig()} and call this method again with the latest config version. * - * @param request A {@link FontFileUpdateRequest} to execute. - * @param baseVersion A base config version to be updated. You can get the latest config version - * by {@link FontConfig#getConfigVersion()} via {@link #getFontConfig()}. If - * the system has a newer config version, the update will fail with - * {@link #RESULT_ERROR_VERSION_MISMATCH}. - * @return A result code. - * - * @see FontConfig#getConfigVersion() - * @see #getFontConfig() - * @see #RESULT_SUCCESS - * @see #RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE - * @see #RESULT_ERROR_VERIFICATION_FAILURE - * @see #RESULT_ERROR_VERSION_MISMATCH - * @see #RESULT_ERROR_INVALID_FONT_FILE - * @see #RESULT_ERROR_INVALID_FONT_NAME - * @see #RESULT_ERROR_DOWNGRADING - * @see #RESULT_ERROR_FAILED_UPDATE_CONFIG - * @see #RESULT_ERROR_FONT_UPDATER_DISABLED - */ - @RequiresPermission(Manifest.permission.UPDATE_FONTS) public @ResultCode int updateFontFile( - @NonNull FontFileUpdateRequest request, @IntRange(from = 0) int baseVersion) { - try { - return mIFontManager.updateFontFile(new FontUpdateRequest( - request.getParcelFileDescriptor(), request.getSignature()), baseVersion); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * @deprecated Use {@link #updateFontFile(FontFileUpdateRequest, int)} - */ - // TODO: Remove this API before Developer Preview 3. - @Deprecated - @RequiresPermission(Manifest.permission.UPDATE_FONTS) public @ResultCode int updateFontFile( - @NonNull ParcelFileDescriptor pfd, - @NonNull byte[] signature, - @IntRange(from = 0) int baseVersion - ) { - return updateFontFile(new FontFileUpdateRequest(pfd, signature), baseVersion); - } - - - /** - * Update or add system wide font families. - * - * <p>This method will update existing font families or add new font families. The updated - * font family definitions will be used when creating {@link android.graphics.Typeface} objects - * with using {@link android.graphics.Typeface#create(String, int)} specifying the family name, - * or through XML resources. Note that system fallback fonts cannot be modified by this method. - * Apps must use {@link android.graphics.Typeface.CustomFallbackBuilder} to use custom fallback - * fonts. - * - * <p>Font files can be updated by including {@link FontFileUpdateRequest} to {@code request} - * via {@link FontFamilyUpdateRequest.Builder#addFontFileUpdateRequest(FontFileUpdateRequest)}. - * The same constraints as {@link #updateFontFile} will apply when updating font files. - * - * <p>The caller must specify the base config version for keeping the font configuration - * consistent. If the font configuration is updated for some reason between the time you get - * a configuration with {@link #getFontConfig()} and the time when you call this method, - * {@link #RESULT_ERROR_VERSION_MISMATCH} will be returned. Get the latest font configuration by - * calling {@link #getFontConfig()} and call this method again with the latest config version. - * * @param request A {@link FontFamilyUpdateRequest} to execute. * @param baseVersion A base config version to be updated. You can get the latest config version * by {@link FontConfig#getConfigVersion()} via {@link #getFontConfig()}. If diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index 16ab900dee06..07ebbaff67ea 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.PublicKey; 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 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri */ @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 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri 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 ac6ba0a4ac58..af48b71f9962 100644 --- a/core/java/android/hardware/camera2/CameraDevice.java +++ b/core/java/android/hardware/camera2/CameraDevice.java @@ -770,6 +770,8 @@ public abstract class CameraDevice implements AutoCloseable { * 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 @@ public abstract class CameraDevice implements AutoCloseable { * 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 @@ public abstract class CameraDevice implements AutoCloseable { * </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 3e0e3f62574f..a3c6f2f1eafd 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.CameraDeviceImpl; 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 android.view.Display; 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 @@ public final class CameraManager { } /** + * 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 @@ public final class CameraManager { } 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 000000000000..c592f19bc45c --- /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 da65f71ce02c..df8eeccbe800 100644 --- a/core/java/android/hardware/camera2/TotalCaptureResult.java +++ b/core/java/android/hardware/camera2/TotalCaptureResult.java @@ -61,8 +61,8 @@ public final class TotalCaptureResult extends CaptureResult { 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 @@ public final class TotalCaptureResult extends CaptureResult { 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 @@ public final class TotalCaptureResult extends CaptureResult { mPartialResults = new ArrayList<>(); mSessionId = CameraCaptureSession.SESSION_ID_NONE; - mPhysicalCaptureResults = new HashMap<String, CaptureResult>(); + mPhysicalCaptureResults = new HashMap<String, TotalCaptureResult>(); } /** @@ -146,8 +147,37 @@ public final class TotalCaptureResult extends CaptureResult { * 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 ce3c81a2bfd6..4defd23231b8 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.ICameraOfflineSession; 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 @@ public class CameraDeviceImpl extends CameraDevice } 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 @@ public class CameraDeviceImpl extends CameraDevice } 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 e9bae0b621ce..0cdf744ecd68 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.Face; 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.StreamConfiguration; 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.io.IOException; 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 @@ public class CameraMetadataNative implements Parcelable { 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 @@ public class CameraMetadataNative implements Parcelable { 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 @@ public class CameraMetadataNative implements Parcelable { 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 @@ public class CameraMetadataNative implements Parcelable { mCameraId = other.mCameraId; mHasMandatoryConcurrentStreams = other.mHasMandatoryConcurrentStreams; mDisplaySize = other.mDisplaySize; + mMultiResolutionStreamConfigurationMap = other.mMultiResolutionStreamConfigurationMap; updateNativeAllocation(); other.updateNativeAllocation(); } @@ -1980,6 +2023,39 @@ public class CameraMetadataNative implements Parcelable { 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 ba4395f70214..b6b1968bfcdd 100644 --- a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java +++ b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java @@ -140,9 +140,10 @@ public class ICameraDeviceUserWrapper { } } - 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 0a50f974aca8..d63683feed9b 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 @@ public final class InputConfiguration { 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 @@ public final class InputConfiguration { 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 @@ public final class InputConfiguration { } /** + * 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 @@ public final class InputConfiguration { if (otherInputConfig.getWidth() == mWidth && otherInputConfig.getHeight() == mHeight && - otherInputConfig.getFormat() == mFormat) { + otherInputConfig.getFormat() == mFormat && + otherInputConfig.isMultiResolution() == mIsMultiResolution) { return true; } return false; @@ -111,19 +179,21 @@ public final class InputConfiguration { */ @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 776d155e5b3e..8a0172ee8018 100644 --- a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java +++ b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java @@ -1297,19 +1297,6 @@ public final class MandatoryStreamCombination { } /** - * 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 final class MandatoryStreamCombination { 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 000000000000..1b368fb8c010 --- /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 000000000000..aa1d1d4aaa18 --- /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 a20a1bf194ea..e31bd601fc03 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.Nullable; 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.util.Size; 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 @@ import java.util.Objects; * {@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 @@ import java.util.Objects; * 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 @@ public final class OutputConfiguration implements Parcelable { } /** + * 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 @@ public final class OutputConfiguration implements Parcelable { 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 @@ public final class OutputConfiguration implements Parcelable { mIsDeferredConfig = true; mIsShared = false; mPhysicalCameraId = null; + mIsMultiResolution = false; } /** @@ -355,8 +435,18 @@ public final class OutputConfiguration implements Parcelable { * <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 @@ public final class OutputConfiguration implements Parcelable { * 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 @@ public final class OutputConfiguration implements Parcelable { * 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 @@ public final class OutputConfiguration implements Parcelable { this.mIsDeferredConfig = other.mIsDeferredConfig; this.mIsShared = other.mIsShared; this.mPhysicalCameraId = other.mPhysicalCameraId; + this.mIsMultiResolution = other.mIsMultiResolution; } /** @@ -543,6 +641,7 @@ public final class OutputConfiguration implements Parcelable { 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 @@ public final class OutputConfiguration implements Parcelable { mConfiguredGenerationId = 0; } mPhysicalCameraId = physicalCameraId; + mIsMultiResolution = isMultiResolutionOutput; } /** @@ -665,6 +765,7 @@ public final class OutputConfiguration implements Parcelable { dest.writeInt(mIsShared ? 1 : 0); dest.writeTypedList(mSurfaces); dest.writeString(mPhysicalCameraId); + dest.writeInt(mIsMultiResolution ? 1 : 0); } /** @@ -694,7 +795,8 @@ public final class OutputConfiguration implements Parcelable { 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 @@ public final class OutputConfiguration implements Parcelable { 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 @@ public final class OutputConfiguration implements Parcelable { 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 8fc919f142a2..ea6b92d4f33e 100644 --- a/core/java/android/hardware/camera2/params/SessionConfiguration.java +++ b/core/java/android/hardware/camera2/params/SessionConfiguration.java @@ -130,11 +130,13 @@ public final class SessionConfiguration implements Parcelable { 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 @@ public final class SessionConfiguration implements Parcelable { 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 10a814acd70b..a25ae6041d77 100644 --- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java +++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java @@ -1575,7 +1575,7 @@ public final class StreamConfigurationMap { 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 @@ public final class StreamConfigurationMap { 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 @@ public final class StreamConfigurationMap { 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/devicestate/DeviceStateManagerGlobal.java b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java index 1b37fb9fdad3..904a54b00fa3 100644 --- a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java +++ b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java @@ -179,8 +179,6 @@ public final class DeviceStateManagerGlobal { @VisibleForTesting(visibility = Visibility.PACKAGE) public void registerDeviceStateCallback(@NonNull DeviceStateCallback callback, @NonNull Executor executor) { - DeviceStateCallbackWrapper wrapper; - DeviceStateInfo currentInfo; synchronized (mLock) { int index = findCallbackLocked(callback); if (index != -1) { @@ -189,25 +187,22 @@ public final class DeviceStateManagerGlobal { } registerCallbackIfNeededLocked(); - if (mLastReceivedInfo == null) { - // Initialize the last received info with the current info if this is the first - // callback being registered. - try { - mLastReceivedInfo = mDeviceStateManager.getDeviceStateInfo(); - } catch (RemoteException ex) { - throw ex.rethrowFromSystemServer(); - } - } - currentInfo = new DeviceStateInfo(mLastReceivedInfo); - - wrapper = new DeviceStateCallbackWrapper(callback, executor); + // Add the callback wrapper to the mCallbacks array after registering the callback as + // the callback could be triggered immediately if the mDeviceStateManager IBinder is in + // the same process as this instance. + DeviceStateCallbackWrapper wrapper = new DeviceStateCallbackWrapper(callback, executor); mCallbacks.add(wrapper); - } - wrapper.notifySupportedStatesChanged(currentInfo.supportedStates); - wrapper.notifyBaseStateChanged(currentInfo.baseState); - wrapper.notifyStateChanged(currentInfo.currentState); + if (mLastReceivedInfo != null) { + // Copy the array to prevent the callback from modifying the internal state. + final int[] supportedStates = Arrays.copyOf(mLastReceivedInfo.supportedStates, + mLastReceivedInfo.supportedStates.length); + wrapper.notifySupportedStatesChanged(supportedStates); + wrapper.notifyBaseStateChanged(mLastReceivedInfo.baseState); + wrapper.notifyStateChanged(mLastReceivedInfo.currentState); + } + } } /** @@ -267,7 +262,7 @@ public final class DeviceStateManagerGlobal { callbacks = new ArrayList<>(mCallbacks); } - final int diff = oldInfo == null ? 1 : info.diff(oldInfo); + final int diff = oldInfo == null ? ~0 : info.diff(oldInfo); if ((diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES) > 0) { for (int i = 0; i < callbacks.size(); i++) { // Copy the array to prevent callbacks from modifying the internal state. diff --git a/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl b/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl index 593be867fe28..efb9888fb6ba 100644 --- a/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl +++ b/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl @@ -21,7 +21,8 @@ import android.hardware.devicestate.DeviceStateInfo; /** @hide */ interface IDeviceStateManagerCallback { /** - * Called in response to a change in {@link DeviceStateInfo}. + * Called in response to a change in {@link DeviceStateInfo}. Guaranteed to be called once + * after successful registration of the callback with the initial value. * * @param info the new device state info. * diff --git a/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl b/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl index 81c7d894ee09..d2cb5bfe6910 100644 --- a/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl +++ b/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl @@ -15,6 +15,8 @@ */ package android.hardware.fingerprint; +import android.hardware.fingerprint.IUdfpsOverlayControllerCallback; + /** * Interface for interacting with the under-display fingerprint sensor (UDFPS) overlay. * @hide @@ -28,7 +30,7 @@ oneway interface IUdfpsOverlayController { const int REASON_AUTH_FPM_OTHER = 5; // Other FingerprintManager usage // Shows the overlay. - void showUdfpsOverlay(int sensorId, int reason); + void showUdfpsOverlay(int sensorId, int reason, IUdfpsOverlayControllerCallback callback); // Hides the overlay. void hideUdfpsOverlay(int sensorId); diff --git a/core/java/android/hardware/fingerprint/IUdfpsOverlayControllerCallback.aidl b/core/java/android/hardware/fingerprint/IUdfpsOverlayControllerCallback.aidl new file mode 100644 index 000000000000..51ada29f828f --- /dev/null +++ b/core/java/android/hardware/fingerprint/IUdfpsOverlayControllerCallback.aidl @@ -0,0 +1,24 @@ +/* + * 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.fingerprint; + +/** + * @hide + */ +oneway interface IUdfpsOverlayControllerCallback { + // Notify system_server if the user cancels a UDFPS-related operation (enroll, auth) + void onUserCanceled(); +} diff --git a/core/java/android/hardware/lights/LightsRequest.java b/core/java/android/hardware/lights/LightsRequest.java index 2626a461aaf5..6fb0eb5df59a 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 @@ public final class LightsRequest { } /** + * 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 b016ed67c4d9..9bf791ba33e0 100644 --- a/core/java/android/net/INetworkPolicyManager.aidl +++ b/core/java/android/net/INetworkPolicyManager.aidl @@ -19,8 +19,6 @@ package android.net; 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 @@ interface INetworkPolicyManager { 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 268002f1dd52..8f1e2defd215 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -232,10 +232,11 @@ public final class IpSecAlgorithm implements Parcelable { 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 b3d8d4e614da..0d26c2de8698 100644 --- a/core/java/android/net/NetworkStateSnapshot.java +++ b/core/java/android/net/NetworkStateSnapshot.java @@ -24,6 +24,8 @@ import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; +import com.android.net.module.util.NetworkIdentityUtils; + import java.util.Objects; /** @@ -124,4 +126,15 @@ public final class NetworkStateSnapshot implements Parcelable { 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 d91cef592d10..236ae8bb11b2 100644 --- a/core/java/android/net/vcn/IVcnStatusCallback.aidl +++ b/core/java/android/net/vcn/IVcnStatusCallback.aidl @@ -18,7 +18,6 @@ package android.net.vcn; /** @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 f8ae492016f0..62de8216ce54 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 eb8c251fec78..8ebf757760c3 100644 --- a/core/java/android/net/vcn/VcnManager.java +++ b/core/java/android/net/vcn/VcnManager.java @@ -359,8 +359,6 @@ public class VcnManager { /** * 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 @@ public class VcnManager { * * <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 @@ public class VcnManager { * <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 @@ public class VcnManager { * <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 @@ public class VcnManager { /** * 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 @@ public class VcnManager { * 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 @@ public class VcnManager { * <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 class VcnManager { 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 @@ public class VcnManager { * <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 @@ public class VcnManager { * @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 @@ public class VcnManager { * 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 @@ public class VcnManager { } @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 000000000000..b6036b4a6fd1 --- /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 000000000000..ce5ec75f01a2 --- /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 000000000000..853a52da766a --- /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 000000000000..6acb34ebb78e --- /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 000000000000..1459671f4136 --- /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 000000000000..0c9ee8432798 --- /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 000000000000..e62acac14bd7 --- /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/BatteryStats.java b/core/java/android/os/BatteryStats.java index 6901df7508ab..66f7bd9d8dee 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -986,26 +986,26 @@ public abstract class BatteryStats implements Parcelable { public abstract void getDeferredJobsLineLocked(StringBuilder sb, int which); /** - * Returns the measured energy in microjoules that the display consumed while the screen - * was on and uid active. - * Will return {@link #ENERGY_DATA_UNAVAILABLE} if data is unavailable + * Returns the battery consumption (in microcoulombs) of the screen while on and uid active, + * derived from on device power measurement data. + * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable. * * {@hide} */ - public abstract long getScreenOnEnergy(); + public abstract long getScreenOnMeasuredBatteryConsumptionUC(); /** - * Returns the energies used by this uid for each + * Returns the battery consumption (in microcoulombs) used by this uid for each * {@link android.hardware.power.stats.EnergyConsumer.ordinal} of (custom) energy consumer * type {@link android.hardware.power.stats.EnergyConsumerType#OTHER}). * - * @return energies (in microjoules) used since boot for each (custom) energy consumer of - * type OTHER, indexed by their ordinal. Returns null if no energy reporting is - * supported. + * @return charge (in microcoulombs) consumed since last reset for each (custom) energy + * consumer of type OTHER, indexed by their ordinal. Returns null if no energy + * reporting is supported. * * {@hide} */ - public abstract @Nullable long[] getCustomMeasuredEnergiesMicroJoules(); + public abstract @Nullable long[] getCustomConsumerMeasuredBatteryConsumptionUC(); public static abstract class Sensor { @@ -2496,40 +2496,41 @@ public abstract class BatteryStats implements Parcelable { }; /** - * Returned value if energy data is unavailable + * Returned value if power data is unavailable * * {@hide} */ - public static final long ENERGY_DATA_UNAVAILABLE = -1; + public static final long POWER_DATA_UNAVAILABLE = -1; /** - * Returns the energy in microjoules that the screen consumed while on. - * Will return {@link #ENERGY_DATA_UNAVAILABLE} if data is unavailable + * Returns the battery consumption (in microcoulombs) of the screen while on, derived from on + * device power measurement data. + * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable. * * {@hide} */ - public abstract long getScreenOnEnergy(); + public abstract long getScreenOnMeasuredBatteryConsumptionUC(); /** - * Returns the energy in microjoules that the screen consumed while in doze - * Will return {@link #ENERGY_DATA_UNAVAILABLE} if data is unavailable + * Returns the battery consumption (in microcoulombs) of the screen in doze, derived from on + * device power measurement data. + * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable. * * {@hide} */ - public abstract long getScreenDozeEnergy(); + public abstract long getScreenDozeMeasuredBatteryConsumptionUC(); /** - * Returns the energies used for each + * Returns the battery consumption (in microcoulombs) that each * {@link android.hardware.power.stats.EnergyConsumer.ordinal} of (custom) energy consumer - * type {@link android.hardware.power.stats.EnergyConsumerType#OTHER}). + * type {@link android.hardware.power.stats.EnergyConsumerType#OTHER}) consumed. * - * @return energies (in microjoules) used since boot for each (custom) energy consumer of - * type OTHER, indexed by their ordinal. Returns null if no energy reporting is - * supported. + * @return charge (in microcoulombs) used by each (custom) energy consumer of type OTHER, + * indexed by their ordinal. Returns null if no energy reporting is supported. * * {@hide} */ - public abstract @Nullable long[] getCustomMeasuredEnergiesMicroJoules(); + public abstract @Nullable long[] getCustomConsumerMeasuredBatteryConsumptionUC(); public static final BitDescription[] HISTORY_STATE_DESCRIPTIONS = new BitDescription[] { new BitDescription(HistoryItem.STATE_CPU_RUNNING_FLAG, "running", "r"), diff --git a/core/java/android/os/BatteryStatsManager.java b/core/java/android/os/BatteryStatsManager.java index 04e529e80bff..1905d708d6d3 100644 --- a/core/java/android/os/BatteryStatsManager.java +++ b/core/java/android/os/BatteryStatsManager.java @@ -24,6 +24,7 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; +import android.net.NetworkStack; import android.os.connectivity.CellularBatteryStats; import android.os.connectivity.WifiBatteryStats; import android.telephony.DataConnectionRealTimeInfo; @@ -458,10 +459,31 @@ public final class BatteryStatsManager { } } + /** + * Notifies the battery stats of a new interface, and the transport types of the network that + * includes that interface. + * + * @param iface The interface of the network. + * @param transportTypes The transport type of the network {@link Transport}. + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK}) + public void reportNetworkInterfaceForTransports(@NonNull String iface, + @NonNull int[] transportTypes) throws RuntimeException { + try { + mBatteryStats.noteNetworkInterfaceForTransports(iface, transportTypes); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + private static int getDataConnectionPowerState(boolean isActive) { // TODO: DataConnectionRealTimeInfo is under telephony package but the constants are used - // for both Wifi and mobile. It would make more sense to separate the constants to a generic - // class or move it to generic package. + // for both Wifi and mobile. It would make more sense to separate the constants to a + // generic class or move it to generic package. return isActive ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW; } diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java index de7b88575e98..f12eb8853c55 100644 --- a/core/java/android/os/BatteryUsageStats.java +++ b/core/java/android/os/BatteryUsageStats.java @@ -37,6 +37,8 @@ public final class BatteryUsageStats implements Parcelable { 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 @@ public final class BatteryUsageStats implements Parcelable { mDischargedPowerUpperBound = builder.mDischargedPowerUpperBoundMah; mHistoryBuffer = builder.mHistoryBuffer; mHistoryTagPool = builder.mHistoryTagPool; + mBatteryTimeRemainingMs = builder.mBatteryTimeRemainingMs; + mChargeTimeRemainingMs = builder.mChargeTimeRemainingMs; double totalPower = 0; @@ -110,6 +114,25 @@ public final class BatteryUsageStats implements Parcelable { } /** + * 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 @@ public final class BatteryUsageStats implements Parcelable { 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 @@ public final class BatteryUsageStats implements Parcelable { 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 @@ public final class BatteryUsageStats implements Parcelable { 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 @@ public final class BatteryUsageStats implements Parcelable { } /** + * 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 a5b0e8d149ef..83f78a56487a 100755 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -1117,6 +1117,18 @@ public class Build { } /** + * A multiplier for various timeouts on the system. + * + * The intent is that products targeting software emulators that are orders of magnitude slower + * than real hardware may set this to a large number. On real devices and hardware-accelerated + * virtualized devices this should not be set. + * + * @hide + */ + public static final int HW_TIMEOUT_MULTIPLIER = + SystemProperties.getInt("ro.hw_timeout_multiplier", 1); + + /** * True if Treble is enabled and required for this device. * * @hide diff --git a/core/java/android/os/BytesMatcher.java b/core/java/android/os/BytesMatcher.java new file mode 100644 index 000000000000..8537f47eb575 --- /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 8f6161329e53..ae7d94cbad79 100644 --- a/core/java/android/os/IPowerManager.aidl +++ b/core/java/android/os/IPowerManager.aidl @@ -42,8 +42,7 @@ interface IPowerManager 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/InputConstants.java b/core/java/android/os/InputConstants.java new file mode 100644 index 000000000000..c8fa0651c228 --- /dev/null +++ b/core/java/android/os/InputConstants.java @@ -0,0 +1,24 @@ +/* + * 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; + +/** @hide */ +public class InputConstants { + public static final int DEFAULT_DISPATCHING_TIMEOUT_MILLIS = + IInputConstants.UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS + * Build.HW_TIMEOUT_MULTIPLIER; +} diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index e5163d83de69..786a7d08047e 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -1277,7 +1277,7 @@ public final class PowerManager { }) 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/Process.java b/core/java/android/os/Process.java index 136dc388022f..e75e224d9a6f 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -397,6 +397,12 @@ public class Process { public static final int THREAD_PRIORITY_VIDEO = -10; /** + * Priority we boost main thread and RT of top app to. + * @hide + */ + public static final int THREAD_PRIORITY_TOP_APP_BOOST = -10; + + /** * Standard priority of audio threads. Applications can not normally * change to this priority. * Use with {@link #setThreadPriority(int)} and diff --git a/core/java/android/os/ShellCallback.java b/core/java/android/os/ShellCallback.java index 632f6c8694ce..be9fb89649d0 100644 --- a/core/java/android/os/ShellCallback.java +++ b/core/java/android/os/ShellCallback.java @@ -102,6 +102,10 @@ public class ShellCallback implements Parcelable { } } + public IBinder getShellCallbackBinder() { + return mShellCallback.asBinder(); + } + ShellCallback(Parcel in) { mLocal = false; mShellCallback = IShellCallback.Stub.asInterface(in.readStrongBinder()); diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java index 0587610630a6..03e5f1d59b86 100644 --- a/core/java/android/os/VibrationEffect.java +++ b/core/java/android/os/VibrationEffect.java @@ -503,6 +503,20 @@ public abstract class VibrationEffect implements Parcelable { } /** @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 @@ public abstract class VibrationEffect implements Parcelable { @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 07272e756e77..50d2de3da965 100644 --- a/core/java/android/os/VibratorInfo.java +++ b/core/java/android/os/VibratorInfo.java @@ -18,6 +18,7 @@ package android.os; 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 @@ import java.util.Objects; * @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 @@ public final class VibratorInfo implements Parcelable { 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 @@ public final class VibratorInfo implements Parcelable { * @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 @@ public final class VibratorInfo implements Parcelable { * @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,12 +158,27 @@ public final class VibratorInfo implements Parcelable { private String[] getCapabilitiesNames() { List<String> names = new ArrayList<>(); - if (hasCapability(CAPABILITY_AMPLITUDE_CONTROL)) { - names.add("AMPLITUDE_CONTROL"); + if (hasCapability(IVibrator.CAP_ON_CALLBACK)) { + names.add("ON_CALLBACK"); + } + if (hasCapability(IVibrator.CAP_PERFORM_CALLBACK)) { + names.add("PERFORM_CALLBACK"); } - if (hasCapability(CAPABILITY_COMPOSE_EFFECTS)) { + 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(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 9ffc5aa0022c..bf2898137967 100644 --- a/core/java/android/os/ZygoteProcess.java +++ b/core/java/android/os/ZygoteProcess.java @@ -333,7 +333,7 @@ public class ZygoteProcess { * 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 @@ public class ZygoteProcess { @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 @@ public class ZygoteProcess { 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 @@ public class ZygoteProcess { * @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 @@ public class ZygoteProcess { @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 @@ public class ZygoteProcess { } 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 @@ public class ZygoteProcess { 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 87dced8a3437..dc6f63a94685 100644 --- a/core/java/android/os/incremental/IncrementalManager.java +++ b/core/java/android/os/incremental/IncrementalManager.java @@ -58,6 +58,8 @@ public final class IncrementalManager { 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/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java index 084b18eb2999..913b827332bf 100644 --- a/core/java/android/permission/PermissionControllerManager.java +++ b/core/java/android/permission/PermissionControllerManager.java @@ -668,7 +668,7 @@ public final class PermissionControllerManager { 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/provider/Settings.java b/core/java/android/provider/Settings.java index 85cef84d8d30..4dfbb6fa2d05 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -825,6 +825,13 @@ public final class Settings { "android.settings.DISPLAY_SETTINGS"; /** + * Activity Action: Show Auto Rotate configuration settings. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_AUTO_ROTATE_SETTINGS = + "android.settings.AUTO_ROTATE_SETTINGS"; + + /** * Activity Action: Show settings to allow configuration of Night display. * <p> * In some cases, a matching Activity may not exist, so ensure you diff --git a/core/java/android/service/autofill/AutofillServiceInfo.java b/core/java/android/service/autofill/AutofillServiceInfo.java index fbc25a6aaf74..4c8ee598f512 100644 --- a/core/java/android/service/autofill/AutofillServiceInfo.java +++ b/core/java/android/service/autofill/AutofillServiceInfo.java @@ -18,10 +18,13 @@ package android.service.autofill; 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 org.xmlpull.v1.XmlPullParserException; 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 @@ public final class AutofillServiceInfo { @Nullable private final String mSettingsActivity; + @Nullable + private final String mPasswordsActivity; @Nullable private final ArrayMap<String, Long> mCompatibilityPackages; @@ -113,12 +120,14 @@ public final class AutofillServiceInfo { 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 @@ public final class AutofillServiceInfo { 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 @@ public final class AutofillServiceInfo { } mSettingsActivity = settingsActivity; + mPasswordsActivity = passwordsActivity; mCompatibilityPackages = compatibilityPackages; mInlineSuggestionsEnabled = inlineSuggestionsEnabled; } @@ -221,6 +233,7 @@ public final class AutofillServiceInfo { return compatibilityPackages; } + @NonNull public ServiceInfo getServiceInfo() { return mServiceInfo; } @@ -230,6 +243,12 @@ public final class AutofillServiceInfo { return mSettingsActivity; } + @Nullable + public String getPasswordsActivity() { + return mPasswordsActivity; + } + + @Nullable public ArrayMap<String, Long> getCompatibilityPackages() { return mCompatibilityPackages; } @@ -238,12 +257,37 @@ public final class AutofillServiceInfo { 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 final class AutofillServiceInfo { 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/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java index 62becc507404..af846b62ae2c 100644 --- a/core/java/android/service/autofill/FillRequest.java +++ b/core/java/android/service/autofill/FillRequest.java @@ -96,6 +96,8 @@ public final class FillRequest implements Parcelable { */ public static final @RequestFlags int FLAG_VIEW_NOT_FOCUSED = 0x10; + // The flag value 0x20 has been defined in AutofillManager. + /** @hide */ public static final int INVALID_REQUEST_ID = Integer.MIN_VALUE; diff --git a/core/java/android/service/storage/ExternalStorageService.java b/core/java/android/service/storage/ExternalStorageService.java index bbe184bd1a8c..da1f457df5d9 100644 --- a/core/java/android/service/storage/ExternalStorageService.java +++ b/core/java/android/service/storage/ExternalStorageService.java @@ -173,8 +173,13 @@ public abstract class ExternalStorageService extends Service { * Called when {@code packageName} is about to ANR. The {@link ExternalStorageService} can * show a progress dialog for the {@code reason}. * + * @param packageName the package name of the ANR'ing app + * @param uid the uid of the ANR'ing app + * @param tid the tid of the ANR'ing app + * @param reason the reason the app is ANR'ing */ - public void onAnrDelayStarted(@NonNull String packageName, int uid, int tid, int reason) { + public void onAnrDelayStarted(@NonNull String packageName, int uid, int tid, + @StorageManager.AppIoBlockedReason int reason) { throw new UnsupportedOperationException("onAnrDelayStarted not implemented"); } diff --git a/core/java/android/service/translation/TEST_MAPPING b/core/java/android/service/translation/TEST_MAPPING new file mode 100644 index 000000000000..37b6fe7396b8 --- /dev/null +++ b/core/java/android/service/translation/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "imports": [ + { + "path": "frameworks/base/services/translation/java/com/android/server/translation" + } + ] +} diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java index e7ceada6180a..e37921ec03cc 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.Handler; 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 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; @@ -71,49 +62,15 @@ import java.util.concurrent.Executor; * 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 @@ public class PhoneStateListener { * * @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 @@ public class PhoneStateListener { * {@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 @@ public class PhoneStateListener { * 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 @@ public class PhoneStateListener { * {@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 @@ public class PhoneStateListener { * 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 @@ public class PhoneStateListener { * {@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 @@ public class PhoneStateListener { * 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 @@ public class PhoneStateListener { * 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 @@ public class PhoneStateListener { * 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 @@ public class PhoneStateListener { * @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 @@ public class PhoneStateListener { * 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 @@ public class PhoneStateListener { * (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 @@ public class PhoneStateListener { * (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 @@ public class PhoneStateListener { * * @see #onServiceStateChanged(ServiceState) * @hide - * @deprecated Use {@link SrvccStateChangedListener} instead. + * @deprecated Use {@link TelephonyCallback.SrvccStateListener} instead. */ @Deprecated @SystemApi @@ -328,7 +286,7 @@ public class PhoneStateListener { * * @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 @@ public class PhoneStateListener { * * @see #onVoiceActivationStateChanged * @hide - * @deprecated Use {@link VoiceActivationStateChangedListener} instead. + * @deprecated Use {@link TelephonyCallback.VoiceActivationStateListener} instead. */ @Deprecated @SystemApi @@ -369,7 +327,7 @@ public class PhoneStateListener { * * @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 @@ public class PhoneStateListener { * 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 @@ public class PhoneStateListener { * {@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 @@ public class PhoneStateListener { * * @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 @@ public class PhoneStateListener { * 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 @@ public class PhoneStateListener { * * @see #onRadioPowerStateChanged * @hide - * @deprecated Use {@link RadioPowerStateChangedListener} instead. + * @deprecated Use {@link TelephonyCallback.RadioPowerStateListener} instead. */ @Deprecated @SystemApi @@ -436,7 +394,7 @@ public class PhoneStateListener { * <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 @@ public class PhoneStateListener { * 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 @@ public class PhoneStateListener { * * @see #onCallAttributesChanged * @hide - * @deprecated Use {@link CallAttributesChangedListener} instead. + * @deprecated Use {@link TelephonyCallback.CallAttributesListener} instead. */ @Deprecated @SystemApi @@ -480,7 +438,7 @@ public class PhoneStateListener { * (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 @@ public class PhoneStateListener { * * @see #onOutgoingEmergencyCall * @hide - * @deprecated Use {@link OutgoingEmergencyCallListener} instead. + * @deprecated Use {@link TelephonyCallback.OutgoingEmergencyCallListener} instead. */ @Deprecated @SystemApi @@ -503,7 +461,7 @@ public class PhoneStateListener { * * @see #onOutgoingEmergencySms * @hide - * @deprecated Use {@link OutgoingEmergencySmsListener} instead. + * @deprecated Use {@link TelephonyCallback.OutgoingEmergencySmsListener} instead. */ @Deprecated @SystemApi @@ -524,7 +482,7 @@ public class PhoneStateListener { * 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 @@ public class PhoneStateListener { * 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 @@ public class PhoneStateListener { /** * @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 @@ public class PhoneStateListener { */ @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 @@ public class PhoneStateListener { * 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 @@ public class PhoneStateListener { * @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 @@ public class PhoneStateListener { * {@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 @@ public class PhoneStateListener { * {@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 @@ public class PhoneStateListener { * {@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 @@ public class PhoneStateListener { * {@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 @@ public class PhoneStateListener { * @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 @@ public class PhoneStateListener { * @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 @@ public class PhoneStateListener { * {@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 @@ public class PhoneStateListener { * {@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 @@ public class PhoneStateListener { * {@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 @@ public class PhoneStateListener { * * @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 @@ public class PhoneStateListener { * {@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 @@ public class PhoneStateListener { * (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 @@ public class PhoneStateListener { * {@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 @@ public class PhoneStateListener { * {@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 @@ public class PhoneStateListener { * * @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 @@ public class PhoneStateListener { * * @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 @@ public class PhoneStateListener { * {@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 @@ public class PhoneStateListener { * 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 @@ public class PhoneStateListener { * {@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 @@ public class PhoneStateListener { * 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 @@ public class PhoneStateListener { * 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 @@ public class PhoneStateListener { * * @deprecated Use {@link #onOutgoingEmergencySms(EmergencyNumber, int)}. * @hide + * @deprecated Use {@link TelephonyCallback.OutgoingEmergencySmsListener} instead. */ @SystemApi @Deprecated @@ -2386,8 +1093,10 @@ public class PhoneStateListener { * @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 @@ public class PhoneStateListener { /** * 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 @@ public class PhoneStateListener { * 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 @@ public class PhoneStateListener { * * @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 @@ public class PhoneStateListener { * @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 @@ public class PhoneStateListener { * 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 @@ public class PhoneStateListener { * * @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 @@ public class PhoneStateListener { * @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 @@ public class PhoneStateListener { * 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 @@ public class PhoneStateListener { * 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 @@ public class PhoneStateListener { Binder.withCleanCallingIdentity( () -> mExecutor.execute(() -> psl.onRegistrationFailed( - cellIdentity, chosenPlmn, domain, causeCode, additionalCauseCode))); + cellIdentity, chosenPlmn, domain, causeCode, additionalCauseCode))); // default implementation empty } @@ -2844,33 +1566,15 @@ public class PhoneStateListener { } 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 000000000000..a2584cae1b9c --- /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 3c355d4b6f45..459c6e94e4ac 100644 --- a/core/java/android/telephony/TelephonyRegistryManager.java +++ b/core/java/android/telephony/TelephonyRegistryManager.java @@ -209,7 +209,7 @@ public class TelephonyRegistryManager { } /** - * 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 @@ public class TelephonyRegistryManager { * @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 class TelephonyRegistryManager { } } - 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 @@ public class TelephonyRegistryManager { 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 2b577d04b18d..4d321079416b 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -49,6 +49,8 @@ public class FeatureFlagUtils { /** @hide */ public static final String SETTINGS_USE_NEW_BACKUP_ELIGIBILITY_RULES = "settings_use_new_backup_eligibility_rules"; + /** @hide */ + public static final String SETTINGS_ENABLE_SECURITY_HUB = "settings_enable_security_hub"; private static final Map<String, String> DEFAULT_FLAGS; @@ -68,10 +70,11 @@ public class FeatureFlagUtils { 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"); + DEFAULT_FLAGS.put(SETTINGS_ENABLE_SECURITY_HUB, "false"); } private static final Set<String> PERSISTENT_FLAGS; diff --git a/core/java/android/util/SizeF.java b/core/java/android/util/SizeF.java index 2edc4a7ff588..c77a02434941 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 @@ import static com.android.internal.util.Preconditions.checkArgumentFinite; * 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 @@ public final class SizeF { 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/Choreographer.java b/core/java/android/view/Choreographer.java index 59299f6b15eb..5c65c659e576 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -744,7 +744,10 @@ public final class Choreographer { } 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/FrameMetricsObserver.java b/core/java/android/view/FrameMetricsObserver.java index 41bc9a742752..35d95be0b57b 100644 --- a/core/java/android/view/FrameMetricsObserver.java +++ b/core/java/android/view/FrameMetricsObserver.java @@ -45,7 +45,8 @@ public class FrameMetricsObserver mWindow = new WeakReference<>(window); mListener = listener; mFrameMetrics = new FrameMetrics(); - mObserver = new HardwareRendererObserver(this, mFrameMetrics.mTimingData, handler); + mObserver = new HardwareRendererObserver(this, mFrameMetrics.mTimingData, handler, + false /*waitForPresentTime*/); } /** diff --git a/core/java/android/view/InputEventAssigner.java b/core/java/android/view/InputEventAssigner.java new file mode 100644 index 000000000000..c159a127f4eb --- /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/InputEventReceiver.java b/core/java/android/view/InputEventReceiver.java index 7d1adc36964b..79d8c14aa0df 100644 --- a/core/java/android/view/InputEventReceiver.java +++ b/core/java/android/view/InputEventReceiver.java @@ -21,6 +21,7 @@ import android.os.Build; import android.os.IBinder; import android.os.Looper; import android.os.MessageQueue; +import android.os.Trace; import android.util.Log; import android.util.SparseIntArray; @@ -198,6 +199,15 @@ public abstract class InputEventReceiver { } /** + * Report the latency information for a specific input event. + */ + public final void reportLatencyInfo(int inputEventId, long gpuCompletedTime, long presentTime) { + Trace.traceBegin(Trace.TRACE_TAG_INPUT, "reportLatencyInfo"); + // TODO(b/169866723) : send this data to InputDispatcher via InputChannel + Trace.traceEnd(Trace.TRACE_TAG_INPUT); + } + + /** * Consumes all pending batched input events. * Must be called on the same Looper thread to which the receiver is attached. * diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index d67439cc9de2..6801c27851a9 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -3589,6 +3589,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { 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 517b0fb8ccd3..20a511a090b5 100644 --- a/core/java/android/view/SurfaceControlFpsListener.java +++ b/core/java/android/view/SurfaceControlFpsListener.java @@ -57,14 +57,14 @@ public abstract class SurfaceControlFpsListener { 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 @@ public abstract class SurfaceControlFpsListener { * * 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 ebef4646b0d9..ab7732b47ca4 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -22188,9 +22188,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * 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 d4aaa611f800..36bf53201e6f 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 @@ import android.graphics.FrameInfo; */ 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 class ViewFrameInfo { 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 class ViewFrameInfo { */ public void reset() { drawStart = 0; - oldestInputEventTime = 0; - newestInputEventTime = 0; + mInputEventId = IInputConstants.INVALID_INPUT_EVENT_ID; flags = 0; } @@ -78,4 +59,12 @@ public class ViewFrameInfo { 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 f8e65bd0d056..9fc415d6401f 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -16,6 +16,7 @@ package android.view; +import static android.os.IInputConstants.INVALID_INPUT_EVENT_ID; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.InputDevice.SOURCE_CLASS_NONE; @@ -105,6 +106,7 @@ import android.graphics.Color; import android.graphics.FrameInfo; import android.graphics.HardwareRenderer; import android.graphics.HardwareRenderer.FrameDrawingCallback; +import android.graphics.HardwareRendererObserver; import android.graphics.Insets; import android.graphics.Matrix; import android.graphics.PixelFormat; @@ -457,6 +459,7 @@ public final class ViewRootImpl implements ViewParent, 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 @@ -1190,6 +1193,14 @@ public final class ViewRootImpl implements ViewParent, } mInputEventReceiver = new WindowInputEventReceiver(inputChannel, Looper.myLooper()); + + if (mAttachInfo.mThreadedRenderer != null) { + InputMetricsListener listener = + new InputMetricsListener(mInputEventReceiver); + mHardwareRendererObserver = new HardwareRendererObserver( + listener, listener.data, mHandler, true /*waitForPresentTime*/); + mAttachInfo.mThreadedRenderer.addObserver(mHardwareRendererObserver); + } } view.assignParent(this); @@ -8352,16 +8363,7 @@ public final class ViewRootImpl implements ViewParent, 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 +8499,11 @@ public final class ViewRootImpl implements ViewParent, 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; } @@ -8572,6 +8579,34 @@ public final class ViewRootImpl implements ViewParent, } WindowInputEventReceiver mInputEventReceiver; + final class InputMetricsListener + implements HardwareRendererObserver.OnFrameMetricsAvailableListener { + public long[] data = new long[FrameMetrics.Index.FRAME_STATS_COUNT]; + + private InputEventReceiver mReceiver; + + InputMetricsListener(InputEventReceiver receiver) { + mReceiver = receiver; + } + + @Override + public void onFrameMetricsAvailable(int dropCountSinceLastInvocation) { + final int inputEventId = (int) data[FrameMetrics.Index.INPUT_EVENT_ID]; + if (inputEventId == INVALID_INPUT_EVENT_ID) { + return; + } + final long presentTime = data[FrameMetrics.Index.DISPLAY_PRESENT_TIME]; + if (presentTime <= 0) { + // Present time is not available for this frame. If the present time is not + // available, we cannot compute end-to-end input latency metrics. + return; + } + final long gpuCompletedTime = data[FrameMetrics.Index.GPU_COMPLETED]; + mReceiver.reportLatencyInfo(inputEventId, gpuCompletedTime, presentTime); + } + } + HardwareRendererObserver mHardwareRendererObserver; + final class ConsumeBatchedInputRunnable implements Runnable { @Override public void run() { diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 1819da4a86a0..7338c7d9a581 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -613,6 +613,10 @@ public interface WindowManager extends ViewManager { * 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 @@ public interface WindowManager extends ViewManager { /** * 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 @@ -3435,7 +3440,7 @@ public interface WindowManager extends ViewManager { /** * Specifies that the window should be considered a trusted system overlay. Trusted system * overlays are ignored when considering whether windows are obscured during input - * dispatch. Requires the {@link android.Manifest.permission.INTERNAL_SYSTEM_WINDOW} + * dispatch. Requires the {@link android.Manifest.permission#INTERNAL_SYSTEM_WINDOW} * permission. * * {@see android.view.MotionEvent#FLAG_WINDOW_IS_OBSCURED} @@ -3467,7 +3472,7 @@ public interface WindowManager extends ViewManager { * @see LayoutParams#setSystemApplicationOverlay(boolean) * * <p>Note: the owner of the window must hold - * {@link android.Manifest.permission.SYSTEM_APPLICATION_OVERLAY} for this to have any + * {@link android.Manifest.permission#SYSTEM_APPLICATION_OVERLAY} for this to have any * effect. * @hide */ diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index 7cc2db1c0dab..72d403e1f867 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -149,8 +149,15 @@ public class WindowlessWindowManager implements IWindowSession { 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 @@ public class WindowlessWindowManager implements IWindowSession { 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/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 4f0c568989de..b0b9d244f0d8 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -25,6 +25,7 @@ import static android.view.autofill.Helper.sVerbose; import static android.view.autofill.Helper.toList; import android.accessibilityservice.AccessibilityServiceInfo; +import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -45,16 +46,21 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.graphics.Rect; import android.metrics.LogMaker; +import android.os.Binder; import android.os.Build; import android.os.Bundle; +import android.os.CancellationSignal; import android.os.Handler; import android.os.IBinder; +import android.os.ICancellationSignal; import android.os.Looper; import android.os.Parcelable; import android.os.RemoteException; import android.os.SystemClock; import android.service.autofill.AutofillService; +import android.service.autofill.FillCallback; import android.service.autofill.FillEventHistory; +import android.service.autofill.IFillCallback; import android.service.autofill.UserData; import android.text.TextUtils; import android.util.ArrayMap; @@ -74,6 +80,7 @@ import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeProvider; import android.view.accessibility.AccessibilityWindowInfo; +import android.view.inputmethod.InlineSuggestionsRequest; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import android.widget.TextView; @@ -99,6 +106,7 @@ import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Set; +import java.util.concurrent.Executor; import sun.misc.Cleaner; @@ -167,6 +175,12 @@ import sun.misc.Cleaner; * shows an autofill save UI if the value of savable views have changed. If the user selects the * option to Save, the current value of the views is then sent to the autofill service. * + * <p>There is another choice for the application to provide it's datasets to the Autofill framework + * by setting an {@link AutofillRequestCallback} through + * {@link #setAutofillRequestCallback(Executor, AutofillRequestCallback)}. The application can use + * its callback instead of the default {@link AutofillService}. See + * {@link AutofillRequestCallback} for more details. + * * <h3 id="additional-notes">Additional notes</h3> * * <p>It is safe to call <code>AutofillManager</code> methods from any thread. @@ -249,6 +263,18 @@ public final class AutofillManager { 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"; @@ -280,6 +306,7 @@ public final class AutofillManager { /** @hide */ public static final int FLAG_ADD_CLIENT_DEBUG = 0x2; /** @hide */ public static final int FLAG_ADD_CLIENT_VERBOSE = 0x4; /** @hide */ public static final int FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY = 0x8; + /** @hide */ public static final int FLAG_ENABLED_CLIENT_SUGGESTIONS = 0x20; // NOTE: flag below is used by the session start receiver only, hence it can have values above /** @hide */ public static final int RECEIVER_FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY = 0x1; @@ -580,6 +607,11 @@ public final class AutofillManager { @GuardedBy("mLock") private boolean mEnabledForAugmentedAutofillOnly; + @GuardedBy("mLock") + @Nullable private AutofillRequestCallback mAutofillRequestCallback; + @GuardedBy("mLock") + @Nullable private Executor mRequestCallbackExecutor; + /** @hide */ public interface AutofillClient { /** @@ -1824,6 +1856,32 @@ public final class AutofillManager { return new AutofillId(parent.getAutofillViewId(), virtualId); } + /** + * Sets the client's suggestions callback for autofill. + * + * @see AutofillRequestCallback + * + * @param executor specifies the thread upon which the callbacks will be invoked. + * @param callback which handles autofill request to provide client's suggestions. + */ + public void setAutofillRequestCallback(@NonNull @CallbackExecutor Executor executor, + @NonNull AutofillRequestCallback callback) { + synchronized (mLock) { + mRequestCallbackExecutor = executor; + mAutofillRequestCallback = callback; + } + } + + /** + * clears the client's suggestions callback for autofill. + */ + public void clearAutofillRequestCallback() { + synchronized (mLock) { + mRequestCallbackExecutor = null; + mAutofillRequestCallback = null; + } + } + @GuardedBy("mLock") private void startSessionLocked(@NonNull AutofillId id, @NonNull Rect bounds, @NonNull AutofillValue value, int flags) { @@ -1884,6 +1942,13 @@ public final class AutofillManager { } } + if (mAutofillRequestCallback != null) { + if (sDebug) { + Log.d(TAG, "startSession with the client suggestions provider"); + } + flags |= FLAG_ENABLED_CLIENT_SUGGESTIONS; + } + mService.startSession(client.autofillClientGetActivityToken(), mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(), mCallback != null, flags, componentName, @@ -2233,6 +2298,28 @@ public final class AutofillManager { } } + private void onFillRequest(InlineSuggestionsRequest request, + CancellationSignal cancellationSignal, FillCallback callback) { + final AutofillRequestCallback autofillRequestCallback; + final Executor executor; + synchronized (mLock) { + autofillRequestCallback = mAutofillRequestCallback; + executor = mRequestCallbackExecutor; + } + if (autofillRequestCallback != null && executor != null) { + final long ident = Binder.clearCallingIdentity(); + try { + executor.execute(() -> + autofillRequestCallback.onFillRequest( + request, cancellationSignal, callback)); + } finally { + Binder.restoreCallingIdentity(ident); + } + } else { + callback.onSuccess(null); + } + } + /** @hide */ public static final int SET_STATE_FLAG_ENABLED = 0x01; /** @hide */ @@ -3612,6 +3699,23 @@ public final class AutofillManager { afm.post(() -> afm.requestShowSoftInput(id)); } } + + @Override + public void requestFillFromClient(int id, InlineSuggestionsRequest request, + IFillCallback callback) { + final AutofillManager afm = mAfm.get(); + if (afm != null) { + ICancellationSignal transport = CancellationSignal.createTransport(); + try { + callback.onCancellable(transport); + } catch (RemoteException e) { + Slog.w(TAG, "Error requesting a cancellation", e); + } + + afm.onFillRequest(request, CancellationSignal.fromTransport(transport), + new FillCallback(callback, id)); + } + } } private static final class AugmentedAutofillManagerClient diff --git a/core/java/android/view/autofill/AutofillRequestCallback.java b/core/java/android/view/autofill/AutofillRequestCallback.java new file mode 100644 index 000000000000..e632a5849471 --- /dev/null +++ b/core/java/android/view/autofill/AutofillRequestCallback.java @@ -0,0 +1,72 @@ +/* + * 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.view.autofill; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.CancellationSignal; +import android.service.autofill.FillCallback; +import android.view.inputmethod.InlineSuggestionsRequest; + +/** + * <p>This class is used to provide some input suggestions to the Autofill framework. + * + * <P>When the user is requested to input something, Autofill will try to query input suggestions + * for the user choosing. If the application want to provide some internal input suggestions, + * implements this callback and register via + * {@link AutofillManager#setAutofillRequestCallback(java.util.concurrent.Executor, + * AutofillRequestCallback)}. Autofill will callback the + * {@link #onFillRequest(InlineSuggestionsRequest, CancellationSignal, FillCallback)} to request + * input suggestions. + * + * <P>To make sure the callback to take effect, must register before the autofill session starts. + * If the autofill session is started, calls {@link AutofillManager#cancel()} to finish current + * session, and then the callback will be used at the next restarted session. + * + * <P>To create a {@link android.service.autofill.FillResponse}, application should fetch + * {@link AutofillId}s from its view structure. Below is an example: + * <pre class="prettyprint"> + * AutofillId usernameId = findViewById(R.id.username).getAutofillId(); + * AutofillId passwordId = findViewById(R.id.password).getAutofillId(); + * </pre> + * To learn more about creating a {@link android.service.autofill.FillResponse}, read + * <a href="/guide/topics/text/autofill-services#fill">Fill out client views</a>. + * + * <P>To fallback to the default {@link android.service.autofill.AutofillService}, just respond + * a null of the {@link android.service.autofill.FillResponse}. And then Autofill will do a fill + * request with the default {@link android.service.autofill.AutofillService}. Or clear the callback + * from {@link AutofillManager} via {@link AutofillManager#clearAutofillRequestCallback()}. If the + * client would like to keep no suggestions for the field, respond with an empty + * {@link android.service.autofill.FillResponse} which has no dataset. + * + * <P>IMPORTANT: This should not be used for displaying anything other than input suggestions, or + * the keyboard may choose to block your app from the inline strip. + */ +public interface AutofillRequestCallback { + /** + * Called by the Android system to decide if a screen can be autofilled by the callback. + * + * @param inlineSuggestionsRequest the {@link InlineSuggestionsRequest request} to handle if + * currently inline suggestions are supported and can be displayed. + * @param cancellationSignal signal for observing cancellation requests. The system will use + * this to notify you that the fill result is no longer needed and you should stop + * handling this fill request in order to save resources. + * @param callback object used to notify the result of the request. + */ + void onFillRequest(@Nullable InlineSuggestionsRequest inlineSuggestionsRequest, + @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback); +} diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl index 1f833f66c257..64507aac54cb 100644 --- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl +++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl @@ -24,9 +24,11 @@ import android.content.Intent; import android.content.IntentSender; import android.graphics.Rect; import android.os.IBinder; +import android.service.autofill.IFillCallback; import android.view.autofill.AutofillId; import android.view.autofill.AutofillValue; import android.view.autofill.IAutofillWindowPresenter; +import android.view.inputmethod.InlineSuggestionsRequest; import android.view.KeyEvent; import com.android.internal.os.IResultReceiver; @@ -140,4 +142,10 @@ oneway interface IAutoFillManagerClient { * Requests to show the soft input method if the focus is on the given id. */ void requestShowSoftInput(in AutofillId id); + + /** + * Requests to determine if a screen can be autofilled by the client app. + */ + void requestFillFromClient(int id, in InlineSuggestionsRequest request, + in IFillCallback callback); } diff --git a/core/java/android/view/displayhash/DisplayHashResultCallback.java b/core/java/android/view/displayhash/DisplayHashResultCallback.java index 15b29adafddd..04d29ee3d48a 100644 --- a/core/java/android/view/displayhash/DisplayHashResultCallback.java +++ b/core/java/android/view/displayhash/DisplayHashResultCallback.java @@ -66,12 +66,19 @@ public interface DisplayHashResultCallback { */ 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/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java index 5980cb6c3671..996757da0641 100644 --- a/core/java/android/view/textservice/TextServicesManager.java +++ b/core/java/android/view/textservice/TextServicesManager.java @@ -257,9 +257,11 @@ public final class TextServicesManager { } /** + * Deprecated. Use {@link #getEnabledSpellCheckerInfos()} instead. * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553, + publicAlternatives = "Use {@link #getEnabledSpellCheckerInfos()} instead.") public SpellCheckerInfo[] getEnabledSpellCheckers() { try { final SpellCheckerInfo[] retval = mService.getEnabledSpellCheckers(mUserId); @@ -279,7 +281,7 @@ public final class TextServicesManager { */ @Nullable @SuppressLint("NullableCollection") - public List<SpellCheckerInfo> getEnabledSpellCheckersList() { + public List<SpellCheckerInfo> getEnabledSpellCheckerInfos() { final SpellCheckerInfo[] enabledSpellCheckers = getEnabledSpellCheckers(); return enabledSpellCheckers != null ? Arrays.asList(enabledSpellCheckers) : null; } @@ -290,7 +292,7 @@ public final class TextServicesManager { * @return The current active spell checker info. */ @Nullable - public SpellCheckerInfo getCurrentSpellChecker() { + public SpellCheckerInfo getCurrentSpellCheckerInfo() { try { // Passing null as a locale for ICS return mService.getCurrentSpellChecker(mUserId, null); @@ -300,12 +302,26 @@ public final class TextServicesManager { } /** + * Deprecated. Use {@link #getCurrentSpellCheckerInfo()} instead. + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, + publicAlternatives = "Use {@link #getCurrentSpellCheckerInfo()} instead.") + @Nullable + public SpellCheckerInfo getCurrentSpellChecker() { + return getCurrentSpellCheckerInfo(); + } + + /** * Retrieve the selected subtype of the selected spell checker, or null if there is none. * * @param allowImplicitlySelectedSubtype {@code true} to return the default language matching * system locale if there's no subtype selected explicitly, otherwise, returns null. * @return The meta information of the selected subtype of the selected spell checker. + * + * @hide */ + @UnsupportedAppUsage @Nullable public SpellCheckerSubtype getCurrentSpellCheckerSubtype( boolean allowImplicitlySelectedSubtype) { diff --git a/core/java/android/view/translation/TEST_MAPPING b/core/java/android/view/translation/TEST_MAPPING new file mode 100644 index 000000000000..37b6fe7396b8 --- /dev/null +++ b/core/java/android/view/translation/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "imports": [ + { + "path": "frameworks/base/services/translation/java/com/android/server/translation" + } + ] +} diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java index 1b62266c12e2..dc42ad583543 100644 --- a/core/java/android/widget/EdgeEffect.java +++ b/core/java/android/widget/EdgeEffect.java @@ -29,7 +29,6 @@ import android.graphics.Matrix; 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 class EdgeEffect { 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 @@ public class EdgeEffect { 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 @@ public class EdgeEffect { 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 @@ public class EdgeEffect { 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 @@ public class EdgeEffect { } /** + * @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 @@ public class EdgeEffect { 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 @@ public class EdgeEffect { 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 23915e06335a..bf552e2a501c 100644 --- a/core/java/android/widget/HorizontalScrollView.java +++ b/core/java/android/widget/HorizontalScrollView.java @@ -249,6 +249,26 @@ public class HorizontalScrollView extends FrameLayout { } /** + * 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 2cf50bbc6793..2328e589216b 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -51,7 +51,6 @@ import android.content.res.loader.ResourcesProvider; 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.DisplayMetrics; 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,11 +353,18 @@ public class RemoteViews implements Parcelable, Filter { * 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; + /** + * Id to use to override the ID of the top-level view in this RemoteViews. + * + * Only used if this RemoteViews is defined from a XML layout value. + */ + private int mViewId = View.NO_ID; + /** Class cookies of the Parcel this instance was read from. */ private Map<Class, Object> mClassCookies; @@ -3042,11 +3049,11 @@ public class RemoteViews implements Parcelable, Filter { 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 +3101,18 @@ public class RemoteViews implements Parcelable, Filter { * 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 +3147,8 @@ public class RemoteViews implements Parcelable, Filter { 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 +3251,7 @@ public class RemoteViews implements Parcelable, Filter { 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 +4637,9 @@ public class RemoteViews implements Parcelable, Filter { * * 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 +4649,17 @@ public class RemoteViews implements Parcelable, Filter { * 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 +4680,46 @@ public class RemoteViews implements Parcelable, Filter { 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 +4743,7 @@ public class RemoteViews implements Parcelable, Filter { /** @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 +4760,7 @@ public class RemoteViews implements Parcelable, Filter { /** @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 +4770,7 @@ public class RemoteViews implements Parcelable, Filter { /** @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); @@ -4768,6 +4806,9 @@ public class RemoteViews implements Parcelable, Filter { inflater = inflater.cloneInContext(inflationContext); inflater.setFilter(shouldUseStaticFilter() ? INFLATER_FILTER : this); View v = inflater.inflate(rv.getLayoutId(), parent, false); + if (mViewId != View.NO_ID) { + v.setId(mViewId); + } v.setTagInternal(R.id.widget_frame, rv.getLayoutId()); return v; } @@ -4828,21 +4869,21 @@ public class RemoteViews implements Parcelable, Filter { /** @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 +5009,7 @@ public class RemoteViews implements Parcelable, Filter { } /** @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 +5053,7 @@ public class RemoteViews implements Parcelable, Filter { /** @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); @@ -5715,4 +5756,25 @@ public class RemoteViews implements Parcelable, Filter { } return true; } + + /** + * Set the ID of the top-level view of the XML layout. + * + * Set to {@link View#NO_ID} to reset and simply keep the id defined in the XML layout. + * + * @throws UnsupportedOperationException if the method is called on a RemoteViews defined in + * term of other RemoteViews (e.g. {@link #RemoteViews(RemoteViews, RemoteViews)}). + */ + public void setViewId(@IdRes int viewId) { + if (hasMultipleLayouts()) { + throw new UnsupportedOperationException( + "The viewId can only be set on RemoteViews defined from a XML layout."); + } + mViewId = viewId; + } + + /** Get the ID of the top-level view of the XML layout, as set by {@link #setViewId}. */ + public @IdRes int getViewId() { + return mViewId; + } } diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java index 65f3da79afe0..30067296f967 100644 --- a/core/java/android/widget/ScrollView.java +++ b/core/java/android/widget/ScrollView.java @@ -281,6 +281,26 @@ public class ScrollView extends FrameLayout { } /** + * 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/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java index 217ade82b336..04020ec3ee8a 100644 --- a/core/java/android/window/TaskOrganizer.java +++ b/core/java/android/window/TaskOrganizer.java @@ -52,7 +52,7 @@ public class TaskOrganizer extends WindowOrganizer { /** @hide */ @VisibleForTesting public TaskOrganizer(ITaskOrganizerController taskOrganizerController, Executor executor) { - mExecutor = executor != null ? executor : command -> command.run(); + mExecutor = executor != null ? executor : Runnable::run; mTaskOrganizerController = taskOrganizerController != null ? taskOrganizerController : getController(); } diff --git a/core/java/android/window/TransitionFilter.java b/core/java/android/window/TransitionFilter.java index 4421f06460a0..141f47b130d1 100644 --- a/core/java/android/window/TransitionFilter.java +++ b/core/java/android/window/TransitionFilter.java @@ -139,8 +139,8 @@ public final class TransitionFilter implements Parcelable { 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 d1d49b6d4722..499ce25f8bb9 100644 --- a/core/java/android/window/TransitionInfo.java +++ b/core/java/android/window/TransitionInfo.java @@ -246,6 +246,33 @@ public final class TransitionInfo implements Parcelable { 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 01e45f613986..66206bf8297a 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 @@ public class WuQuantizer implements Quantizer { } } - 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 21131738cede..3958b9eefefb 100644 --- a/core/java/com/android/internal/inputmethod/CallbackUtils.java +++ b/core/java/com/android/internal/inputmethod/CallbackUtils.java @@ -225,4 +225,31 @@ public final class CallbackUtils { 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 d6a466316ed4..ba3a34334e86 100644 --- a/core/java/com/android/internal/inputmethod/Completable.java +++ b/core/java/com/android/internal/inputmethod/Completable.java @@ -444,6 +444,13 @@ public final class Completable { } /** + * @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 @@ public final class Completable { 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/com/android/internal/inputmethod/IIInputContentUriTokenResultCallback.aidl b/core/java/com/android/internal/inputmethod/IIInputContentUriTokenResultCallback.aidl new file mode 100644 index 000000000000..2e6d2247b51b --- /dev/null +++ b/core/java/com/android/internal/inputmethod/IIInputContentUriTokenResultCallback.aidl @@ -0,0 +1,25 @@ +/* + * 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.internal.inputmethod; + +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 f0e26cf4bbcf..e4dd7b0629b5 100644 --- a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl +++ b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl @@ -19,25 +19,31 @@ package com.android.internal.inputmethod; 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 d6730e8b0bdb..04cf3f3e546f 100644 --- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java +++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java @@ -95,7 +95,8 @@ public final class InputMethodPrivilegedOperations { } /** - * 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 @@ public final class InputMethodPrivilegedOperations { 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 @@ public final class InputMethodPrivilegedOperations { 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 @@ public final class InputMethodPrivilegedOperations { 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 @@ public final class InputMethodPrivilegedOperations { } /** - * 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 @@ public final class InputMethodPrivilegedOperations { 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 @@ public final class InputMethodPrivilegedOperations { 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 @@ public final class InputMethodPrivilegedOperations { 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 @@ public final class InputMethodPrivilegedOperations { /** * 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 @@ public final class InputMethodPrivilegedOperations { 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 @@ public final class InputMethodPrivilegedOperations { 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 @@ public final class InputMethodPrivilegedOperations { 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 @@ public final class InputMethodPrivilegedOperations { 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 @@ public final class InputMethodPrivilegedOperations { 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 @@ public final class InputMethodPrivilegedOperations { 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 @@ public final class InputMethodPrivilegedOperations { 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 @@ public final class InputMethodPrivilegedOperations { 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 2a48c1f60aa9..c56ed2d19927 100644 --- a/core/java/com/android/internal/inputmethod/ResultCallbacks.java +++ b/core/java/com/android/internal/inputmethod/ResultCallbacks.java @@ -387,4 +387,41 @@ public final class ResultCallbacks { } }; } + + /** + * 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 33ee8f04d83e..c897002c88e9 100644 --- a/core/java/com/android/internal/jank/FrameTracker.java +++ b/core/java/com/android/internal/jank/FrameTracker.java @@ -121,7 +121,8 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener mChoreographer = choreographer; mSurfaceControlWrapper = surfaceControlWrapper; mHandler = handler; - mObserver = new HardwareRendererObserver(this, mMetricsWrapper.getTiming(), handler); + mObserver = new HardwareRendererObserver( + this, mMetricsWrapper.getTiming(), handler, false /*waitForPresentTime*/); mTraceThresholdMissedFrames = traceThresholdMissedFrames; mTraceThresholdFrameTimeMillis = traceThresholdFrameTimeMillis; mListener = listener; @@ -327,11 +328,8 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener } 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/AmbientDisplayPowerCalculator.java b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java index e153eb2f0933..586607e413d9 100644 --- a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java +++ b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java @@ -46,7 +46,8 @@ public class AmbientDisplayPowerCalculator extends PowerCalculator { long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { final long durationMs = calculateDuration(batteryStats, rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED); - final double powerMah = getMeasuredOrEstimatedPower(batteryStats.getScreenDozeEnergy(), + final double powerMah = getMeasuredOrEstimatedPower( + batteryStats.getScreenDozeMeasuredBatteryConsumptionUC(), mPowerEstimator, durationMs, query.shouldForceUsePowerProfileModel()); builder.getOrCreateSystemBatteryConsumerBuilder( SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY) @@ -64,7 +65,8 @@ public class AmbientDisplayPowerCalculator extends PowerCalculator { public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats, long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) { final long durationMs = calculateDuration(batteryStats, rawRealtimeUs, statsType); - final double powerMah = getMeasuredOrEstimatedPower(batteryStats.getScreenDozeEnergy(), + final double powerMah = getMeasuredOrEstimatedPower( + batteryStats.getScreenDozeMeasuredBatteryConsumptionUC(), mPowerEstimator, durationMs, false); if (powerMah > 0) { BatterySipper bs = new BatterySipper(BatterySipper.DrainType.AMBIENT_DISPLAY, null, 0); @@ -78,5 +80,4 @@ public class AmbientDisplayPowerCalculator extends PowerCalculator { private long calculateDuration(BatteryStats batteryStats, long rawRealtimeUs, int statsType) { return batteryStats.getScreenDozeTime(rawRealtimeUs, statsType) / 1000; } - } diff --git a/core/java/com/android/internal/os/DischargedPowerCalculator.java b/core/java/com/android/internal/os/BatteryChargeCalculator.java index e94020cc4f18..dc72f3267390 100644 --- a/core/java/com/android/internal/os/DischargedPowerCalculator.java +++ b/core/java/com/android/internal/os/BatteryChargeCalculator.java @@ -27,10 +27,10 @@ import java.util.List; /** * 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 @@ public class DischargedPowerCalculator extends PowerCalculator { .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/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 73527d4a80d8..9ecb0ad09bc4 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -105,7 +105,7 @@ import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidUserSysTimeReader; import com.android.internal.os.SystemServerCpuThreadReader.SystemServiceCpuThreadTimes; import com.android.internal.power.MeasuredEnergyStats; -import com.android.internal.power.MeasuredEnergyStats.StandardEnergyBucket; +import com.android.internal.power.MeasuredEnergyStats.StandardPowerBucket; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.XmlUtils; @@ -169,7 +169,7 @@ public class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version - static final int VERSION = 193; + static final int VERSION = 194; // The maximum number of names wakelocks we will keep track of // per uid; once the limit is reached, we batch the remaining wakelocks @@ -996,9 +996,9 @@ public class BatteryStatsImpl extends BatteryStats { int mWifiRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW; /** - * Accumulated global (generally, device-wide total) energy consumption of various consumers + * Accumulated global (generally, device-wide total) charge consumption of various consumers * while on battery. - * Its '<b>custom</b> energy buckets' correspond to the + * Its '<b>custom</b> power buckets' correspond to the * {@link android.hardware.power.stats.EnergyConsumer.ordinal}s of (custom) energy consumer * type {@link android.hardware.power.stats.EnergyConsumerType#OTHER}). * @@ -1009,6 +1009,8 @@ public class BatteryStatsImpl extends BatteryStats { protected @Nullable MeasuredEnergyStats mGlobalMeasuredEnergyStats; /** Last known screen state. Needed for apportioning display energy. */ int mScreenStateAtLastEnergyMeasurement = Display.STATE_UNKNOWN; + /** Cpu Power calculator for attributing measured cpu charge consumption to uids */ + @Nullable CpuPowerCalculator mCpuPowerCalculator = null; /** * These provide time bases that discount the time the device is plugged @@ -6965,35 +6967,35 @@ public class BatteryStatsImpl extends BatteryStats { } @Override - public long getScreenOnEnergy() { - return getMeasuredEnergyMicroJoules(MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_ON); + public long getScreenOnMeasuredBatteryConsumptionUC() { + return getPowerBucketConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON); } @Override - public long getScreenDozeEnergy() { - return getMeasuredEnergyMicroJoules(MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_DOZE); + public long getScreenDozeMeasuredBatteryConsumptionUC() { + return getPowerBucketConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_SCREEN_DOZE); } /** - * Returns the energy in microjoules that the given standard energy bucket consumed. - * Will return {@link #ENERGY_DATA_UNAVAILABLE} if data is unavailable + * Returns the consumption (in microcoulombs) that the given standard power bucket consumed. + * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable * - * @param bucket standard energy bucket of interest - * @return energy (in microjoules) used for this energy bucket + * @param bucket standard power bucket of interest + * @return charge (in microcoulombs) used for this power bucket */ - private long getMeasuredEnergyMicroJoules(@StandardEnergyBucket int bucket) { + private long getPowerBucketConsumptionUC(@StandardPowerBucket int bucket) { if (mGlobalMeasuredEnergyStats == null) { - return ENERGY_DATA_UNAVAILABLE; + return POWER_DATA_UNAVAILABLE; } - return mGlobalMeasuredEnergyStats.getAccumulatedStandardBucketEnergy(bucket); + return mGlobalMeasuredEnergyStats.getAccumulatedStandardBucketCharge(bucket); } @Override - public @Nullable long[] getCustomMeasuredEnergiesMicroJoules() { + public @Nullable long[] getCustomConsumerMeasuredBatteryConsumptionUC() { if (mGlobalMeasuredEnergyStats == null) { return null; } - return mGlobalMeasuredEnergyStats.getAccumulatedCustomBucketEnergies(); + return mGlobalMeasuredEnergyStats.getAccumulatedCustomBucketCharges(); } @Override public long getStartClockTime() { @@ -7347,8 +7349,8 @@ public class BatteryStatsImpl extends BatteryStats { private final ArraySet<BinderCallStats> mBinderCallStats = new ArraySet<>(); /** - * Measured energies attributed to this uid while on battery. - * Its '<b>custom</b> energy buckets' correspond to the + * Measured charge consumption by this uid while on battery. + * Its '<b>custom</b> power buckets' correspond to the * {@link android.hardware.power.stats.EnergyConsumer.ordinal}s of (custom) energy consumer * type {@link android.hardware.power.stats.EnergyConsumerType#OTHER}). * @@ -7768,44 +7770,44 @@ public class BatteryStatsImpl extends BatteryStats { return mUidMeasuredEnergyStats; } - /** Adds the given energy to the given standard energy bucket for this uid. */ - private void addEnergyToStandardBucketLocked(long energyDeltaUJ, - @StandardEnergyBucket int energyBucket) { - getOrCreateMeasuredEnergyStatsLocked() - .updateStandardBucket(energyBucket, energyDeltaUJ); + /** Adds the given charge to the given standard power bucket for this uid. */ + private void addChargeToStandardBucketLocked(long chargeDeltaUC, + @StandardPowerBucket int powerBucket) { + getOrCreateMeasuredEnergyStatsLocked().updateStandardBucket(powerBucket, chargeDeltaUC); } - /** Adds the given energy to the given custom energy bucket for this uid. */ - private void addEnergyToCustomBucketLocked(long energyDeltaUJ, int energyBucket) { - getOrCreateMeasuredEnergyStatsLocked().updateCustomBucket(energyBucket, energyDeltaUJ); + /** Adds the given charge to the given custom power bucket for this uid. */ + private void addChargeToCustomBucketLocked(long chargeDeltaUC, int powerBucket) { + getOrCreateMeasuredEnergyStatsLocked().updateCustomBucket(powerBucket, chargeDeltaUC); } /** - * Returns the energy used by this uid for a standard energy bucket of interest. - * @param bucket standard energy bucket of interest - * @return energy (in microjoules) used by this uid for this energy bucket + * Returns the battery consumption (in microcoulomb) of this uid for a standard power bucket + * of interest. + * @param bucket standard power bucket of interest + * @return consumption (in microcolombs) used by this uid for this power bucket */ - public long getMeasuredEnergyMicroJoules(@StandardEnergyBucket int bucket) { + public long getMeasuredBatteryConsumptionUC(@StandardPowerBucket int bucket) { if (mBsi.mGlobalMeasuredEnergyStats == null || !mBsi.mGlobalMeasuredEnergyStats.isStandardBucketSupported(bucket)) { - return ENERGY_DATA_UNAVAILABLE; + return POWER_DATA_UNAVAILABLE; } if (mUidMeasuredEnergyStats == null) { return 0L; // It is supported, but was never filled, so it must be 0 } - return mUidMeasuredEnergyStats.getAccumulatedStandardBucketEnergy(bucket); + return mUidMeasuredEnergyStats.getAccumulatedStandardBucketCharge(bucket); } @Override - public long[] getCustomMeasuredEnergiesMicroJoules() { + public long[] getCustomConsumerMeasuredBatteryConsumptionUC() { if (mBsi.mGlobalMeasuredEnergyStats == null) { return null; } if (mUidMeasuredEnergyStats == null) { // Custom buckets may exist. But all values for this uid are 0 so we report all 0s. - return new long[mBsi.mGlobalMeasuredEnergyStats.getNumberCustomEnergyBuckets()]; + return new long[mBsi.mGlobalMeasuredEnergyStats.getNumberCustomPowerBuckets()]; } - return mUidMeasuredEnergyStats.getAccumulatedCustomBucketEnergies(); + return mUidMeasuredEnergyStats.getAccumulatedCustomBucketCharges(); } /** @@ -8476,8 +8478,8 @@ public class BatteryStatsImpl extends BatteryStats { } @Override - public long getScreenOnEnergy() { - return getMeasuredEnergyMicroJoules(MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_ON); + public long getScreenOnMeasuredBatteryConsumptionUC() { + return getMeasuredBatteryConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON); } void initNetworkActivityLocked() { @@ -12170,27 +12172,108 @@ public class BatteryStatsImpl extends BatteryStats { } /** - * Accumulate Display energy and distribute it to the correct state and the apps. + * Accumulate Cpu charge consumption and distribute it to the correct state and the apps. + * Only call if device is on battery. + * + * @param clusterChargeUC amount of charge (microcoulombs) consumed by each Cpu Cluster + * @param accumulator collection of calculated uid cpu power consumption to smear + * clusterChargeUC against. + */ + @GuardedBy("this") + private void updateCpuMeasuredEnergyStatsLocked(@NonNull long[] clusterChargeUC, + @NonNull CpuDeltaPowerAccumulator accumulator) { + if (DEBUG_ENERGY) { + Slog.d(TAG, + "Updating cpu cluster stats: " + clusterChargeUC.toString()); + } + if (mGlobalMeasuredEnergyStats == null) { + return; + } + + final int numClusters = clusterChargeUC.length; + long totalCpuChargeUC = 0; + for (int i = 0; i < numClusters; i++) { + totalCpuChargeUC += clusterChargeUC[i]; + } + if (totalCpuChargeUC <= 0) return; + + mGlobalMeasuredEnergyStats.updateStandardBucket(MeasuredEnergyStats.POWER_BUCKET_CPU, + totalCpuChargeUC); + + // Calculate the measured microcoulombs/calculated milliamp-hour charge ratio for each + // cluster to normalize each uid's estimated power usage against actual power usage for + // a given cluster. + final double[] clusterChargeRatio = new double[numClusters]; + for (int cluster = 0; cluster < numClusters; cluster++) { + + final double totalClusterChargeMah = accumulator.totalClusterChargesMah[cluster]; + if (totalClusterChargeMah <= 0.0) { + // This cluster did not have any work on it, since last update. + // Avoid dividing by zero. + clusterChargeRatio[cluster] = 0.0; + } else { + clusterChargeRatio[cluster] = + clusterChargeUC[cluster] / accumulator.totalClusterChargesMah[cluster]; + } + } + + // Assign and distribute power usage to apps based on their calculated cpu cluster charge. + final long uidChargeArraySize = accumulator.perUidCpuClusterChargesMah.size(); + for (int i = 0; i < uidChargeArraySize; i++) { + final Uid uid = accumulator.perUidCpuClusterChargesMah.keyAt(i); + final double[] uidClusterChargesMah = accumulator.perUidCpuClusterChargesMah.valueAt(i); + + // Iterate each cpu cluster and sum the proportional measured cpu cluster charge to + // get the total cpu charge consumed by a uid. + long uidCpuChargeUC = 0; + for (int cluster = 0; cluster < numClusters; cluster++) { + final double uidClusterChargeMah = uidClusterChargesMah[cluster]; + + // Proportionally allocate the measured cpu cluster charge to a uid using the + // measured charge/calculated charge ratio. Add 0.5 to round the proportional + // charge double to the nearest long value. + final long uidClusterChargeUC = + (long) (uidClusterChargeMah * clusterChargeRatio[cluster] + + 0.5); + + uidCpuChargeUC += uidClusterChargeUC; + } + + if (uidCpuChargeUC < 0) { + Slog.wtf(TAG, + "Unexpected proportional measured charge (" + uidCpuChargeUC + ") for uid " + + uid.mUid); + continue; + } + + uid.addChargeToStandardBucketLocked(uidCpuChargeUC, + MeasuredEnergyStats.POWER_BUCKET_CPU); + } + } + + /** + * Accumulate Display charge consumption and distribute it to the correct state and the apps. * * NOTE: The algorithm used makes the strong assumption that app foreground activity time * is always 0 when the screen is not "ON" and whenever the rail energy is 0 (if supported). * To the extent that those assumptions are violated, the algorithm will err. * - * @param energyUJ amount of energy (microjoules) used by Display since this was last called. + * @param chargeUC amount of charge (microcoulombs) used by Display since this was last called. * @param screenState screen state at the time this data collection was scheduled */ @GuardedBy("this") - public void updateDisplayEnergyLocked(long energyUJ, int screenState, long elapsedRealtimeMs) { - if (DEBUG_ENERGY) Slog.d(TAG, "Updating display stats: " + energyUJ); + public void updateDisplayMeasuredEnergyStatsLocked(long chargeUC, int screenState, + long elapsedRealtimeMs) { + if (DEBUG_ENERGY) Slog.d(TAG, "Updating display stats: " + chargeUC); if (mGlobalMeasuredEnergyStats == null) { return; } - final @StandardEnergyBucket int energyBucket = - MeasuredEnergyStats.getDisplayEnergyBucket(mScreenStateAtLastEnergyMeasurement); + final @StandardPowerBucket int powerBucket = + MeasuredEnergyStats.getDisplayPowerBucket(mScreenStateAtLastEnergyMeasurement); mScreenStateAtLastEnergyMeasurement = screenState; - if (!mOnBatteryInternal || energyUJ <= 0) { + if (!mOnBatteryInternal || chargeUC <= 0) { // There's nothing further to update. return; } @@ -12205,13 +12288,13 @@ public class BatteryStatsImpl extends BatteryStats { return; } - mGlobalMeasuredEnergyStats.updateStandardBucket(energyBucket, energyUJ); + mGlobalMeasuredEnergyStats.updateStandardBucket(powerBucket, chargeUC); // Now we blame individual apps, but only if the display was ON. - if (energyBucket != MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_ON) { + if (powerBucket != MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON) { return; } - // TODO(b/175726779): Consider unifying the code with the non-rail display energy blaming. + // TODO(b/175726779): Consider unifying the code with the non-rail display power blaming. // NOTE: fg time is NOT pooled. If two uids are both somehow in fg, then that time is // 'double counted' and will simply exceed the realtime that elapsed. @@ -12230,7 +12313,7 @@ public class BatteryStatsImpl extends BatteryStats { fgTimeMsArray.put(uid, fgTimeMs); totalFgTimeMs += fgTimeMs; } - long totalDisplayEnergyMJ = energyUJ / 1000; // not final + long totalDisplayChargeMC = chargeUC / 1000; // not final // Actually assign and distribute power usage to apps based on their fg time since mark. // TODO(b/175726326): Decide on 'energy' units and make sure algorithm won't overflow. @@ -12240,47 +12323,47 @@ public class BatteryStatsImpl extends BatteryStats { final long fgTimeMs = fgTimeMsArray.valueAt(i); // Using long division: "appEnergy = totalEnergy * appFg/totalFg + 0.5" with rounding - final long appDisplayEnergyMJ = - (totalDisplayEnergyMJ * fgTimeMs + (totalFgTimeMs / 2)) + final long appDisplayChargeMC = + (totalDisplayChargeMC * fgTimeMs + (totalFgTimeMs / 2)) / totalFgTimeMs; - uid.addEnergyToStandardBucketLocked(appDisplayEnergyMJ * 1000, energyBucket); + uid.addChargeToStandardBucketLocked(appDisplayChargeMC * 1000, powerBucket); // To mitigate round-off errors, remove this app from numerator & denominator totals - totalDisplayEnergyMJ -= appDisplayEnergyMJ; + totalDisplayChargeMC -= appDisplayChargeMC; totalFgTimeMs -= fgTimeMs; } } /** - * Accumulate Custom energy bucket energy, globally and for each app. + * Accumulate Custom power bucket charge, globally and for each app. * - * @param totalEnergyUJ energy (microjoules) used for this bucket since this was last called. - * @param uidEnergies map of uid->energy (microjoules) for this bucket since last called. - * Data inside uidEnergies will not be modified (treated immutable). + * @param totalChargeUC charge (microcoulombs) used for this bucket since this was last called. + * @param uidCharges map of uid->charge (microcoulombs) for this bucket since last called. + * Data inside uidCharges will not be modified (treated immutable). * Uids not already known to BatteryStats will be ignored. */ - public void updateCustomMeasuredEnergyDataLocked(int customEnergyBucket, - long totalEnergyUJ, @Nullable SparseLongArray uidEnergies) { + public void updateCustomMeasuredEnergyStatsLocked(int customPowerBucket, + long totalChargeUC, @Nullable SparseLongArray uidCharges) { if (DEBUG_ENERGY) { - Slog.d(TAG, "Updating attributed measured energy stats for custom bucket " - + customEnergyBucket - + " with total energy " + totalEnergyUJ - + " and uid energies " + String.valueOf(uidEnergies)); + Slog.d(TAG, "Updating attributed measured charge stats for custom bucket " + + customPowerBucket + + " with total charge " + totalChargeUC + + " and uid charges " + String.valueOf(uidCharges)); } if (mGlobalMeasuredEnergyStats == null) return; - if (!mOnBatteryInternal || mIgnoreNextExternalStats || totalEnergyUJ <= 0) return; + if (!mOnBatteryInternal || mIgnoreNextExternalStats || totalChargeUC <= 0) return; - mGlobalMeasuredEnergyStats.updateCustomBucket(customEnergyBucket, totalEnergyUJ); + mGlobalMeasuredEnergyStats.updateCustomBucket(customPowerBucket, totalChargeUC); - if (uidEnergies == null) return; - final int numUids = uidEnergies.size(); + if (uidCharges == null) return; + final int numUids = uidCharges.size(); for (int i = 0; i < numUids; i++) { - final int uidInt = mapUid(uidEnergies.keyAt(i)); - final long uidEnergyUJ = uidEnergies.valueAt(i); - if (uidEnergyUJ == 0) continue; + final int uidInt = mapUid(uidCharges.keyAt(i)); + final long uidChargeUC = uidCharges.valueAt(i); + if (uidChargeUC == 0) continue; final Uid uidObj = getAvailableUidStatsLocked(uidInt); if (uidObj != null) { - uidObj.addEnergyToCustomBucketLocked(uidEnergyUJ, customEnergyBucket); + uidObj.addChargeToCustomBucketLocked(uidChargeUC, customPowerBucket); } else { // Ignore any uid not already known to BatteryStats, rather than creating a new Uid. // Otherwise we could end up reviving dead Uids. Note that the CPU data is updated @@ -12288,8 +12371,8 @@ public class BatteryStatsImpl extends BatteryStats { // Recently removed uids (especially common for isolated uids) can reach this path // and are ignored. if (!Process.isIsolated(uidInt)) { - Slog.w(TAG, "Received measured energy " + totalEnergyUJ + " for custom bucket " - + customEnergyBucket + " for non-existent uid " + uidInt); + Slog.w(TAG, "Received measured charge " + totalChargeUC + " for custom bucket " + + customPowerBucket + " for non-existent uid " + uidInt); } } } @@ -12416,6 +12499,64 @@ public class BatteryStatsImpl extends BatteryStats { } /** + * Object for calculating and accumulating the estimated cpu power used while reading the + * various cpu kernel files. + */ + @VisibleForTesting + public static class CpuDeltaPowerAccumulator { + // Keeps track of total charge used per cluster. + public final double[] totalClusterChargesMah; + // Keeps track of charge used per cluster per uid. + public final ArrayMap<Uid, double[]> perUidCpuClusterChargesMah; + + private final CpuPowerCalculator mCalculator; + private Uid mCachedUid = null; + private double[] mUidClusterCache = null; + + CpuDeltaPowerAccumulator(CpuPowerCalculator calculator, int nClusters) { + mCalculator = calculator; + totalClusterChargesMah = new double[nClusters]; + perUidCpuClusterChargesMah = new ArrayMap<>(); + } + + /** Add per cpu cluster durations to the currently cached uid. */ + public void addCpuClusterDurationsMs(Uid uid, long[] durationsMs) { + final double[] uidChargesMah = getOrCreateUidCpuClusterCharges(uid); + for (int cluster = 0; cluster < durationsMs.length; cluster++) { + final double estimatedDeltaMah = mCalculator.calculatePerCpuClusterPowerMah(cluster, + durationsMs[cluster]); + uidChargesMah[cluster] += estimatedDeltaMah; + totalClusterChargesMah[cluster] += estimatedDeltaMah; + } + } + + /** Add per speed per cpu cluster durations to the currently cached uid. */ + public void addCpuClusterSpeedDurationsMs(Uid uid, int cluster, int speed, + long durationsMs) { + final double[] uidChargesMah = getOrCreateUidCpuClusterCharges(uid); + final double estimatedDeltaMah = mCalculator.calculatePerCpuFreqPowerMah(cluster, speed, + durationsMs); + uidChargesMah[cluster] += estimatedDeltaMah; + totalClusterChargesMah[cluster] += estimatedDeltaMah; + } + + private double[] getOrCreateUidCpuClusterCharges(Uid uid) { + // Repeated additions on the same uid is very likely. + // Skip a lookup if getting the same uid as the last get. + if (uid == mCachedUid) return mUidClusterCache; + + double[] uidChargesMah = perUidCpuClusterChargesMah.get(uid); + if (uidChargesMah == null) { + uidChargesMah = new double[totalClusterChargesMah.length]; + perUidCpuClusterChargesMah.put(uid, uidChargesMah); + } + mCachedUid = uid; + mUidClusterCache = uidChargesMah; + return uidChargesMah; + } + } + + /** * Read and distribute CPU usage across apps. If their are partial wakelocks being held * and we are on battery with screen off, we give more of the cpu time to those apps holding * wakelocks. If the screen is on, we just assign the actual cpu time an app used. @@ -12424,7 +12565,8 @@ public class BatteryStatsImpl extends BatteryStats { * buckets. */ @GuardedBy("this") - public void updateCpuTimeLocked(boolean onBattery, boolean onBatteryScreenOff) { + public void updateCpuTimeLocked(boolean onBattery, boolean onBatteryScreenOff, + long[] measuredCpuClusterChargeUC) { if (mPowerProfile == null) { return; } @@ -12478,21 +12620,48 @@ public class BatteryStatsImpl extends BatteryStats { mUserInfoProvider.refreshUserIds(); final SparseLongArray updatedUids = mCpuUidFreqTimeReader.perClusterTimesAvailable() ? null : new SparseLongArray(); + + final CpuDeltaPowerAccumulator powerAccumulator; + if (mGlobalMeasuredEnergyStats != null + && mGlobalMeasuredEnergyStats.isStandardBucketSupported( + MeasuredEnergyStats.POWER_BUCKET_CPU) && mCpuPowerCalculator != null) { + if (measuredCpuClusterChargeUC == null) { + Slog.wtf(TAG, + "POWER_BUCKET_CPU supported but no measured Cpu Cluster charge reported " + + "on updateCpuTimeLocked!"); + powerAccumulator = null; + } else { + // Cpu Measured Energy is supported, create an object to accumulate the estimated + // charge consumption since the last cpu update + final int numClusters = mPowerProfile.getNumCpuClusters(); + powerAccumulator = new CpuDeltaPowerAccumulator(mCpuPowerCalculator, numClusters); + } + } else { + powerAccumulator = null; + } + readKernelUidCpuTimesLocked(partialTimersToConsider, updatedUids, onBattery); // updatedUids=null means /proc/uid_time_in_state provides snapshots of per-cluster cpu // freqs, so no need to approximate these values. if (updatedUids != null) { - updateClusterSpeedTimes(updatedUids, onBattery); + updateClusterSpeedTimes(updatedUids, onBattery, powerAccumulator); } - readKernelUidCpuFreqTimesLocked(partialTimersToConsider, onBattery, onBatteryScreenOff); + readKernelUidCpuFreqTimesLocked(partialTimersToConsider, onBattery, onBatteryScreenOff, + powerAccumulator); mNumAllUidCpuTimeReads += 2; if (mConstants.TRACK_CPU_ACTIVE_CLUSTER_TIME) { + // Cpu Active times do not get any info ony how to attribute measured Cpu Cluster + // charge, so not need to provide the powerAccumulator readKernelUidCpuActiveTimesLocked(onBattery); - readKernelUidCpuClusterTimesLocked(onBattery); + readKernelUidCpuClusterTimesLocked(onBattery, powerAccumulator); mNumAllUidCpuTimeReads += 2; } updateSystemServerThreadStats(); + + if (powerAccumulator != null) { + updateCpuMeasuredEnergyStatsLocked(measuredCpuClusterChargeUC, powerAccumulator); + } } /** @@ -12579,12 +12748,16 @@ public class BatteryStatsImpl extends BatteryStats { /** * Take snapshot of cpu times (aggregated over all uids) at different frequencies and - * calculate cpu times spent by each uid at different frequencies. + * calculate cpu times spent by each uid at different frequencies. Will also add estimated + * power consumptions, if powerAccumulator data structure is provided. * - * @param updatedUids The uids for which times spent at different frequencies are calculated. + * @param updatedUids The uids for which times spent at different frequencies are calculated. + * @param onBattery whether or not this is onBattery + * @param powerAccumulator object to accumulate the estimated cluster charge consumption. */ @VisibleForTesting - public void updateClusterSpeedTimes(@NonNull SparseLongArray updatedUids, boolean onBattery) { + public void updateClusterSpeedTimes(@NonNull SparseLongArray updatedUids, boolean onBattery, + @Nullable CpuDeltaPowerAccumulator powerAccumulator) { long totalCpuClustersTimeMs = 0; // Read the time spent for each cluster at various cpu frequencies. final long[][] clusterSpeedTimesMs = new long[mKernelCpuSpeedReaders.length][]; @@ -12626,9 +12799,15 @@ public class BatteryStatsImpl extends BatteryStats { if (cpuSpeeds[speed] == null) { cpuSpeeds[speed] = new LongSamplingCounter(mOnBatteryTimeBase); } - cpuSpeeds[speed].addCountLocked(appCpuTimeUs + final long deltaSpeedCount = appCpuTimeUs * clusterSpeedTimesMs[cluster][speed] - / totalCpuClustersTimeMs, onBattery); + / totalCpuClustersTimeMs; + cpuSpeeds[speed].addCountLocked(deltaSpeedCount, onBattery); + + if (powerAccumulator != null) { + powerAccumulator.addCpuClusterSpeedDurationsMs(u, cluster, + speed, deltaSpeedCount); + } } } } @@ -12750,13 +12929,18 @@ public class BatteryStatsImpl extends BatteryStats { /** * Take a snapshot of the cpu times spent by each uid in each freq and update the - * corresponding counters. + * corresponding counters. Will also add estimated power consumptions, if powerAccumulator + * data structure is provided. * * @param partialTimers The wakelock holders among which the cpu freq times will be distributed. + * @param onBattery whether or not this is onBattery + * @param onBatteryScreenOff whether or not this is onBattery with the screen off. + * @param powerAccumulator object to accumulate the estimated cluster charge consumption. */ @VisibleForTesting public void readKernelUidCpuFreqTimesLocked(@Nullable ArrayList<StopwatchTimer> partialTimers, - boolean onBattery, boolean onBatteryScreenOff) { + boolean onBattery, boolean onBatteryScreenOff, + @Nullable CpuDeltaPowerAccumulator powerAccumulator) { final boolean perClusterTimesAvailable = mCpuUidFreqTimeReader.perClusterTimesAvailable(); final int numWakelocks = partialTimers == null ? 0 : partialTimers.size(); @@ -12765,7 +12949,9 @@ public class BatteryStatsImpl extends BatteryStats { final long startTimeMs = mClocks.uptimeMillis(); final long elapsedRealtimeMs = mClocks.elapsedRealtime(); final List<Integer> uidsToRemove = new ArrayList<>(); - mCpuUidFreqTimeReader.readDelta(false, (uid, cpuFreqTimeMs) -> { + // If power is being accumulated for attribution, data needs to be read immediately. + final boolean forceRead = powerAccumulator != null; + mCpuUidFreqTimeReader.readDelta(forceRead, (uid, cpuFreqTimeMs) -> { uid = mapUid(uid); if (Process.isIsolated(uid)) { uidsToRemove.add(uid); @@ -12828,6 +13014,11 @@ public class BatteryStatsImpl extends BatteryStats { appAllocationUs = cpuFreqTimeMs[freqIndex] * 1000; } cpuTimesUs[speed].addCountLocked(appAllocationUs, onBattery); + + if (powerAccumulator != null) { + powerAccumulator.addCpuClusterSpeedDurationsMs(u, cluster, + speed, appAllocationUs / 1000); + } freqIndex++; } } @@ -12868,6 +13059,11 @@ public class BatteryStatsImpl extends BatteryStats { mWakeLockAllocationsUs[cluster][speed] / (numWakelocks - i); cpuTimeUs[speed].addCountLocked(allocationUs, onBattery); mWakeLockAllocationsUs[cluster][speed] -= allocationUs; + + if (powerAccumulator != null) { + powerAccumulator.addCpuClusterSpeedDurationsMs(u, cluster, + speed, allocationUs / 1000); + } } } } @@ -12910,14 +13106,21 @@ public class BatteryStatsImpl extends BatteryStats { /** * Take a snapshot of the cpu cluster times spent by each uid and update the corresponding - * counters. + * counters. Will also add estimated power consumptions, if powerAccumulator data structure + * is provided. + * + * @param onBattery whether or not this is onBattery + * @param powerAccumulator object to accumulate the estimated cluster charge consumption. */ @VisibleForTesting - public void readKernelUidCpuClusterTimesLocked(boolean onBattery) { + public void readKernelUidCpuClusterTimesLocked(boolean onBattery, + @Nullable CpuDeltaPowerAccumulator powerAccumulator) { final long startTimeMs = mClocks.uptimeMillis(); final long elapsedRealtimeMs = mClocks.elapsedRealtime(); final List<Integer> uidsToRemove = new ArrayList<>(); - mCpuUidClusterTimeReader.readDelta(false, (uid, cpuClusterTimesMs) -> { + // If power is being accumulated for attribution, data needs to be read immediately. + final boolean forceRead = powerAccumulator != null; + mCpuUidClusterTimeReader.readDelta(forceRead, (uid, cpuClusterTimesMs) -> { uid = mapUid(uid); if (Process.isIsolated(uid)) { uidsToRemove.add(uid); @@ -12931,6 +13134,10 @@ public class BatteryStatsImpl extends BatteryStats { } final Uid u = getUidStatsLocked(uid, elapsedRealtimeMs, startTimeMs); u.mCpuClusterTimesMs.addCountLocked(cpuClusterTimesMs, onBattery); + + if (powerAccumulator != null) { + powerAccumulator.addCpuClusterDurationsMs(u, cpuClusterTimesMs); + } }); for (int uid : uidsToRemove) { mCpuUidClusterTimeReader.removeUid(uid); @@ -13197,8 +13404,9 @@ public class BatteryStatsImpl extends BatteryStats { } } + mBatteryVoltageMv = voltageMv; + if (ENABLE_FOREGROUND_STATS_COLLECTION) { - mBatteryVoltageMv = voltageMv; if (onBattery) { final long energyNwh = (voltageMv * (long) chargeUah); final long energyDelta = mLastBatteryEnergyCapacityNwh - energyNwh; @@ -13982,9 +14190,9 @@ public class BatteryStatsImpl extends BatteryStats { registerUsbStateReceiver(context); } /** - * Initialize the measured energy stats data structures. + * Initialize the measured charge stats data structures. * - * @param supportedStandardBuckets boolean array indicating which {@link StandardEnergyBucket}s + * @param supportedStandardBuckets boolean array indicating which {@link StandardPowerBucket}s * are currently supported. * If null, none are supported (regardless of numCustomBuckets). * @param numCustomBuckets number of custom (OTHER) EnergyConsumers on this device @@ -13997,27 +14205,39 @@ public class BatteryStatsImpl extends BatteryStats { if (supportedStandardBuckets == null) { if (mGlobalMeasuredEnergyStats != null) { - // Measured energy buckets no longer supported, wipe out the existing data. + // Measured energy no longer supported, wipe out the existing data. supportedBucketMismatch = true; } - } else if (mGlobalMeasuredEnergyStats == null) { - mGlobalMeasuredEnergyStats - = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets); - return; } else { - supportedBucketMismatch = !mGlobalMeasuredEnergyStats.isSupportEqualTo( - supportedStandardBuckets, numCustomBuckets); + if (mGlobalMeasuredEnergyStats == null) { + mGlobalMeasuredEnergyStats = + new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets); + return; + } else { + supportedBucketMismatch = !mGlobalMeasuredEnergyStats.isSupportEqualTo( + supportedStandardBuckets, numCustomBuckets); + } + + if (supportedStandardBuckets[MeasuredEnergyStats.POWER_BUCKET_CPU]) { + mCpuPowerCalculator = new CpuPowerCalculator(mPowerProfile); + } } if (supportedBucketMismatch) { - mGlobalMeasuredEnergyStats = supportedStandardBuckets == null ? - null : new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets); - // Supported energy buckets changed since last boot. + mGlobalMeasuredEnergyStats = supportedStandardBuckets == null + ? null : new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets); + // Supported power buckets changed since last boot. // Existing data is no longer reliable. resetAllStatsLocked(SystemClock.uptimeMillis(), SystemClock.elapsedRealtime()); } } + /** Get the last known Battery voltage (in millivolts), returns -1 if unknown */ + @GuardedBy("this") + public int getBatteryVoltageMvLocked() { + return mBatteryVoltageMv; + } + @VisibleForTesting public final class Constants extends ContentObserver { public static final String KEY_TRACK_CPU_TIMES_BY_PROC_STATE @@ -14293,11 +14513,11 @@ public class BatteryStatsImpl extends BatteryStats { } /** - * Dump measured energy stats + * Dump measured charge stats */ @GuardedBy("this") public void dumpMeasuredEnergyStatsLocked(PrintWriter pw) { - pw.printf("On battery measured energy stats (microjoules) \n"); + pw.printf("On battery measured charge stats (microcoulombs) \n"); if (mGlobalMeasuredEnergyStats == null) { pw.printf(" Not supported on this device.\n"); return; @@ -14314,7 +14534,7 @@ public class BatteryStatsImpl extends BatteryStats { } } - /** Dump measured energy stats for the given uid */ + /** Dump measured charge stats for the given uid */ @GuardedBy("this") private void dumpMeasuredEnergyStatsLocked(PrintWriter pw, String name, MeasuredEnergyStats stats) { diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java index 15b584d1fd06..6dd612e4c9bf 100644 --- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java +++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java @@ -55,7 +55,7 @@ public class BatteryUsageStatsProvider { 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)); @@ -123,10 +123,10 @@ public class BatteryUsageStatsProvider { final long realtimeUs = mStats.mClocks.elapsedRealtime() * 1000; final long uptimeUs = mStats.mClocks.uptimeMillis() * 1000; - final long[] customMeasuredEnergiesMicroJoules = - mStats.getCustomMeasuredEnergiesMicroJoules(); - final int customPowerComponentCount = customMeasuredEnergiesMicroJoules != null - ? customMeasuredEnergiesMicroJoules.length + final long[] customMeasuredChargesUC = + mStats.getCustomConsumerMeasuredBatteryConsumptionUC(); + final int customPowerComponentCount = customMeasuredChargesUC != null + ? customMeasuredChargesUC.length : 0; // TODO(b/174186358): read extra time component number from configuration diff --git a/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java b/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java index 2606d80eaa09..9941e30f5d1c 100644 --- a/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java +++ b/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java @@ -35,7 +35,7 @@ public class CustomMeasuredPowerCalculator extends PowerCalculator { long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { super.calculate(builder, batteryStats, rawRealtimeUs, rawUptimeUs, query); final double[] customMeasuredPowerMah = calculateMeasuredEnergiesMah( - batteryStats.getCustomMeasuredEnergiesMicroJoules()); + batteryStats.getCustomConsumerMeasuredBatteryConsumptionUC()); if (customMeasuredPowerMah != null) { final SystemBatteryConsumer.Builder systemBatteryConsumerBuilder = builder.getOrCreateSystemBatteryConsumerBuilder( @@ -52,7 +52,7 @@ public class CustomMeasuredPowerCalculator extends PowerCalculator { protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u, long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { final double[] customMeasuredPowerMah = calculateMeasuredEnergiesMah( - u.getCustomMeasuredEnergiesMicroJoules()); + u.getCustomConsumerMeasuredBatteryConsumptionUC()); if (customMeasuredPowerMah != null) { for (int i = 0; i < customMeasuredPowerMah.length; i++) { app.setConsumedPowerForCustomComponent( @@ -65,20 +65,20 @@ public class CustomMeasuredPowerCalculator extends PowerCalculator { @Override protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs, long rawUptimeUs, int statsType) { - updateCustomMeasuredPowerMah(app, u.getCustomMeasuredEnergiesMicroJoules()); + updateCustomMeasuredPowerMah(app, u.getCustomConsumerMeasuredBatteryConsumptionUC()); } - private void updateCustomMeasuredPowerMah(BatterySipper sipper, long[] measuredEnergiesUJ) { - sipper.customMeasuredPowerMah = calculateMeasuredEnergiesMah(measuredEnergiesUJ); + private void updateCustomMeasuredPowerMah(BatterySipper sipper, long[] measuredChargeUC) { + sipper.customMeasuredPowerMah = calculateMeasuredEnergiesMah(measuredChargeUC); } - private double[] calculateMeasuredEnergiesMah(long[] measuredEnergiesUJ) { - if (measuredEnergiesUJ == null) { + private double[] calculateMeasuredEnergiesMah(long[] measuredChargeUC) { + if (measuredChargeUC == null) { return null; } - final double[] measuredEnergiesMah = new double[measuredEnergiesUJ.length]; - for (int i = 0; i < measuredEnergiesUJ.length; i++) { - measuredEnergiesMah[i] = uJtoMah(measuredEnergiesUJ[i]); + final double[] measuredEnergiesMah = new double[measuredChargeUC.length]; + for (int i = 0; i < measuredChargeUC.length; i++) { + measuredEnergiesMah[i] = uCtoMah(measuredChargeUC[i]); } return measuredEnergiesMah; } diff --git a/core/java/com/android/internal/os/OWNERS b/core/java/com/android/internal/os/OWNERS index 0aa54f556b92..3f01ebb1afe7 100644 --- a/core/java/com/android/internal/os/OWNERS +++ b/core/java/com/android/internal/os/OWNERS @@ -6,6 +6,7 @@ per-file *Cpu* = file:CPU_OWNERS 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/PowerCalculator.java b/core/java/com/android/internal/os/PowerCalculator.java index fe4fb7afa1f5..72385e273cf0 100644 --- a/core/java/com/android/internal/os/PowerCalculator.java +++ b/core/java/com/android/internal/os/PowerCalculator.java @@ -30,6 +30,8 @@ import java.util.Locale; */ public abstract class PowerCalculator { + protected static final double MILLIAMPHOUR_PER_MICROCOULOMB = 1.0 / 1000.0 / 60.0 / 60.0; + /** * Attributes the total amount of power used by this subsystem to various consumers such * as apps. @@ -115,12 +117,12 @@ public abstract class PowerCalculator { /** * Returns either the measured energy converted to mAh or a usage-based estimate. */ - protected static double getMeasuredOrEstimatedPower(long measuredEnergyUj, + protected static double getMeasuredOrEstimatedPower(long measuredEnergyUC, UsageBasedPowerEstimator powerEstimator, long durationMs, boolean forceUsePowerProfileModel) { - if (measuredEnergyUj != BatteryStats.ENERGY_DATA_UNAVAILABLE + if (measuredEnergyUC != BatteryStats.POWER_DATA_UNAVAILABLE && !forceUsePowerProfileModel) { - return uJtoMah(measuredEnergyUj); + return uCtoMah(measuredEnergyUC); } return powerEstimator.calculatePower(durationMs); } @@ -156,13 +158,7 @@ public abstract class PowerCalculator { return String.format(Locale.ENGLISH, format, power); } - static double uJtoMah(long energyUJ) { - if (energyUJ == 0) { - return 0; - } - - // TODO(b/173765509): Convert properly. This is mJ / V * (h/3600s) = mAh with V = 3.7 fixed. - // Leaving for later since desired units of energy have yet to be decided - return energyUJ / 1000.0 / 3.7 / 3600; + static double uCtoMah(long chargeUC) { + return chargeUC * MILLIAMPHOUR_PER_MICROCOULOMB; } } diff --git a/core/java/com/android/internal/os/ScreenPowerCalculator.java b/core/java/com/android/internal/os/ScreenPowerCalculator.java index 5dca8d5e70fa..d94bb31f58bf 100644 --- a/core/java/com/android/internal/os/ScreenPowerCalculator.java +++ b/core/java/com/android/internal/os/ScreenPowerCalculator.java @@ -141,9 +141,9 @@ public class ScreenPowerCalculator extends PowerCalculator { statsType); if (!forceUsePowerProfileModel) { - final long energyUJ = batteryStats.getScreenOnEnergy(); - if (energyUJ != BatteryStats.ENERGY_DATA_UNAVAILABLE) { - totalPowerAndDuration.powerMah = uJtoMah(energyUJ); + final long chargeUC = batteryStats.getScreenOnMeasuredBatteryConsumptionUC(); + if (chargeUC != BatteryStats.POWER_DATA_UNAVAILABLE) { + totalPowerAndDuration.powerMah = uCtoMah(chargeUC); return true; } } @@ -157,14 +157,14 @@ public class ScreenPowerCalculator extends PowerCalculator { BatteryStats.Uid u, long rawRealtimeUs) { appPowerAndDuration.durationMs = getProcessForegroundTimeMs(u, rawRealtimeUs); - final long energyUJ = u.getScreenOnEnergy(); - if (energyUJ < 0) { + final long chargeUC = u.getScreenOnMeasuredBatteryConsumptionUC(); + if (chargeUC < 0) { Slog.wtf(TAG, "Screen energy not supported, so calculateApp shouldn't de called"); appPowerAndDuration.powerMah = 0; return; } - appPowerAndDuration.powerMah = uJtoMah(energyUJ); + appPowerAndDuration.powerMah = uCtoMah(chargeUC); } private long calculateDuration(BatteryStats batteryStats, long rawRealtimeUs, int statsType) { diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index 6b1d408bee9a..8b5a62ada1c5 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -202,7 +202,7 @@ public final class Zygote { 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 @@ public final class Zygote { * @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 @@ public final class Zygote { 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 @@ public final class Zygote { 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 @@ public final class Zygote { * 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 @@ public final class Zygote { 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 @@ public final class Zygote { 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 65b454d47db2..ef8398294c5b 100644 --- a/core/java/com/android/internal/os/ZygoteArguments.java +++ b/core/java/com/android/internal/os/ZygoteArguments.java @@ -230,7 +230,7 @@ class ZygoteArguments { * 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 @@ class ZygoteArguments { } } 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 37c75907061c..1673362028f9 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -265,7 +265,7 @@ class ZygoteConnection { 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/java/com/android/internal/power/MeasuredEnergyStats.java b/core/java/com/android/internal/power/MeasuredEnergyStats.java index d49203c731e9..e3d5464ca413 100644 --- a/core/java/com/android/internal/power/MeasuredEnergyStats.java +++ b/core/java/com/android/internal/power/MeasuredEnergyStats.java @@ -17,7 +17,7 @@ package com.android.internal.power; -import static android.os.BatteryStats.ENERGY_DATA_UNAVAILABLE; +import static android.os.BatteryStats.POWER_DATA_UNAVAILABLE; import android.annotation.IntDef; import android.annotation.NonNull; @@ -34,8 +34,8 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** - * Tracks the measured energy usage of various subsystems according to their - * {@link StandardEnergyBucket} or custom energy bucket (which is tied to + * Tracks the measured charge consumption of various subsystems according to their + * {@link StandardPowerBucket} or custom power bucket (which is tied to * {@link android.hardware.power.stats.EnergyConsumer.ordinal}). * * This class doesn't use a TimeBase, and instead requires manually decisions about when to @@ -46,51 +46,53 @@ public class MeasuredEnergyStats { private static final String TAG = "MeasuredEnergyStats"; // Note: {@link com.android.internal.os.BatteryStatsImpl#VERSION} MUST be updated if standard - // energy bucket integers are modified/added/removed. - public static final int ENERGY_BUCKET_UNKNOWN = -1; - public static final int ENERGY_BUCKET_SCREEN_ON = 0; - public static final int ENERGY_BUCKET_SCREEN_DOZE = 1; - public static final int ENERGY_BUCKET_SCREEN_OTHER = 2; - public static final int NUMBER_STANDARD_ENERGY_BUCKETS = 3; // Buckets above this are custom. - - @IntDef(prefix = {"ENERGY_BUCKET_"}, value = { - ENERGY_BUCKET_UNKNOWN, - ENERGY_BUCKET_SCREEN_ON, - ENERGY_BUCKET_SCREEN_DOZE, - ENERGY_BUCKET_SCREEN_OTHER, + // power bucket integers are modified/added/removed. + public static final int POWER_BUCKET_UNKNOWN = -1; + public static final int POWER_BUCKET_SCREEN_ON = 0; + public static final int POWER_BUCKET_SCREEN_DOZE = 1; + public static final int POWER_BUCKET_SCREEN_OTHER = 2; + public static final int POWER_BUCKET_CPU = 3; + public static final int NUMBER_STANDARD_POWER_BUCKETS = 4; // Buckets above this are custom. + + @IntDef(prefix = {"POWER_BUCKET_"}, value = { + POWER_BUCKET_UNKNOWN, + POWER_BUCKET_SCREEN_ON, + POWER_BUCKET_SCREEN_DOZE, + POWER_BUCKET_SCREEN_OTHER, + POWER_BUCKET_CPU, }) @Retention(RetentionPolicy.SOURCE) - public @interface StandardEnergyBucket { + public @interface StandardPowerBucket { } /** - * Total energy (in microjoules) that an energy bucket (including both - * {@link StandardEnergyBucket} and custom buckets) has accumulated since the last reset. - * Values MUST be non-zero or ENERGY_DATA_UNAVAILABLE. Accumulation only occurs + * Total charge (in microcoulombs) that a power bucket (including both + * {@link StandardPowerBucket} and custom buckets) has accumulated since the last reset. + * Values MUST be non-zero or POWER_DATA_UNAVAILABLE. Accumulation only occurs * while the necessary conditions are satisfied (e.g. on battery). * - * Energy for both {@link StandardEnergyBucket}s and custom energy buckets are stored in this + * Charge for both {@link StandardPowerBucket}s and custom power buckets are stored in this * array, and may internally both referred to as 'buckets'. This is an implementation detail; * externally, we differentiate between these two data sources. * * Warning: Long array is used for access speed. If the number of supported subsystems * becomes large, consider using an alternate data structure such as a SparseLongArray. */ - private final long[] mAccumulatedEnergiesMicroJoules; + private final long[] mAccumulatedChargeMicroCoulomb; /** - * Creates a MeasuredEnergyStats set to support the provided energy buckets. - * supportedStandardBuckets must be of size {@link #NUMBER_STANDARD_ENERGY_BUCKETS}. - * numCustomBuckets >= 0 is the number of (non-standard) custom energy buckets on the device. + * Creates a MeasuredEnergyStats set to support the provided power buckets. + * supportedStandardBuckets must be of size {@link #NUMBER_STANDARD_POWER_BUCKETS}. + * numCustomBuckets >= 0 is the number of (non-standard) custom power buckets on the device. */ public MeasuredEnergyStats(boolean[] supportedStandardBuckets, int numCustomBuckets) { - final int numTotalBuckets = NUMBER_STANDARD_ENERGY_BUCKETS + numCustomBuckets; - mAccumulatedEnergiesMicroJoules = new long[numTotalBuckets]; - // Initialize to all zeros where supported, otherwise ENERGY_DATA_UNAVAILABLE. + final int numTotalBuckets = NUMBER_STANDARD_POWER_BUCKETS + numCustomBuckets; + mAccumulatedChargeMicroCoulomb = new long[numTotalBuckets]; + // Initialize to all zeros where supported, otherwise POWER_DATA_UNAVAILABLE. // All custom buckets are, by definition, supported, so their values stay at 0. - for (int stdBucket = 0; stdBucket < NUMBER_STANDARD_ENERGY_BUCKETS; stdBucket++) { + for (int stdBucket = 0; stdBucket < NUMBER_STANDARD_POWER_BUCKETS; stdBucket++) { if (!supportedStandardBuckets[stdBucket]) { - mAccumulatedEnergiesMicroJoules[stdBucket] = ENERGY_DATA_UNAVAILABLE; + mAccumulatedChargeMicroCoulomb[stdBucket] = POWER_DATA_UNAVAILABLE; } } } @@ -101,12 +103,12 @@ public class MeasuredEnergyStats { */ private MeasuredEnergyStats(MeasuredEnergyStats template) { final int numIndices = template.getNumberOfIndices(); - mAccumulatedEnergiesMicroJoules = new long[numIndices]; - // Initialize to all zeros where supported, otherwise ENERGY_DATA_UNAVAILABLE. + mAccumulatedChargeMicroCoulomb = new long[numIndices]; + // Initialize to all zeros where supported, otherwise POWER_DATA_UNAVAILABLE. // All custom buckets are, by definition, supported, so their values stay at 0. - for (int stdBucket = 0; stdBucket < NUMBER_STANDARD_ENERGY_BUCKETS; stdBucket++) { + for (int stdBucket = 0; stdBucket < NUMBER_STANDARD_POWER_BUCKETS; stdBucket++) { if (!template.isIndexSupported(stdBucket)) { - mAccumulatedEnergiesMicroJoules[stdBucket] = ENERGY_DATA_UNAVAILABLE; + mAccumulatedChargeMicroCoulomb[stdBucket] = POWER_DATA_UNAVAILABLE; } } } @@ -124,20 +126,20 @@ public class MeasuredEnergyStats { * See {@link #createAndReadSummaryFromParcel(Parcel, MeasuredEnergyStats)}. */ private MeasuredEnergyStats(int numIndices) { - mAccumulatedEnergiesMicroJoules = new long[numIndices]; + mAccumulatedChargeMicroCoulomb = new long[numIndices]; } /** Construct from parcel. */ public MeasuredEnergyStats(Parcel in) { final int size = in.readInt(); - mAccumulatedEnergiesMicroJoules = new long[size]; - in.readLongArray(mAccumulatedEnergiesMicroJoules); + mAccumulatedChargeMicroCoulomb = new long[size]; + in.readLongArray(mAccumulatedChargeMicroCoulomb); } /** Write to parcel */ public void writeToParcel(Parcel out) { - out.writeInt(mAccumulatedEnergiesMicroJoules.length); - out.writeLongArray(mAccumulatedEnergiesMicroJoules); + out.writeInt(mAccumulatedChargeMicroCoulomb.length); + out.writeLongArray(mAccumulatedChargeMicroCoulomb); } /** @@ -153,11 +155,11 @@ public class MeasuredEnergyStats { final int numWrittenEntries = in.readInt(); for (int entry = 0; entry < numWrittenEntries; entry++) { final int index = in.readInt(); - final long energyUJ = in.readLong(); + final long chargeUC = in.readLong(); if (overwriteAvailability) { - mAccumulatedEnergiesMicroJoules[index] = energyUJ; + mAccumulatedChargeMicroCoulomb[index] = chargeUC; } else { - setValueIfSupported(index, energyUJ); + setValueIfSupported(index, chargeUC); } } } @@ -172,14 +174,14 @@ public class MeasuredEnergyStats { final int posOfNumWrittenEntries = out.dataPosition(); out.writeInt(0); int numWrittenEntries = 0; - // Write only the supported buckets (with non-zero energy, if applicable). - for (int index = 0; index < mAccumulatedEnergiesMicroJoules.length; index++) { - final long energy = mAccumulatedEnergiesMicroJoules[index]; - if (energy < 0) continue; - if (energy == 0 && skipZero) continue; + // Write only the supported buckets (with non-zero charge, if applicable). + for (int index = 0; index < mAccumulatedChargeMicroCoulomb.length; index++) { + final long charge = mAccumulatedChargeMicroCoulomb[index]; + if (charge < 0) continue; + if (charge == 0 && skipZero) continue; out.writeInt(index); - out.writeLong(mAccumulatedEnergiesMicroJoules[index]); + out.writeLong(charge); numWrittenEntries++; } final int currPos = out.dataPosition(); @@ -190,80 +192,82 @@ public class MeasuredEnergyStats { /** Get number of possible buckets, including both standard and custom ones. */ private int getNumberOfIndices() { - return mAccumulatedEnergiesMicroJoules.length; + return mAccumulatedChargeMicroCoulomb.length; } - /** Updates the given standard energy bucket with the given energy if accumulate is true. */ - public void updateStandardBucket(@StandardEnergyBucket int bucket, long energyDeltaUJ) { + + /** Updates the given standard power bucket with the given charge if accumulate is true. */ + public void updateStandardBucket(@StandardPowerBucket int bucket, long chargeDeltaUC) { checkValidStandardBucket(bucket); - updateEntry(bucket, energyDeltaUJ); + updateEntry(bucket, chargeDeltaUC); } - /** Updates the given custom energy bucket with the given energy if accumulate is true. */ - public void updateCustomBucket(int customBucket, long energyDeltaUJ) { + /** Updates the given custom power bucket with the given charge if accumulate is true. */ + public void updateCustomBucket(int customBucket, long chargeDeltaUC) { if (!isValidCustomBucket(customBucket)) { Slog.e(TAG, "Attempted to update invalid custom bucket " + customBucket); return; } final int index = customBucketToIndex(customBucket); - updateEntry(index, energyDeltaUJ); + updateEntry(index, chargeDeltaUC); } - /** Updates the given index with the given energy if accumulate is true. */ - private void updateEntry(int index, long energyDeltaUJ) { - if (mAccumulatedEnergiesMicroJoules[index] >= 0L) { - mAccumulatedEnergiesMicroJoules[index] += energyDeltaUJ; + /** Updates the given index with the given charge if accumulate is true. */ + private void updateEntry(int index, long chargeDeltaUC) { + if (mAccumulatedChargeMicroCoulomb[index] >= 0L) { + mAccumulatedChargeMicroCoulomb[index] += chargeDeltaUC; } else { - Slog.wtf(TAG, "Attempting to add " + energyDeltaUJ + " to unavailable bucket " + Slog.wtf(TAG, "Attempting to add " + chargeDeltaUC + " to unavailable bucket " + getBucketName(index) + " whose value was " - + mAccumulatedEnergiesMicroJoules[index]); + + mAccumulatedChargeMicroCoulomb[index]); } } /** - * Return accumulated energy (in microjoules) for a standard energy bucket since last reset. - * Returns {@link android.os.BatteryStats#ENERGY_DATA_UNAVAILABLE} if this data is unavailable. - * @throws IllegalArgumentException if no such {@link StandardEnergyBucket}. + * Return accumulated charge (in microcouloumb) for a standard power bucket since last reset. + * Returns {@link android.os.BatteryStats#POWER_DATA_UNAVAILABLE} if this data is unavailable. + * @throws IllegalArgumentException if no such {@link StandardPowerBucket}. */ - public long getAccumulatedStandardBucketEnergy(@StandardEnergyBucket int bucket) { + public long getAccumulatedStandardBucketCharge(@StandardPowerBucket int bucket) { checkValidStandardBucket(bucket); - return mAccumulatedEnergiesMicroJoules[bucket]; + return mAccumulatedChargeMicroCoulomb[bucket]; } /** - * Return accumulated energy (in microjoules) for the a custom energy bucket since last reset. - * Returns {@link android.os.BatteryStats#ENERGY_DATA_UNAVAILABLE} if this data is unavailable. + * Return accumulated charge (in microcoulomb) for the a custom power bucket since last + * reset. + * Returns {@link android.os.BatteryStats#POWER_DATA_UNAVAILABLE} if this data is unavailable. */ @VisibleForTesting - public long getAccumulatedCustomBucketEnergy(int customBucket) { + public long getAccumulatedCustomBucketCharge(int customBucket) { if (!isValidCustomBucket(customBucket)) { - return ENERGY_DATA_UNAVAILABLE; + return POWER_DATA_UNAVAILABLE; } - return mAccumulatedEnergiesMicroJoules[customBucketToIndex(customBucket)]; + return mAccumulatedChargeMicroCoulomb[customBucketToIndex(customBucket)]; } /** - * Return accumulated energies (in microjoules) for all custom energy buckets since last reset. + * Return accumulated charge (in microcoulomb) for all custom power buckets since last reset. */ - public @NonNull long[] getAccumulatedCustomBucketEnergies() { - final long[] energies = new long[getNumberCustomEnergyBuckets()]; - for (int bucket = 0; bucket < energies.length; bucket++) { - energies[bucket] = mAccumulatedEnergiesMicroJoules[customBucketToIndex(bucket)]; + public @NonNull long[] getAccumulatedCustomBucketCharges() { + final long[] charges = new long[getNumberCustomPowerBuckets()]; + for (int bucket = 0; bucket < charges.length; bucket++) { + charges[bucket] = mAccumulatedChargeMicroCoulomb[customBucketToIndex(bucket)]; } - return energies; + return charges; } /** - * Map {@link android.view.Display} STATE_ to corresponding {@link StandardEnergyBucket}. + * Map {@link android.view.Display} STATE_ to corresponding {@link StandardPowerBucket}. */ - public static @StandardEnergyBucket int getDisplayEnergyBucket(int screenState) { + public static @StandardPowerBucket int getDisplayPowerBucket(int screenState) { if (Display.isOnState(screenState)) { - return ENERGY_BUCKET_SCREEN_ON; + return POWER_BUCKET_SCREEN_ON; } if (Display.isDozeState(screenState)) { - return ENERGY_BUCKET_SCREEN_DOZE; + return POWER_BUCKET_SCREEN_DOZE; } - return ENERGY_BUCKET_SCREEN_OTHER; + return POWER_BUCKET_SCREEN_OTHER; } /** @@ -280,9 +284,9 @@ public class MeasuredEnergyStats { // Check if any MeasuredEnergyStats exists on the parcel if (arraySize == 0) return null; - final int numCustomBuckets = arraySize - NUMBER_STANDARD_ENERGY_BUCKETS; + final int numCustomBuckets = arraySize - NUMBER_STANDARD_POWER_BUCKETS; final MeasuredEnergyStats stats = new MeasuredEnergyStats( - new boolean[NUMBER_STANDARD_ENERGY_BUCKETS], numCustomBuckets); + new boolean[NUMBER_STANDARD_POWER_BUCKETS], numCustomBuckets); stats.readSummaryFromParcel(in, true); return stats; } @@ -337,8 +341,8 @@ public class MeasuredEnergyStats { /** Returns true iff any of the buckets are supported and non-zero. */ private boolean containsInterestingData() { - for (int index = 0; index < mAccumulatedEnergiesMicroJoules.length; index++) { - if (mAccumulatedEnergiesMicroJoules[index] > 0) return true; + for (int index = 0; index < mAccumulatedChargeMicroCoulomb.length; index++) { + if (mAccumulatedChargeMicroCoulomb[index] > 0) return true; } return false; } @@ -359,7 +363,7 @@ public class MeasuredEnergyStats { stats.writeSummaryToParcel(dest, skipZero); } - /** Reset accumulated energy. */ + /** Reset accumulated charges. */ private void reset() { final int numIndices = getNumberOfIndices(); for (int index = 0; index < numIndices; index++) { @@ -367,42 +371,42 @@ public class MeasuredEnergyStats { } } - /** Reset accumulated energy of the given stats. */ + /** Reset accumulated charges of the given stats. */ public static void resetIfNotNull(@Nullable MeasuredEnergyStats stats) { if (stats != null) stats.reset(); } /** If the index is AVAILABLE, overwrite its value; otherwise leave it as UNAVAILABLE. */ private void setValueIfSupported(int index, long value) { - if (mAccumulatedEnergiesMicroJoules[index] != ENERGY_DATA_UNAVAILABLE) { - mAccumulatedEnergiesMicroJoules[index] = value; + if (mAccumulatedChargeMicroCoulomb[index] != POWER_DATA_UNAVAILABLE) { + mAccumulatedChargeMicroCoulomb[index] = value; } } /** - * Check if measuring the energy of the given bucket is supported by this device. - * @throws IllegalArgumentException if not a valid {@link StandardEnergyBucket}. + * Check if measuring the charge consumption of the given bucket is supported by this device. + * @throws IllegalArgumentException if not a valid {@link StandardPowerBucket}. */ - public boolean isStandardBucketSupported(@StandardEnergyBucket int bucket) { + public boolean isStandardBucketSupported(@StandardPowerBucket int bucket) { checkValidStandardBucket(bucket); return isIndexSupported(bucket); } private boolean isIndexSupported(int index) { - return mAccumulatedEnergiesMicroJoules[index] != ENERGY_DATA_UNAVAILABLE; + return mAccumulatedChargeMicroCoulomb[index] != POWER_DATA_UNAVAILABLE; } - /** Check if the supported energy buckets are precisely those given. */ + /** Check if the supported power buckets are precisely those given. */ public boolean isSupportEqualTo( @NonNull boolean[] queriedStandardBuckets, int numCustomBuckets) { final int numBuckets = getNumberOfIndices(); // TODO(b/178504428): Detect whether custom buckets have changed qualitatively, not just // quantitatively, and treat as mismatch if so. - if (numBuckets != NUMBER_STANDARD_ENERGY_BUCKETS + numCustomBuckets) { + if (numBuckets != NUMBER_STANDARD_POWER_BUCKETS + numCustomBuckets) { return false; } - for (int stdBucket = 0; stdBucket < NUMBER_STANDARD_ENERGY_BUCKETS; stdBucket++) { + for (int stdBucket = 0; stdBucket < NUMBER_STANDARD_POWER_BUCKETS; stdBucket++) { if (isStandardBucketSupported(stdBucket) != queriedStandardBuckets[stdBucket]) { return false; } @@ -413,14 +417,14 @@ public class MeasuredEnergyStats { /** Dump debug data. */ public void dump(PrintWriter pw) { pw.print(" "); - for (int index = 0; index < mAccumulatedEnergiesMicroJoules.length; index++) { + for (int index = 0; index < mAccumulatedChargeMicroCoulomb.length; index++) { pw.print(getBucketName(index)); pw.print(" : "); - pw.print(mAccumulatedEnergiesMicroJoules[index]); + pw.print(mAccumulatedChargeMicroCoulomb[index]); if (!isIndexSupported(index)) { pw.print(" (unsupported)"); } - if (index != mAccumulatedEnergiesMicroJoules.length - 1) { + if (index != mAccumulatedChargeMicroCoulomb.length - 1) { pw.print(", "); } } @@ -433,38 +437,38 @@ public class MeasuredEnergyStats { */ private static String getBucketName(int index) { if (isValidStandardBucket(index)) { - return DebugUtils.valueToString(MeasuredEnergyStats.class, "ENERGY_BUCKET_", index); + return DebugUtils.valueToString(MeasuredEnergyStats.class, "POWER_BUCKET_", index); } return "CUSTOM_" + indexToCustomBucket(index); } - /** Get the number of custom energy buckets on this device. */ - public int getNumberCustomEnergyBuckets() { - return mAccumulatedEnergiesMicroJoules.length - NUMBER_STANDARD_ENERGY_BUCKETS; + /** Get the number of custom power buckets on this device. */ + public int getNumberCustomPowerBuckets() { + return mAccumulatedChargeMicroCoulomb.length - NUMBER_STANDARD_POWER_BUCKETS; } private static int customBucketToIndex(int customBucket) { - return customBucket + NUMBER_STANDARD_ENERGY_BUCKETS; + return customBucket + NUMBER_STANDARD_POWER_BUCKETS; } private static int indexToCustomBucket(int index) { - return index - NUMBER_STANDARD_ENERGY_BUCKETS; + return index - NUMBER_STANDARD_POWER_BUCKETS; } - private static void checkValidStandardBucket(@StandardEnergyBucket int bucket) { + private static void checkValidStandardBucket(@StandardPowerBucket int bucket) { if (!isValidStandardBucket(bucket)) { - throw new IllegalArgumentException("Illegal StandardEnergyBucket " + bucket); + throw new IllegalArgumentException("Illegal StandardPowerBucket " + bucket); } } - private static boolean isValidStandardBucket(@StandardEnergyBucket int bucket) { - return bucket >= 0 && bucket < NUMBER_STANDARD_ENERGY_BUCKETS; + private static boolean isValidStandardBucket(@StandardPowerBucket int bucket) { + return bucket >= 0 && bucket < NUMBER_STANDARD_POWER_BUCKETS; } /** Returns whether the given custom bucket is valid (exists) on this device. */ @VisibleForTesting public boolean isValidCustomBucket(int customBucket) { return customBucket >= 0 - && customBucketToIndex(customBucket) < mAccumulatedEnergiesMicroJoules.length; + && customBucketToIndex(customBucket) < mAccumulatedChargeMicroCoulomb.length; } } diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index fde48e86b0f3..2e25ea3601da 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -79,7 +79,7 @@ interface IStatusBarService in int notificationLocation, boolean modifiedBeforeSending); void onNotificationSettingsViewed(String key); void onNotificationBubbleChanged(String key, boolean isBubble, int flags); - void onBubbleNotificationSuppressionChanged(String key, boolean isSuppressed); + void onBubbleNotificationSuppressionChanged(String key, boolean isNotifSuppressed, boolean isBubbleSuppressed); void hideCurrentInputMethodForBubbles(); void grantInlineReplyUriPermission(String key, in Uri uri, in UserHandle user, String packageName); void clearInlineReplyUriPermissions(String key); diff --git a/core/jni/OWNERS b/core/jni/OWNERS index 35d1d7bd7946..f6629fd250f6 100644 --- a/core/jni/OWNERS +++ b/core/jni/OWNERS @@ -43,6 +43,7 @@ per-file android_os_HwRemoteBinder* = file:platform/system/libhwbinder:/OWNERS 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_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp index b0c575162b56..b207ad39edc3 100644 --- a/core/jni/android_content_res_ApkAssets.cpp +++ b/core/jni/android_content_res_ApkAssets.cpp @@ -353,14 +353,10 @@ static jlong NativeLoadEmpty(JNIEnv* env, jclass /*clazz*/, jint flags, jobject return reinterpret_cast<jlong>(apk_assets.release()); } -static void NativeDestroy(void* ptr) { +static void NativeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) { delete reinterpret_cast<ApkAssets*>(ptr); } -static jlong NativeGetFinalizer(JNIEnv* /*env*/, jclass /*clazz*/) { - return static_cast<jlong>(reinterpret_cast<uintptr_t>(&NativeDestroy)); -} - static jstring NativeGetAssetPath(JNIEnv* env, jclass /*clazz*/, jlong ptr) { auto apk_assets = reinterpret_cast<const ApkAssets*>(ptr); if (auto path = apk_assets->GetPath()) { @@ -477,7 +473,7 @@ static const JNINativeMethod gApkAssetsMethods[] = { {"nativeLoadFdOffsets", "(ILjava/io/FileDescriptor;Ljava/lang/String;JJILandroid/content/res/loader/AssetsProvider;)J", (void*)NativeLoadFromFdOffset}, - {"nativeGetFinalizer", "()J", (void*)NativeGetFinalizer}, + {"nativeDestroy", "(J)V", (void*)NativeDestroy}, {"nativeGetAssetPath", "(J)Ljava/lang/String;", (void*)NativeGetAssetPath}, {"nativeGetDebugName", "(J)Ljava/lang/String;", (void*)NativeGetDebugName}, {"nativeGetStringBlock", "(J)J", (void*)NativeGetStringBlock}, diff --git a/core/jni/android_view_SurfaceControlFpsListener.cpp b/core/jni/android_view_SurfaceControlFpsListener.cpp index 6fa12e510459..0b15acd77689 100644 --- a/core/jni/android_view_SurfaceControlFpsListener.cpp +++ b/core/jni/android_view_SurfaceControlFpsListener.cpp @@ -84,11 +84,9 @@ void nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) { 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 @@ const JNINativeMethod gMethods[] = { /* 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 bcfb06b15ab8..836074f1d5f7 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 insertPackagesToMergedList(JNIEnv* env, } 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) { - - 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); + 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); - 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 @@ static void BindMountStorageDirs(JNIEnv* env, jobjectArray pkg_data_info_list, } // 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); + + // Keep capabilities across UID change, unless we're staying root. + if (uid != 0) { + EnableKeepCapabilities(fail_fn); + } - 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); + SetInheritable(permitted_capabilities, fail_fn); - // Keep capabilities across UID change, unless we're staying root. - if (uid != 0) { - EnableKeepCapabilities(fail_fn); - } + DropCapabilitiesBoundingSet(fail_fn); - SetInheritable(permitted_capabilities, 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()); - DropCapabilitiesBoundingSet(fail_fn); + MountEmulatedStorage(uid, mount_external, need_pre_initialize_native_bridge, 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()); + // Make sure app is running in its own mount namespace before isolating its data directories. + ensureInAppMountNamespace(fail_fn); - MountEmulatedStorage(uid, mount_external, need_pre_initialize_native_bridge, 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, 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); + } + // 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); + } - // Make sure app is running in its own mount namespace before isolating its data directories. - ensureInAppMountNamespace(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)); + } + } - // 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); - } + SetGids(env, gids, is_child_zygote, fail_fn); + SetRLimits(env, rlimits, 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)); + 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()); } - } - SetGids(env, gids, is_child_zygote, fail_fn); - SetRLimits(env, rlimits, 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()); - } + if (setresgid(gid, gid, gid) == -1) { + fail_fn(CREATE_ERROR("setresgid(%d) failed: %s", gid, strerror(errno))); + } - if (setresgid(gid, gid, gid) == -1) { - fail_fn(CREATE_ERROR("setresgid(%d) failed: %s", gid, strerror(errno))); - } + // 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); - // 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); + // Must be called before losing the permission to set scheduler policy. + SetSchedulerPolicy(fail_fn, is_top_app); - // Must be called before losing the permission to set scheduler policy. - SetSchedulerPolicy(fail_fn, is_top_app); + if (setresuid(uid, uid, uid) == -1) { + fail_fn(CREATE_ERROR("setresuid(%d) failed: %s", uid, strerror(errno))); + } - 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"); + } - // 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"); + } + } - 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"); + } } - } - // 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); } - } - 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::NATIVE_HEAP_ZERO_INIT; - // 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; + 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)); + } + } - // 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); - } + SetCapabilities(permitted_capabilities, effective_capabilities, permitted_capabilities, + fail_fn); - // 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; + __android_log_close(); + AStatsSocket_close(); - 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; + 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 (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 (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)); } - } - - 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"); + } - // 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(); - // 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."); + } - 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)); + } } - // 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(); } - } - if (is_child_zygote) { - initUnsolSocketToSystemServer(); - } + env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags, + is_system_server, is_child_zygote, managed_instruction_set); - 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); - // 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."); - } + if (env->ExceptionCheck()) { + fail_fn("Error calling post fork hooks."); + } } static uint64_t GetEffectiveCapabilityMask(JNIEnv* env) { @@ -2068,12 +2069,11 @@ static void com_android_internal_os_Zygote_nativePreApplicationInit(JNIEnv*, jcl 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 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( 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 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer( 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 @@ static void com_android_internal_os_Zygote_nativeAllowFileAcrossFork( 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 @@ static void com_android_internal_os_Zygote_nativeInstallSeccompUidGidFilter( * @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); - - 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); + 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, + 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 06a71cb22672..7fa627b3f809 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* kPathWhitelist[] = { 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; - } +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; + } - // Check any paths added to the dynamic whitelist. - for (const auto& whitelist_path : whitelist_) { - if (path == whitelist_path) - return true; - } + // Check any paths added to the dynamic allowlist. + for (const auto& allowlist_path : allowlist_) { + if (path == allowlist_path) return true; + } - // Framework jars are allowed. - static const char* kFrameworksPrefix[] = { - "/system/framework/", - "/system_ext/framework/", - }; + // Framework jars are allowed. + static const char* kFrameworksPrefix[] = { + "/system/framework/", + "/system_ext/framework/", + }; - static const char* kJarSuffix = ".jar"; + 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; + for (const auto& frameworks_prefix : kFrameworksPrefix) { + if (android::base::StartsWith(path, frameworks_prefix) && + android::base::EndsWith(path, kJarSuffix)) { + 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; - } + // 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; + } - // the in-memory file created by ART through memfd_create is allowed. - if (IsArtMemfd(path)) { - return true; - } + // the in-memory file created by ART through memfd_create is allowed. + if (IsArtMemfd(path)) { + return true; + } - // 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"; - - 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; - } + // 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; - } + 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 whitelisted automatically. - static const char* kZygoteWhitelistPath = "/vendor/zygote_whitelist/"; - if (android::base::StartsWith(path, kZygoteWhitelistPath) - && 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; + 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 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, fail_fn_t fail_fn) 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 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, fail_fn_t fail_fn) 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 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, fail_fn_t fail_fn) 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 2caf1575981a..14c318e8e84a 100644 --- a/core/jni/fd_utils.h +++ b/core/jni/fd_utils.h @@ -33,42 +33,40 @@ class FileDescriptorInfo; // 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 ec41a47a8798..74a37cadc54c 100644 --- a/core/proto/android/server/activitymanagerservice.proto +++ b/core/proto/android/server/activitymanagerservice.proto @@ -628,6 +628,7 @@ message ActivityManagerServiceDumpProcessesProto { 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 50d1e6bb0b18..8e1da0819515 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. --> @@ -1915,7 +1915,7 @@ @hide --> <permission android:name="android.permission.SUSPEND_APPS" - android:protectionLevel="signature|wellbeing" /> + android:protectionLevel="signature|role" /> <!-- Allows applications to discover and pair bluetooth devices. <p>Protection level: normal @@ -2789,7 +2789,7 @@ <p>Not for use by third-party applications. --> <permission android:name="android.permission.SYSTEM_APPLICATION_OVERLAY" - android:protectionLevel="signature|recents|wellbeing"/> + android:protectionLevel="signature|recents|role"/> <!-- @deprecated Use {@link android.Manifest.permission#REQUEST_COMPANION_RUN_IN_BACKGROUND} @hide @@ -5138,7 +5138,7 @@ <!-- @SystemApi Allows the holder to access and manage instant applications on the device. @hide --> <permission android:name="android.permission.ACCESS_INSTANT_APPS" - android:protectionLevel="signature|installer|verifier|wellbeing" /> + android:protectionLevel="signature|installer|verifier|role" /> <uses-permission android:name="android.permission.ACCESS_INSTANT_APPS"/> <!-- Allows the holder to view the instant applications on the device. @@ -5318,7 +5318,7 @@ <!-- @SystemApi Allows an application to turn on / off quiet mode. @hide --> <permission android:name="android.permission.MODIFY_QUIET_MODE" - android:protectionLevel="signature|privileged|wellbeing|development" /> + android:protectionLevel="signature|privileged|development" /> <!-- Allows internal management of the camera framework @hide --> @@ -5561,6 +5561,17 @@ <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" /> + + <!-- @SystemApi Allows the holder to set the source of the data when setting a clip on the + clipboard. + @hide --> + <permission android:name="android.permission.SET_CLIP_SOURCE" + android:protectionLevel="signature|recents" /> + <!-- Attribution for Geofencing service. --> <attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/> <!-- Attribution for Country Detector. --> diff --git a/core/res/res/layout/notification_template_material_big_media.xml b/core/res/res/layout/notification_template_material_big_media.xml index bdd4430a7985..aa20ad36720b 100644 --- a/core/res/res/layout/notification_template_material_big_media.xml +++ b/core/res/res/layout/notification_template_material_big_media.xml @@ -59,32 +59,15 @@ <!--<include layout="@layout/notification_template_part_line1"/>--> <!--<include layout="@layout/notification_template_text"/>--> - <LinearLayout - android:id="@+id/line1" + <TextView android:id="@+id/title" + android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="horizontal" - > - <TextView android:id="@+id/title" - android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:singleLine="true" - android:ellipsize="marquee" - android:fadingEdge="horizontal" - android:textAlignment="viewStart" - /> - <TextView android:id="@+id/text_line_1" - style="@style/Widget.DeviceDefault.Notification.Text" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="end|bottom" - android:layout_marginStart="16dp" - android:singleLine="true" - android:ellipsize="marquee" - android:fadingEdge="horizontal" - /> - </LinearLayout> + android:singleLine="true" + android:ellipsize="marquee" + android:fadingEdge="horizontal" + android:textAlignment="viewStart" + /> <com.android.internal.widget.ImageFloatingTextView style="@style/Widget.DeviceDefault.Notification.Text" diff --git a/core/res/res/layout/notification_template_material_media.xml b/core/res/res/layout/notification_template_material_media.xml index baffdd5ac0f1..542e59df76c0 100644 --- a/core/res/res/layout/notification_template_material_media.xml +++ b/core/res/res/layout/notification_template_material_media.xml @@ -63,32 +63,15 @@ <!--<include layout="@layout/notification_template_part_line1"/>--> <!--<include layout="@layout/notification_template_text"/>--> - <LinearLayout - android:id="@+id/line1" + <TextView android:id="@+id/title" + android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="horizontal" - > - <TextView android:id="@+id/title" - android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:singleLine="true" - android:ellipsize="marquee" - android:fadingEdge="horizontal" - android:textAlignment="viewStart" - /> - <TextView android:id="@+id/text_line_1" - style="@style/Widget.DeviceDefault.Notification.Text" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="end|bottom" - android:layout_marginStart="16dp" - android:singleLine="true" - android:ellipsize="marquee" - android:fadingEdge="horizontal" - /> - </LinearLayout> + android:singleLine="true" + android:ellipsize="marquee" + android:fadingEdge="horizontal" + android:textAlignment="viewStart" + /> <com.android.internal.widget.ImageFloatingTextView style="@style/Widget.DeviceDefault.Notification.Text" diff --git a/core/res/res/layout/notification_template_part_line1.xml b/core/res/res/layout/notification_template_part_line1.xml index fc5bd9cc6c0b..ca8fe7908e14 100644 --- a/core/res/res/layout/notification_template_part_line1.xml +++ b/core/res/res/layout/notification_template_part_line1.xml @@ -15,29 +15,13 @@ ~ limitations under the License --> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/line1" +<TextView + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/title" + android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.BigTitle" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="horizontal" - > - <TextView android:id="@+id/title" - android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.BigTitle" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:singleLine="true" - android:ellipsize="marquee" - android:fadingEdge="horizontal" - android:textAlignment="viewStart" - /> - <TextView android:id="@+id/text_line_1" - style="@style/Widget.DeviceDefault.Notification.Text" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="end|bottom" - android:layout_marginStart="16dp" - android:singleLine="true" - android:ellipsize="marquee" - android:fadingEdge="horizontal" - /> -</LinearLayout> + android:maxLines="2" + android:ellipsize="end" + android:textAlignment="viewStart" + /> diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 4b591bf63e7b..648d2a1034d0 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 a43b29a56131..eb98c69b92be 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 3990bab4447b..d6759b6453b8 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 28af8a3b24e0..0a4c397de8c3 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 8459403ff291..afb5c397dde5 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 a7f6433b4977..0d23fa56d55b 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 1022cef7fbc8..87b4ce7faa5a 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 ef20bade3275..7e847e0a66af 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 0e30c046e2f8..4d3d79394521 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 77b64b52e04a..2e24175bbaa4 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 a226ac3bc3c2..70caa2cff7fe 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 fdb2ff1b83f2..0f732669f467 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 dddc07037201..13afaf251317 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 472f1d216f15..512b3a555eec 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 22b3401cf89b..d9dc2c55cb09 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 f2cbb75f6580..73e2ca0d3fe5 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 f440c8ac2263..67130e1fb5c5 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 93881e992d84..1d36494b7b8b 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 a7fa30ebc2d9..016c55c3352c 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 ce9a915f9c2a..aef32a4d55b6 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 01d0c7e06c73..bd7da803e42b 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 28ff5fb61b22..d771977431c3 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 cb2bcdc3d463..ec02fad6683c 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 f95c2796557c..8ee77a600739 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 714b5e4635ad..42b8c85f7eb9 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 ef872e98f6c3..be0cd2358b8b 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 7cc316077b1f..5c26e683d354 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 a3c0badee9b4..3d8856df65bf 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 72a799ede92f..1c5ab13035f3 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 7a2527f50cba..fd3a06baa3fa 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 f108aa7fdcd0..be64e904b908 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 91073d445ac6..3a6ce2179c96 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 32f33dfaea4e..3cd0aba28c04 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 cd1bbb11d468..8d6e42e1e7ff 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 f7fe38457a56..28d2ed8963b0 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 5824c3a64843..cd5b35affb86 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 d435a253ad22..83b4a684ae58 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 ee771df1b51c..e3cb913fe0fd 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 b03f94ca5117..4b54bdbc2469 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 c25bd5757526..7a03bb32efcb 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 68edfeac6eb1..1c00fe65ba82 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 b3516d5c353c..a2512d2a9d08 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 22bdd772856a..e9110c217d4a 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 52f0a7c9c2ae..16e2efa6f5c0 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 4d8888ebdb9a..258422574dd7 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 87c2cebe78fa..7fb32e7d2034 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 2c3742baeae6..820d7a029b9e 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 8d6ce865ec7c..91c38a4ac3bd 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 af3ce0065ff5..88fb8246845f 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 aaab7b59837b..f82267d115eb 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 c69928546143..203ad3d39060 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 a31951a3f5ac..102c469ad21d 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 5e5b29f8e4e0..d8d43a64ab7b 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 137c138cba97..82008b069346 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 de71c39a05d0..1bafd6006e3c 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 83c03a4361c0..a15a9a46a4d1 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 e2be98d723fa..1f2680e2b101 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 bc761429b4c7..e3c3c09214c8 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 c9f57efc0c29..26861dd06e34 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 6c12366d932a..01bf27679dc2 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 d5cec263b6b9..aa693582f0fa 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 686795065c61..232a17219eb4 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 d5cec263b6b9..aa693582f0fa 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 690884a452f9..01daa557ca99 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 84752d5bfe5a..1a513e462580 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 66547decf56e..e01a1c446614 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 487b8181e510..011b042f81b3 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 87a66b36b7d7..0a7f7600abfc 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 4c3742493fbb..ddce26d68e59 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 d061d6f68b9f..11d5e7d8c43c 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 8288d413e9c9..4f6ccff5313f 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 6ac7d2a583e2..8dd721f8890a 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 1ac17340e941..3760c6dc73c5 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 9f822e31260c..63ee3a0374af 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 21865cde4a70..3c985b999162 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 37d06f83284f..7402195a0de8 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 2132aace6350..147553fbfa0a 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 3b9db401be3a..77e664afcbfe 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 c10f3e97bca2..10f787b70fd1 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 f77de7daad1d..f2c5589f392b 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 baf0b86dd1be..4d7091c68696 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 9345fc82b1d3..1f8f1766b376 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 1187f003124d..ebc02c502b8a 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 949257234918..10d05c1fa14d 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 e5a026bd6fa5..976b97a2b8ed 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 100983bcef0d..05d29c2685f4 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" /> @@ -8630,6 +8633,9 @@ Described here are the attributes that can be included in that tag. --> <declare-styleable name="RecognitionService"> <attr name="settingsActivity" /> + <!-- Flag indicating whether a recognition service can be selected as default. The default + value of this flag is true. --> + <attr name="selectableAsDefault" format="boolean" /> </declare-styleable> <!-- Use <code>voice-interaction-service</code> as the root tag of the XML resource that diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index bed5c31bd327..cc52655ad7d2 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -285,9 +285,6 @@ <!-- Additional flag from base permission type: this permission can be automatically granted to the system default text classifier --> <flag name="textClassifier" value="0x10000" /> - <!-- Additional flag from base permission type: this permission will be granted to the - wellbeing app, as defined by the OEM. --> - <flag name="wellbeing" value="0x20000" /> <!-- Additional flag from base permission type: this permission can be automatically granted to the document manager --> <flag name="documenter" value="0x40000" /> @@ -825,6 +822,12 @@ <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back Stack</a> document for more details about tasks.--> <enum name="singleInstance" value="3" /> + <!-- The activity can only be running as the root activity of the task, the first activity + that created the task, and therefore there will only be one instance of this activity + in a task. In constrast to the {@code singleTask} launch mode, this activity can be + started in multiple instances in different tasks if the + {@code FLAG_ACTIVITY_MULTIPLE_TASK} is set.--> + <enum name="singleInstancePerTask" value="4" /> </attr> <!-- Specify the orientation an activity should be run in. If not @@ -1370,7 +1373,7 @@ <p>The default value of this attribute is <code>false</code>. --> <attr name="resumeWhilePausing" format="boolean" /> - <!-- Indicates that it is okay for this activity to be put in multi-window mode. Intended for a + <!-- Hint to platform that the activity works well in multi-window mode. Intended for a multi-window device where there can be multiple activities of various sizes on the screen at the same time. @@ -1390,7 +1393,7 @@ resizeable. <p>NOTE: The value of {@link android.R.attr#screenOrientation} is ignored for - resizeable activities when in multi-window mode. --> + resizeable activities when in multi-window mode before Android 12. --> <attr name="resizeableActivity" format="boolean" /> <!-- Indicates that the activity specifically supports the picture-in-picture form of diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml index d79c01faaa36..22467e4c1402 100644 --- a/core/res/res/values/colors.xml +++ b/core/res/res/values/colors.xml @@ -151,7 +151,7 @@ <color name="notification_action_button_text_color">@color/notification_default_color</color> - <color name="notification_progress_background_color">@color/secondary_text_material_light</color> + <color name="notification_progress_background_color">@color/notification_secondary_text_color_current</color> <color name="notification_action_list">#ffeeeeee</color> @@ -171,7 +171,7 @@ <color name="accessibility_focus_highlight_color">#bf39b500</color> <color name="autofilled_highlight">#4dffeb3b</color> - <color name="system_notification_accent_color">#ff607D8B</color> + <color name="system_notification_accent_color">#00000000</color> <!-- Default user icon colors --> <color name="user_icon_1">#ff00bcd4</color><!-- cyan 500 --> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index d61d19a41266..8bc3a52fa17b 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,10 @@ <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 hold the wellbeing role. --> + <string name="config_systemWellbeing" translatable="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 +4663,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/ids.xml b/core/res/res/values/ids.xml index 0f0ac56f1e51..3a41d5fed238 100644 --- a/core/res/res/values/ids.xml +++ b/core/res/res/values/ids.xml @@ -29,6 +29,7 @@ <item type="id" name="icon2" /> <item type="id" name="input" /> <item type="id" name="left_icon" /> + <item type="id" name="line1" /> <item type="id" name="list" /> <item type="id" name="list_container" /> <item type="id" name="menu" /> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 2004d0a8d15c..b5d1e0ceec02 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -3085,6 +3085,8 @@ <public name="hand_secondTint"/> <public name="hand_secondTintMode"/> <public name="dataExtractionRules"/> + <public name="passwordsActivity"/> + <public name="selectableAsDefault"/> </public-group> <public-group type="drawable" first-id="0x010800b5"> @@ -3168,6 +3170,10 @@ <public name="config_customMediaSessionPolicyProvider" /> <!-- @hide @SystemApi --> <public name="config_systemSpeechRecognizer" /> + <!-- @hide @SystemApi --> + <public name="config_systemWifiCoexManager" /> + <!-- @hide @SystemApi --> + <public name="config_systemWellbeing" /> </public-group> <public-group type="id" first-id="0x01020055"> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index ff9d26fb2363..00cc81639608 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" /> @@ -2917,7 +2912,6 @@ <java-symbol type="id" name="time_divider" /> <java-symbol type="id" name="header_text_divider" /> <java-symbol type="id" name="header_text_secondary_divider" /> - <java-symbol type="id" name="text_line_1" /> <java-symbol type="drawable" name="ic_expand_notification" /> <java-symbol type="drawable" name="ic_collapse_notification" /> <java-symbol type="drawable" name="ic_expand_bundle" /> @@ -4181,7 +4175,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/GameManagerTests/Android.bp b/core/tests/GameManagerTests/Android.bp index 2789e9f316d1..8c5d6d5a76a1 100644 --- a/core/tests/GameManagerTests/Android.bp +++ b/core/tests/GameManagerTests/Android.bp @@ -29,6 +29,7 @@ android_test { "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 8f50051725cd..0c964114a76e 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 @@ import org.junit.runner.RunWith; */ @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 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 testGameModeGetterSetter() { + public void testPrivilegedGameModeGetterSetter() { assertEquals(GameManager.GAME_MODE_UNSUPPORTED, mGameManager.getGameMode(PACKAGE_NAME_0)); @@ -62,22 +83,4 @@ public final class GameManagerTests { 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/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java index 9e6827c19cb2..78569bdb4adc 100644 --- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java +++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java @@ -38,14 +38,9 @@ public class BatteryConsumerData { private static final String[] PACKAGES_SYSTEM = {PACKAGE_MEDIA_PROVIDER, PACKAGE_CALENDAR_PROVIDER, PACKAGE_SYSTEMUI}; - // Temporary placeholder voltage for converting energy to charge - // TODO: remove this when b/173765509 is resolved - private static final double MOCK_NOMINAL_VOLTAGE = 3.7; - // Unit conversion: - // mAh = uWs * (1/1000)(milli/micro) * (1/Voltage) * (1/3600)(hours/second) - private static final double UJ_2_MAH = - (1.0 / 1000) * (1.0 / MOCK_NOMINAL_VOLTAGE) * (1.0 / 3600); + // mAh = uC * (1/1000)(milli/micro) * (1/3600)(hours/second) + private static final double UC_2_MAH = (1.0 / 1000) * (1.0 / 3600); enum EntryType { POWER, @@ -178,8 +173,10 @@ public class BatteryConsumerData { mBatteryConsumerInfo = BatteryConsumerInfoHelper.makeBatteryConsumerInfo( context.getPackageManager(), requestedBatterySipper); - long totalScreenMeasuredEnergyUJ = batteryStats.getScreenOnEnergy(); - long uidScreenMeasuredEnergyUJ = requestedBatterySipper.uidObj.getScreenOnEnergy(); + long totalScreenMeasuredChargeUC = + batteryStats.getScreenOnMeasuredBatteryConsumptionUC(); + long uidScreenMeasuredChargeUC = + requestedBatterySipper.uidObj.getScreenOnMeasuredBatteryConsumptionUC(); addEntry("Total power", EntryType.POWER, requestedBatterySipper.totalSmearedPowerMah, totalSmearedPowerMah); @@ -189,10 +186,10 @@ public class BatteryConsumerData { requestedBatterySipper.totalSmearedPowerMah, totalPowerExcludeSystemMah); addEntry("Screen, smeared", EntryType.POWER, requestedBatterySipper.screenPowerMah, totalScreenPower); - if (uidScreenMeasuredEnergyUJ != BatteryStats.ENERGY_DATA_UNAVAILABLE - && totalScreenMeasuredEnergyUJ != BatteryStats.ENERGY_DATA_UNAVAILABLE) { - final double measuredCharge = UJ_2_MAH * uidScreenMeasuredEnergyUJ; - final double totalMeasuredCharge = UJ_2_MAH * totalScreenMeasuredEnergyUJ; + if (uidScreenMeasuredChargeUC != BatteryStats.POWER_DATA_UNAVAILABLE + && totalScreenMeasuredChargeUC != BatteryStats.POWER_DATA_UNAVAILABLE) { + final double measuredCharge = UC_2_MAH * uidScreenMeasuredChargeUC; + final double totalMeasuredCharge = UC_2_MAH * totalScreenMeasuredChargeUC; addEntry("Screen, measured", EntryType.POWER, measuredCharge, totalMeasuredCharge); } @@ -297,17 +294,19 @@ public class BatteryConsumerData { BatteryStats batteryStats) { switch (drainType) { case AMBIENT_DISPLAY: - final long totalDozeMeasuredEnergyUJ = batteryStats.getScreenDozeEnergy(); - if (totalDozeMeasuredEnergyUJ != BatteryStats.ENERGY_DATA_UNAVAILABLE) { - final double measuredCharge = UJ_2_MAH * totalDozeMeasuredEnergyUJ; + final long totalDozeMeasuredChargeUC = + batteryStats.getScreenDozeMeasuredBatteryConsumptionUC(); + if (totalDozeMeasuredChargeUC != BatteryStats.POWER_DATA_UNAVAILABLE) { + final double measuredCharge = UC_2_MAH * totalDozeMeasuredChargeUC; addEntry("Measured ambient display power", EntryType.POWER, measuredCharge, measuredCharge); } break; case SCREEN: - final long totalScreenMeasuredEnergyUJ = batteryStats.getScreenOnEnergy(); - if (totalScreenMeasuredEnergyUJ != BatteryStats.ENERGY_DATA_UNAVAILABLE) { - final double measuredCharge = UJ_2_MAH * totalScreenMeasuredEnergyUJ; + final long totalScreenMeasuredChargeUC = + batteryStats.getScreenOnMeasuredBatteryConsumptionUC(); + if (totalScreenMeasuredChargeUC != BatteryStats.POWER_DATA_UNAVAILABLE) { + final double measuredCharge = UC_2_MAH * totalScreenMeasuredChargeUC; addEntry("Measured screen power", EntryType.POWER, measuredCharge, measuredCharge); } 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 0fe44630f308..9e8837386128 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 static com.google.common.truth.Truth.assertThat; import android.os.Bundle; +import com.google.common.collect.ImmutableList; + import org.junit.Test; import java.util.List; @@ -67,9 +69,9 @@ public class SearchSpecTest { 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 bf6b07f71839..677f4bd9e46d 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 @@ public class SetSchemaRequestTest { } @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 @@ public class SetSchemaRequestTest { } @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/os/BytesMatcherTest.java b/core/tests/coretests/src/android/os/BytesMatcherTest.java new file mode 100644 index 000000000000..67c1b3c947fb --- /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 89411902bb6b..c06405affc1b 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.assertEquals; 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 @@ public class VibratorInfoTest { @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 @@ public class VibratorInfoTest { @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 @@ public class VibratorInfoTest { @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 366aabd183e3..fa824b140caa 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.FileInputStream; 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 @@ public final class CredentialManagementAppTest { 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 36104cf0f71d..c15fc3a15112 100644 --- a/core/tests/coretests/src/android/view/SurfaceControlFpsListenerTest.java +++ b/core/tests/coretests/src/android/view/SurfaceControlFpsListenerTest.java @@ -39,7 +39,7 @@ public class SurfaceControlFpsListenerTest { } }; - listener.register(new SurfaceControl()); + listener.register(0); listener.unregister(); } diff --git a/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java index add04698e372..c67f90136992 100644 --- a/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java @@ -44,18 +44,18 @@ public class AmbientDisplayPowerCalculatorTest { public void testMeasuredEnergyBasedModel() { BatteryStatsImpl stats = mStatsRule.getBatteryStats(); - stats.updateDisplayEnergyLocked(300_000_000, Display.STATE_ON, 0); + stats.updateDisplayMeasuredEnergyStatsLocked(300_000_000, Display.STATE_ON, 0); stats.noteScreenStateLocked(Display.STATE_DOZE, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS); - stats.updateDisplayEnergyLocked(200_000_000, Display.STATE_DOZE, + stats.updateDisplayMeasuredEnergyStatsLocked(200_000_000, Display.STATE_DOZE, 30 * MINUTE_IN_MS); stats.noteScreenStateLocked(Display.STATE_OFF, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS); - stats.updateDisplayEnergyLocked(100_000_000, Display.STATE_OFF, + stats.updateDisplayMeasuredEnergyStatsLocked(100_000_000, Display.STATE_OFF, 120 * MINUTE_IN_MS); AmbientDisplayPowerCalculator calculator = @@ -68,8 +68,9 @@ public class AmbientDisplayPowerCalculatorTest { SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY); assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE)) .isEqualTo(90 * MINUTE_IN_MS); + // 100,000,00 uC / 1000 (micro-/milli-) / 360 (seconds/hour) = 27.777778 mAh assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE)) - .isWithin(PRECISION).of(7.5075075); + .isWithin(PRECISION).of(27.777778); } @Test diff --git a/core/tests/coretests/src/com/android/internal/os/DischargedPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryChargeCalculatorTest.java index bec3d1644e81..cf126c62dac7 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 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) @SmallTest -public class DischargedPowerCalculatorTest { +public class BatteryChargeCalculatorTest { private static final double PRECISION = 0.00001; @Rule @@ -40,27 +40,41 @@ public class DischargedPowerCalculatorTest { @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); - - DischargedPowerCalculator calculator = - new DischargedPowerCalculator(mStatsRule.getPowerProfile()); + /* 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); - 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/BatteryStatsCpuTimesTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java index ff728d651067..4319740ffdf3 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java @@ -121,7 +121,7 @@ public class BatteryStatsCpuTimesTest { when(mCpuUidFreqTimeReader.readFreqs(mPowerProfile)).thenReturn(freqs); // RUN - mBatteryStatsImpl.updateCpuTimeLocked(false, false); + mBatteryStatsImpl.updateCpuTimeLocked(false, false, null); // VERIFY assertArrayEquals("Unexpected cpu freqs", freqs, mBatteryStatsImpl.getCpuFreqs()); @@ -141,7 +141,7 @@ public class BatteryStatsCpuTimesTest { mBatteryStatsImpl.setOnBatteryInternal(true); // RUN - mBatteryStatsImpl.updateCpuTimeLocked(true, false); + mBatteryStatsImpl.updateCpuTimeLocked(true, false, null); // VERIFY verify(mUserInfoProvider).refreshUserIds(); @@ -221,7 +221,7 @@ public class BatteryStatsCpuTimesTest { } // RUN - mBatteryStatsImpl.updateClusterSpeedTimes(updatedUids, true); + mBatteryStatsImpl.updateClusterSpeedTimes(updatedUids, true, null); // VERIFY int totalClustersTimeMs = 0; @@ -563,7 +563,7 @@ public class BatteryStatsCpuTimesTest { any(KernelCpuUidFreqTimeReader.Callback.class)); // RUN - mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false); + mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false, null); // VERIFY for (int i = 0; i < testUids.length; ++i) { @@ -596,7 +596,7 @@ public class BatteryStatsCpuTimesTest { any(KernelCpuUidFreqTimeReader.Callback.class)); // RUN - mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true); + mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true, null); // VERIFY for (int i = 0; i < testUids.length; ++i) { @@ -647,7 +647,7 @@ public class BatteryStatsCpuTimesTest { when(mCpuUidFreqTimeReader.perClusterTimesAvailable()).thenReturn(true); // RUN - mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false); + mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false, null); // VERIFY for (int i = 0; i < testUids.length; ++i) { @@ -690,7 +690,7 @@ public class BatteryStatsCpuTimesTest { any(KernelCpuUidFreqTimeReader.Callback.class)); // RUN - mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true); + mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true, null); // VERIFY for (int i = 0; i < testUids.length; ++i) { @@ -757,7 +757,7 @@ public class BatteryStatsCpuTimesTest { when(mCpuUidFreqTimeReader.perClusterTimesAvailable()).thenReturn(true); // RUN - mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(partialTimers, true, false); + mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(partialTimers, true, false, null); // VERIFY final long[][] expectedWakeLockUidTimesUs = new long[clusterFreqs.length][]; @@ -846,7 +846,7 @@ public class BatteryStatsCpuTimesTest { any(KernelCpuUidFreqTimeReader.Callback.class)); // RUN - mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false); + mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false, null); // VERIFY for (int i = 0; i < testUids.length; ++i) { @@ -879,7 +879,7 @@ public class BatteryStatsCpuTimesTest { any(KernelCpuUidFreqTimeReader.Callback.class)); // RUN - mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true); + mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true, null); // VERIFY for (int i = 0; i < testUids.length; ++i) { @@ -923,7 +923,7 @@ public class BatteryStatsCpuTimesTest { any(KernelCpuUidFreqTimeReader.Callback.class)); // RUN - mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false); + mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false, null); // VERIFY for (int i = 0; i < testUids.length; ++i) { @@ -963,7 +963,7 @@ public class BatteryStatsCpuTimesTest { any(KernelCpuUidFreqTimeReader.Callback.class)); // RUN - mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false); + mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false, null); // VERIFY for (int i = 0; i < testUids.length; ++i) { @@ -1020,7 +1020,7 @@ public class BatteryStatsCpuTimesTest { any(KernelCpuUidFreqTimeReader.Callback.class)); // RUN - mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false); + mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false, null); // VERIFY for (int i = 0; i < testUids.length; ++i) { @@ -1169,7 +1169,7 @@ public class BatteryStatsCpuTimesTest { any(KernelCpuUidClusterTimeReader.Callback.class)); // RUN - mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true); + mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true, null); // VERIFY for (int i = 0; i < testUids.length; ++i) { @@ -1199,7 +1199,7 @@ public class BatteryStatsCpuTimesTest { any(KernelCpuUidClusterTimeReader.Callback.class)); // RUN - mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true); + mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true, null); // VERIFY for (int i = 0; i < testUids.length; ++i) { @@ -1244,7 +1244,7 @@ public class BatteryStatsCpuTimesTest { any(KernelCpuUidClusterTimeReader.Callback.class)); // RUN - mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true); + mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true, null); // VERIFY for (int i = 0; i < testUids.length; ++i) { diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java index 931611ea7478..f168b3c160cb 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java @@ -503,7 +503,7 @@ public class BatteryStatsNoteTest extends TestCase { } @SmallTest - public void testUpdateDisplayEnergyLocked() { + public void testUpdateDisplayMeasuredEnergyStatsLocked() { final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms final MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); @@ -520,8 +520,8 @@ public class BatteryStatsNoteTest extends TestCase { // Case A: uid1 off, uid2 off, battery off, screen off bi.updateTimeBasesLocked(battery, screen, clocks.realtime*1000, 0); bi.setOnBatteryInternal(battery); - bi.updateDisplayEnergyLocked(500_000, screen, clocks.realtime); - checkMeasuredEnergy("A", uid1, blame1, uid2, blame2, globalDoze, bi); + bi.updateDisplayMeasuredEnergyStatsLocked(500_000, screen, clocks.realtime); + checkMeasuredCharge("A", uid1, blame1, uid2, blame2, globalDoze, bi); // Case B: uid1 off, uid2 off, battery ON, screen off clocks.realtime += 17; @@ -529,65 +529,65 @@ public class BatteryStatsNoteTest extends TestCase { bi.updateTimeBasesLocked(battery, screen, clocks.realtime*1000, 0); bi.setOnBatteryInternal(battery); clocks.realtime += 19; - bi.updateDisplayEnergyLocked(510_000, screen, clocks.realtime); - checkMeasuredEnergy("B", uid1, blame1, uid2, blame2, globalDoze, bi); + bi.updateDisplayMeasuredEnergyStatsLocked(510_000, screen, clocks.realtime); + checkMeasuredCharge("B", uid1, blame1, uid2, blame2, globalDoze, bi); // Case C: uid1 ON, uid2 off, battery on, screen off clocks.realtime += 18; setFgState(uid1, true, bi); clocks.realtime += 18; - bi.updateDisplayEnergyLocked(520_000, screen, clocks.realtime); - checkMeasuredEnergy("C", uid1, blame1, uid2, blame2, globalDoze, bi); + bi.updateDisplayMeasuredEnergyStatsLocked(520_000, screen, clocks.realtime); + checkMeasuredCharge("C", uid1, blame1, uid2, blame2, globalDoze, bi); // Case D: uid1 on, uid2 off, battery on, screen ON clocks.realtime += 17; screen = Display.STATE_ON; - bi.updateDisplayEnergyLocked(521_000, screen, clocks.realtime); + bi.updateDisplayMeasuredEnergyStatsLocked(521_000, screen, clocks.realtime); blame1 += 0; // Screen had been off during the measurement period - checkMeasuredEnergy("D.1", uid1, blame1, uid2, blame2, globalDoze, bi); + checkMeasuredCharge("D.1", uid1, blame1, uid2, blame2, globalDoze, bi); clocks.realtime += 101; - bi.updateDisplayEnergyLocked(530_000, screen, clocks.realtime); + bi.updateDisplayMeasuredEnergyStatsLocked(530_000, screen, clocks.realtime); blame1 += 530_000; - checkMeasuredEnergy("D.2", uid1, blame1, uid2, blame2, globalDoze, bi); + checkMeasuredCharge("D.2", uid1, blame1, uid2, blame2, globalDoze, bi); // Case E: uid1 on, uid2 ON, battery on, screen on clocks.realtime += 20; setFgState(uid2, true, bi); clocks.realtime += 40; - bi.updateDisplayEnergyLocked(540_000, screen, clocks.realtime); + bi.updateDisplayMeasuredEnergyStatsLocked(540_000, screen, clocks.realtime); // In the past 60ms, sum of fg is 20+40+40=100ms. uid1 is blamed for 60/100; uid2 for 40/100 blame1 += 540_000 * (20 + 40) / (20 + 40 + 40); blame2 += 540_000 * ( 0 + 40) / (20 + 40 + 40); - checkMeasuredEnergy("E", uid1, blame1, uid2, blame2, globalDoze, bi); + checkMeasuredCharge("E", uid1, blame1, uid2, blame2, globalDoze, bi); // Case F: uid1 on, uid2 OFF, battery on, screen on clocks.realtime += 40; setFgState(uid2, false, bi); clocks.realtime += 120; - bi.updateDisplayEnergyLocked(550_000, screen, clocks.realtime); + bi.updateDisplayMeasuredEnergyStatsLocked(550_000, screen, clocks.realtime); // In the past 160ms, sum f fg is 200ms. uid1 is blamed for 40+120 of it; uid2 for 40 of it. blame1 += 550_000 * (40 + 120) / (40 + 40 + 120); blame2 += 550_000 * (40 + 0 ) / (40 + 40 + 120); - checkMeasuredEnergy("F", uid1, blame1, uid2, blame2, globalDoze, bi); + checkMeasuredCharge("F", uid1, blame1, uid2, blame2, globalDoze, bi); // Case G: uid1 on, uid2 off, battery on, screen DOZE clocks.realtime += 5; screen = Display.STATE_DOZE; - bi.updateDisplayEnergyLocked(570_000, screen, clocks.realtime); + bi.updateDisplayMeasuredEnergyStatsLocked(570_000, screen, clocks.realtime); blame1 += 570_000; // All of this pre-doze time is blamed on uid1. - checkMeasuredEnergy("G", uid1, blame1, uid2, blame2, globalDoze, bi); + checkMeasuredCharge("G", uid1, blame1, uid2, blame2, globalDoze, bi); // Case H: uid1 on, uid2 off, battery on, screen ON clocks.realtime += 6; screen = Display.STATE_ON; - bi.updateDisplayEnergyLocked(580_000, screen, clocks.realtime); + bi.updateDisplayMeasuredEnergyStatsLocked(580_000, screen, clocks.realtime); blame1 += 0; // The screen had been doze during the energy period globalDoze += 580_000; - checkMeasuredEnergy("H", uid1, blame1, uid2, blame2, globalDoze, bi); + checkMeasuredCharge("H", uid1, blame1, uid2, blame2, globalDoze, bi); } @SmallTest - public void testUpdateCustomMeasuredEnergyDataLocked_neverCalled() { + public void testUpdateCustomMeasuredEnergyStatsLocked_neverCalled() { final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms final MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); bi.setOnBatteryInternal(true); @@ -595,20 +595,20 @@ public class BatteryStatsNoteTest extends TestCase { final int uid1 = 11500; final int uid2 = 11501; - // Initially, all custom buckets report energy of 0. - checkCustomMeasuredEnergy("0", 0, 0, uid1, 0, 0, uid2, 0, 0, bi); + // Initially, all custom buckets report charge of 0. + checkCustomBatteryConsumption("0", 0, 0, uid1, 0, 0, uid2, 0, 0, bi); } @SmallTest - public void testUpdateCustomMeasuredEnergyDataLocked() { + public void testUpdateCustomMeasuredEnergyStatsLocked() { final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms final MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); final int bucketA = 0; // Custom bucket 0 final int bucketB = 1; // Custom bucket 1 - long totalBlameA = 0; // Total energy consumption for bucketA (may exceed sum of uids) - long totalBlameB = 0; // Total energy consumption for bucketB (may exceed sum of uids) + long totalBlameA = 0; // Total charge consumption for bucketA (may exceed sum of uids) + long totalBlameB = 0; // Total charge consumption for bucketB (may exceed sum of uids) final int uid1 = 10500; long blame1A = 0; // Blame for uid1 in bucketA @@ -618,60 +618,60 @@ public class BatteryStatsNoteTest extends TestCase { long blame2A = 0; // Blame for uid2 in bucketA long blame2B = 0; // Blame for uid2 in bucketB - final SparseLongArray newEnergiesA = new SparseLongArray(2); - final SparseLongArray newEnergiesB = new SparseLongArray(2); + final SparseLongArray newChargesA = new SparseLongArray(2); + final SparseLongArray newChargesB = new SparseLongArray(2); // ----- Case A: battery off (so blame does not increase) bi.setOnBatteryInternal(false); - newEnergiesA.put(uid1, 20_000); - // Implicit newEnergiesA.put(uid2, 0); - bi.updateCustomMeasuredEnergyDataLocked(bucketA, 500_000, newEnergiesA); + newChargesA.put(uid1, 20_000); + // Implicit newChargesA.put(uid2, 0); + bi.updateCustomMeasuredEnergyStatsLocked(bucketA, 500_000, newChargesA); - newEnergiesB.put(uid1, 60_000); - // Implicit newEnergiesB.put(uid2, 0); - bi.updateCustomMeasuredEnergyDataLocked(bucketB, 700_000, newEnergiesB); + newChargesB.put(uid1, 60_000); + // Implicit newChargesB.put(uid2, 0); + bi.updateCustomMeasuredEnergyStatsLocked(bucketB, 700_000, newChargesB); - checkCustomMeasuredEnergy( + checkCustomBatteryConsumption( "A", totalBlameA, totalBlameB, uid1, blame1A, blame1B, uid2, blame2A, blame2B, bi); // ----- Case B: battery on bi.setOnBatteryInternal(true); - newEnergiesA.put(uid1, 7_000); blame1A += 7_000; - // Implicit newEnergiesA.put(uid2, 0); blame2A += 0; - bi.updateCustomMeasuredEnergyDataLocked(bucketA, 310_000, newEnergiesA); + newChargesA.put(uid1, 7_000); blame1A += 7_000; + // Implicit newChargesA.put(uid2, 0); blame2A += 0; + bi.updateCustomMeasuredEnergyStatsLocked(bucketA, 310_000, newChargesA); totalBlameA += 310_000; - newEnergiesB.put(uid1, 63_000); blame1B += 63_000; - newEnergiesB.put(uid2, 15_000); blame2B += 15_000; - bi.updateCustomMeasuredEnergyDataLocked(bucketB, 790_000, newEnergiesB); + newChargesB.put(uid1, 63_000); blame1B += 63_000; + newChargesB.put(uid2, 15_000); blame2B += 15_000; + bi.updateCustomMeasuredEnergyStatsLocked(bucketB, 790_000, newChargesB); totalBlameB += 790_000; - checkCustomMeasuredEnergy( + checkCustomBatteryConsumption( "B", totalBlameA, totalBlameB, uid1, blame1A, blame1B, uid2, blame2A, blame2B, bi); // ----- Case C: battery still on - newEnergiesA.delete(uid1); blame1A += 0; - newEnergiesA.put(uid2, 16_000); blame2A += 16_000; - bi.updateCustomMeasuredEnergyDataLocked(bucketA, 560_000, newEnergiesA); + newChargesA.delete(uid1); blame1A += 0; + newChargesA.put(uid2, 16_000); blame2A += 16_000; + bi.updateCustomMeasuredEnergyStatsLocked(bucketA, 560_000, newChargesA); totalBlameA += 560_000; - bi.updateCustomMeasuredEnergyDataLocked(bucketB, 10_000, null); + bi.updateCustomMeasuredEnergyStatsLocked(bucketB, 10_000, null); totalBlameB += 10_000; - checkCustomMeasuredEnergy( + checkCustomBatteryConsumption( "C", totalBlameA, totalBlameB, uid1, blame1A, blame1B, uid2, blame2A, blame2B, bi); // ----- Case D: battery still on - bi.updateCustomMeasuredEnergyDataLocked(bucketA, 0, newEnergiesA); - bi.updateCustomMeasuredEnergyDataLocked(bucketB, 15_000, new SparseLongArray(1)); + bi.updateCustomMeasuredEnergyStatsLocked(bucketA, 0, newChargesA); + bi.updateCustomMeasuredEnergyStatsLocked(bucketB, 15_000, new SparseLongArray(1)); totalBlameB += 15_000; - checkCustomMeasuredEnergy( + checkCustomBatteryConsumption( "D", totalBlameA, totalBlameB, uid1, blame1A, blame1B, uid2, blame2A, blame2B, bi); } @@ -686,32 +686,34 @@ public class BatteryStatsNoteTest extends TestCase { } } - private void checkMeasuredEnergy(String caseName, int uid1, long blame1, int uid2, long blame2, + private void checkMeasuredCharge(String caseName, int uid1, long blame1, int uid2, long blame2, long globalDoze, MockBatteryStatsImpl bi) { - final int bucket = MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_ON; + final int bucket = MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON; assertEquals("Wrong uid1 blame for Case " + caseName, blame1, - bi.getUidStatsLocked(uid1).getMeasuredEnergyMicroJoules(bucket)); + bi.getUidStatsLocked(uid1).getMeasuredBatteryConsumptionUC(bucket)); assertEquals("Wrong uid2 blame for Case " + caseName, blame2, - bi.getUidStatsLocked(uid2).getMeasuredEnergyMicroJoules(bucket)); + bi.getUidStatsLocked(uid2).getMeasuredBatteryConsumptionUC(bucket)); assertEquals("Wrong total blame for Case " + caseName, blame1 + blame2, - bi.getScreenOnEnergy()); + bi.getScreenOnMeasuredBatteryConsumptionUC()); assertEquals("Wrong doze for Case " + caseName, globalDoze, - bi.getScreenDozeEnergy()); + bi.getScreenDozeMeasuredBatteryConsumptionUC()); } - private void checkCustomMeasuredEnergy(String caseName, + private void checkCustomBatteryConsumption(String caseName, long totalBlameA, long totalBlameB, int uid1, long blame1A, long blame1B, int uid2, long blame2A, long blame2B, MockBatteryStatsImpl bi) { - final long[] actualTotal = bi.getCustomMeasuredEnergiesMicroJoules(); - final long[] actualUid1 = bi.getUidStatsLocked(uid1).getCustomMeasuredEnergiesMicroJoules(); - final long[] actualUid2 = bi.getUidStatsLocked(uid2).getCustomMeasuredEnergiesMicroJoules(); + final long[] actualTotal = bi.getCustomConsumerMeasuredBatteryConsumptionUC(); + final long[] actualUid1 = + bi.getUidStatsLocked(uid1).getCustomConsumerMeasuredBatteryConsumptionUC(); + final long[] actualUid2 = + bi.getUidStatsLocked(uid2).getCustomConsumerMeasuredBatteryConsumptionUC(); assertNotNull(actualTotal); assertNotNull(actualUid1); 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 74c37ada2054..ee472880b79f 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 @@ import org.junit.runners.Suite; @Suite.SuiteClasses({ AmbientDisplayPowerCalculatorTest.class, AudioPowerCalculatorTest.class, + BatteryChargeCalculatorTest.class, BatteryStatsCpuTimesTest.class, BatteryStatsBackgroundStatsTest.class, BatteryStatsBinderCallStatsTest.class, @@ -49,7 +50,6 @@ import org.junit.runners.Suite; CameraPowerCalculatorTest.class, CpuPowerCalculatorTest.class, CustomMeasuredPowerCalculatorTest.class, - DischargedPowerCalculatorTest.class, FlashlightPowerCalculatorTest.class, GnssPowerCalculatorTest.class, IdlePowerCalculatorTest.class, diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java index 167994200ed7..8aeb761ffc4d 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java @@ -147,7 +147,7 @@ public class BatteryUsageStatsRule implements TestRule { BatteryUsageStats apply(BatteryUsageStatsQuery query, PowerCalculator... calculators) { final long[] customMeasuredEnergiesMicroJoules = - mBatteryStats.getCustomMeasuredEnergiesMicroJoules(); + mBatteryStats.getCustomConsumerMeasuredBatteryConsumptionUC(); final int customMeasuredEnergiesCount = customMeasuredEnergiesMicroJoules != null ? customMeasuredEnergiesMicroJoules.length : 0; diff --git a/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java index e691beb09a70..70888905d7c8 100644 --- a/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java @@ -126,7 +126,7 @@ public class CpuPowerCalculatorTest { return null; }).when(mMockKernelCpuUidClusterTimeReader).readDelta(any()); - mStatsRule.getBatteryStats().updateCpuTimeLocked(true, true); + mStatsRule.getBatteryStats().updateCpuTimeLocked(true, true, null); mStatsRule.getUidStats(APP_UID1).getProcessStatsLocked("foo").addCpuTimeLocked(4321, 1234); mStatsRule.getUidStats(APP_UID1).getProcessStatsLocked("bar").addCpuTimeLocked(5432, 2345); diff --git a/core/tests/coretests/src/com/android/internal/os/CustomMeasuredPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/CustomMeasuredPowerCalculatorTest.java index f298f5988fc3..0c91b2959f8e 100644 --- a/core/tests/coretests/src/com/android/internal/os/CustomMeasuredPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/CustomMeasuredPowerCalculatorTest.java @@ -47,10 +47,10 @@ public class CustomMeasuredPowerCalculatorTest { final BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats(); SparseLongArray uidEnergies = new SparseLongArray(); uidEnergies.put(APP_UID, 30_000_000); - batteryStats.updateCustomMeasuredEnergyDataLocked(0, 100_000_000, uidEnergies); + batteryStats.updateCustomMeasuredEnergyStatsLocked(0, 100_000_000, uidEnergies); uidEnergies.put(APP_UID, 120_000_000); - batteryStats.updateCustomMeasuredEnergyDataLocked(1, 200_000_000, uidEnergies); + batteryStats.updateCustomMeasuredEnergyStatsLocked(1, 200_000_000, uidEnergies); CustomMeasuredPowerCalculator calculator = new CustomMeasuredPowerCalculator(mStatsRule.getPowerProfile()); diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java index 1687a78c9875..a47c4d832083 100644 --- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java +++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java @@ -47,8 +47,8 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl { setExternalStatsSyncLocked(new DummyExternalStatsSync()); - final boolean[] supportedStandardBuckets - = new boolean[MeasuredEnergyStats.NUMBER_STANDARD_ENERGY_BUCKETS]; + final boolean[] supportedStandardBuckets = + new boolean[MeasuredEnergyStats.NUMBER_STANDARD_POWER_BUCKETS]; Arrays.fill(supportedStandardBuckets, true); mGlobalMeasuredEnergyStats = new MeasuredEnergyStats(supportedStandardBuckets, 2); diff --git a/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java index 86e615c035c7..f3cf81ca3e86 100644 --- a/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java @@ -52,19 +52,19 @@ public class ScreenPowerCalculatorTest { BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats(); batteryStats.noteScreenStateLocked(Display.STATE_ON, 0, 0, 0); - batteryStats.updateDisplayEnergyLocked(0, Display.STATE_ON, 2 * MINUTE_IN_MS); + batteryStats.updateDisplayMeasuredEnergyStatsLocked(0, Display.STATE_ON, 2 * MINUTE_IN_MS); setFgState(APP_UID1, true, 2 * MINUTE_IN_MS, 2 * MINUTE_IN_MS); setFgState(APP_UID1, false, 20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS); setFgState(APP_UID2, true, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS); - batteryStats.updateDisplayEnergyLocked(300_000_000, Display.STATE_ON, + batteryStats.updateDisplayMeasuredEnergyStatsLocked(300_000_000, Display.STATE_ON, 60 * MINUTE_IN_MS); batteryStats.noteScreenStateLocked(Display.STATE_OFF, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS); - batteryStats.updateDisplayEnergyLocked(100_000_000, Display.STATE_DOZE, + batteryStats.updateDisplayMeasuredEnergyStatsLocked(100_000_000, Display.STATE_DOZE, 120 * MINUTE_IN_MS); mStatsRule.setTime(120 * MINUTE_IN_US, 120 * MINUTE_IN_US); @@ -78,20 +78,29 @@ public class ScreenPowerCalculatorTest { mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_SCREEN); assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE)) .isEqualTo(80 * MINUTE_IN_MS); + + // 400000000 uAs * (1 mA / 1000 uA) * (1 h / 3600 s) = 111.11111 mAh assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE)) - .isWithin(PRECISION).of(30.03003); + .isWithin(PRECISION).of(111.11111); UidBatteryConsumer uid1 = mStatsRule.getUidBatteryConsumer(APP_UID1); assertThat(uid1.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN)) .isEqualTo(18 * MINUTE_IN_MS); + + // Uid1 ran for 18 minutes out of the total 48 min of foreground time during the first + // Display update. Uid1 charge = 18 / 48 * 300000000 uAs = 31.25 mAh assertThat(uid1.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN)) - .isWithin(PRECISION).of(8.44594); + .isWithin(PRECISION).of(31.25); UidBatteryConsumer uid2 = mStatsRule.getUidBatteryConsumer(APP_UID2); assertThat(uid2.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN)) .isEqualTo(90 * MINUTE_IN_MS); + + // Uid2 ran for 30 minutes out of the total 48 min of foreground time during the first + // Display update and then took all of the time during the second Display update. + // Uid1 charge = 30 / 48 * 300000000 + 100000000 mAs = 79.86111 mAh assertThat(uid2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN)) - .isWithin(PRECISION).of(21.58408); + .isWithin(PRECISION).of(79.86111); } @Test diff --git a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java index b5282e9a625a..6edbbb0ad789 100644 --- a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java @@ -91,7 +91,7 @@ public class SystemServicePowerCalculatorTest { new long[] {10000, 20000, 30000, 40000} ); - mMockBatteryStats.readKernelUidCpuFreqTimesLocked(null, true, false); + mMockBatteryStats.readKernelUidCpuFreqTimesLocked(null, true, false, null); int workSourceUid1 = 100; int workSourceUid2 = 200; diff --git a/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java b/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java index d217bce24b9c..ed6e27b199b9 100644 --- a/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java +++ b/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java @@ -16,12 +16,12 @@ package com.android.internal.power; -import static android.os.BatteryStats.ENERGY_DATA_UNAVAILABLE; +import static android.os.BatteryStats.POWER_DATA_UNAVAILABLE; -import static com.android.internal.power.MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_DOZE; -import static com.android.internal.power.MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_ON; -import static com.android.internal.power.MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_OTHER; -import static com.android.internal.power.MeasuredEnergyStats.NUMBER_STANDARD_ENERGY_BUCKETS; +import static com.android.internal.power.MeasuredEnergyStats.NUMBER_STANDARD_POWER_BUCKETS; +import static com.android.internal.power.MeasuredEnergyStats.POWER_BUCKET_SCREEN_DOZE; +import static com.android.internal.power.MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON; +import static com.android.internal.power.MeasuredEnergyStats.POWER_BUCKET_SCREEN_OTHER; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -48,75 +48,75 @@ public class MeasuredEnergyStatsTest { @Test public void testConstruction() { - final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS]; + final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS]; final int numCustomBuckets = 2; - supportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true; - supportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false; - supportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true; + supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true; + supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false; + supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true; - final MeasuredEnergyStats stats - = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets); + final MeasuredEnergyStats stats = + new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets); - for (int i = 0; i < NUMBER_STANDARD_ENERGY_BUCKETS; i++) { + for (int i = 0; i < NUMBER_STANDARD_POWER_BUCKETS; i++) { if (supportedStandardBuckets[i]) { assertTrue(stats.isStandardBucketSupported(i)); - assertEquals(0L, stats.getAccumulatedStandardBucketEnergy(i)); + assertEquals(0L, stats.getAccumulatedStandardBucketCharge(i)); } else { assertFalse(stats.isStandardBucketSupported(i)); - assertEquals(ENERGY_DATA_UNAVAILABLE, stats.getAccumulatedStandardBucketEnergy(i)); + assertEquals(POWER_DATA_UNAVAILABLE, stats.getAccumulatedStandardBucketCharge(i)); } } for (int i = 0; i < numCustomBuckets; i++) { - assertEquals(0L, stats.getAccumulatedCustomBucketEnergy(i)); + assertEquals(0L, stats.getAccumulatedCustomBucketCharge(i)); } } @Test public void testCreateFromTemplate() { - final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS]; + final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS]; final int numCustomBuckets = 2; - supportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true; - supportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false; - supportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true; - - final MeasuredEnergyStats stats - = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets); - stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10); - stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5); - stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40); + supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true; + supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false; + supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true; + + final MeasuredEnergyStats stats = + new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets); + stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10); + stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5); + stats.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40); stats.updateCustomBucket(0, 50); stats.updateCustomBucket(1, 60); final MeasuredEnergyStats newStats = MeasuredEnergyStats.createFromTemplate(stats); - for (int i = 0; i < NUMBER_STANDARD_ENERGY_BUCKETS; i++) { + for (int i = 0; i < NUMBER_STANDARD_POWER_BUCKETS; i++) { if (supportedStandardBuckets[i]) { assertTrue(newStats.isStandardBucketSupported(i)); - assertEquals(0L, newStats.getAccumulatedStandardBucketEnergy(i)); + assertEquals(0L, newStats.getAccumulatedStandardBucketCharge(i)); } else { assertFalse(newStats.isStandardBucketSupported(i)); - assertEquals(ENERGY_DATA_UNAVAILABLE, - newStats.getAccumulatedStandardBucketEnergy(i)); + assertEquals(POWER_DATA_UNAVAILABLE, + newStats.getAccumulatedStandardBucketCharge(i)); } } for (int i = 0; i < numCustomBuckets; i++) { - assertEquals(0L, newStats.getAccumulatedCustomBucketEnergy(i)); + assertEquals(0L, newStats.getAccumulatedCustomBucketCharge(i)); } } @Test public void testReadWriteParcel() { - final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS]; + final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS]; final int numCustomBuckets = 2; - supportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true; - supportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false; - supportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true; - - final MeasuredEnergyStats stats - = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets); - stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10); - stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5); - stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40); + supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true; + supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false; + supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true; + + final MeasuredEnergyStats stats = + new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets); + stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10); + stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5); + stats.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40); stats.updateCustomBucket(0, 50); stats.updateCustomBucket(1, 60); @@ -126,32 +126,32 @@ public class MeasuredEnergyStatsTest { parcel.setDataPosition(0); MeasuredEnergyStats newStats = new MeasuredEnergyStats(parcel); - for (int i = 0; i < NUMBER_STANDARD_ENERGY_BUCKETS; i++) { - assertEquals(stats.getAccumulatedStandardBucketEnergy(i), - newStats.getAccumulatedStandardBucketEnergy(i)); + for (int i = 0; i < NUMBER_STANDARD_POWER_BUCKETS; i++) { + assertEquals(stats.getAccumulatedStandardBucketCharge(i), + newStats.getAccumulatedStandardBucketCharge(i)); } for (int i = 0; i < numCustomBuckets; i++) { - assertEquals(stats.getAccumulatedCustomBucketEnergy(i), - newStats.getAccumulatedCustomBucketEnergy(i)); + assertEquals(stats.getAccumulatedCustomBucketCharge(i), + newStats.getAccumulatedCustomBucketCharge(i)); } - assertEquals(ENERGY_DATA_UNAVAILABLE, - newStats.getAccumulatedCustomBucketEnergy(numCustomBuckets + 1)); + assertEquals(POWER_DATA_UNAVAILABLE, + newStats.getAccumulatedCustomBucketCharge(numCustomBuckets + 1)); parcel.recycle(); } @Test public void testCreateAndReadSummaryFromParcel() { - final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS]; + final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS]; final int numCustomBuckets = 2; - supportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true; - supportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false; - supportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true; - - final MeasuredEnergyStats stats - = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets); - stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10); - stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5); - stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40); + supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true; + supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false; + supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true; + + final MeasuredEnergyStats stats = + new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets); + stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10); + stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5); + stats.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40); stats.updateCustomBucket(0, 50); stats.updateCustomBucket(1, 60); @@ -160,90 +160,90 @@ public class MeasuredEnergyStatsTest { parcel.setDataPosition(0); MeasuredEnergyStats newStats = MeasuredEnergyStats.createAndReadSummaryFromParcel(parcel); - for (int i = 0; i < NUMBER_STANDARD_ENERGY_BUCKETS; i++) { + for (int i = 0; i < NUMBER_STANDARD_POWER_BUCKETS; i++) { assertEquals(stats.isStandardBucketSupported(i), newStats.isStandardBucketSupported(i)); - assertEquals(stats.getAccumulatedStandardBucketEnergy(i), - newStats.getAccumulatedStandardBucketEnergy(i)); + assertEquals(stats.getAccumulatedStandardBucketCharge(i), + newStats.getAccumulatedStandardBucketCharge(i)); } for (int i = 0; i < numCustomBuckets; i++) { - assertEquals(stats.getAccumulatedCustomBucketEnergy(i), - newStats.getAccumulatedCustomBucketEnergy(i)); + assertEquals(stats.getAccumulatedCustomBucketCharge(i), + newStats.getAccumulatedCustomBucketCharge(i)); } - assertEquals(ENERGY_DATA_UNAVAILABLE, - newStats.getAccumulatedCustomBucketEnergy(numCustomBuckets + 1)); + assertEquals(POWER_DATA_UNAVAILABLE, + newStats.getAccumulatedCustomBucketCharge(numCustomBuckets + 1)); parcel.recycle(); } @Test public void testCreateAndReadSummaryFromParcel_existingTemplate() { - final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS]; + final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS]; final int numCustomBuckets = 2; - supportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true; - supportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false; - supportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true; - - final MeasuredEnergyStats template - = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets); - template.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10); - template.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5); - template.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40); + supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true; + supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false; + supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true; + + final MeasuredEnergyStats template = + new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets); + template.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10); + template.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5); + template.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40); template.updateCustomBucket(0, 50); final MeasuredEnergyStats stats = MeasuredEnergyStats.createFromTemplate(template); - stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 200); - stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 7); - stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 63); + stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 200); + stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 7); + stats.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 63); stats.updateCustomBucket(0, 315); stats.updateCustomBucket(1, 316); final Parcel parcel = Parcel.obtain(); MeasuredEnergyStats.writeSummaryToParcel(stats, parcel, false); - final boolean[] newsupportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS]; - newsupportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true; - newsupportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = true; // switched false > true - newsupportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = false; // switched true > false - final MeasuredEnergyStats newTemplate - = new MeasuredEnergyStats(newsupportedStandardBuckets, numCustomBuckets); + final boolean[] newsupportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS]; + newsupportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true; + newsupportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = true; // switched false > true + newsupportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = false; // switched true > false + final MeasuredEnergyStats newTemplate = + new MeasuredEnergyStats(newsupportedStandardBuckets, numCustomBuckets); parcel.setDataPosition(0); final MeasuredEnergyStats newStats = MeasuredEnergyStats.createAndReadSummaryFromParcel(parcel, newTemplate); - for (int i = 0; i < NUMBER_STANDARD_ENERGY_BUCKETS; i++) { + for (int i = 0; i < NUMBER_STANDARD_POWER_BUCKETS; i++) { if (!newsupportedStandardBuckets[i]) { assertFalse(newStats.isStandardBucketSupported(i)); - assertEquals(ENERGY_DATA_UNAVAILABLE, - newStats.getAccumulatedStandardBucketEnergy(i)); + assertEquals(POWER_DATA_UNAVAILABLE, + newStats.getAccumulatedStandardBucketCharge(i)); } else if (!supportedStandardBuckets[i]) { assertTrue(newStats.isStandardBucketSupported(i)); - assertEquals(0L, newStats.getAccumulatedStandardBucketEnergy(i)); + assertEquals(0L, newStats.getAccumulatedStandardBucketCharge(i)); } else { assertTrue(newStats.isStandardBucketSupported(i)); - assertEquals(stats.getAccumulatedStandardBucketEnergy(i), - newStats.getAccumulatedStandardBucketEnergy(i)); + assertEquals(stats.getAccumulatedStandardBucketCharge(i), + newStats.getAccumulatedStandardBucketCharge(i)); } } for (int i = 0; i < numCustomBuckets; i++) { - assertEquals(stats.getAccumulatedCustomBucketEnergy(i), - newStats.getAccumulatedCustomBucketEnergy(i)); + assertEquals(stats.getAccumulatedCustomBucketCharge(i), + newStats.getAccumulatedCustomBucketCharge(i)); } - assertEquals(ENERGY_DATA_UNAVAILABLE, - newStats.getAccumulatedCustomBucketEnergy(numCustomBuckets + 1)); + assertEquals(POWER_DATA_UNAVAILABLE, + newStats.getAccumulatedCustomBucketCharge(numCustomBuckets + 1)); parcel.recycle(); } @Test public void testCreateAndReadSummaryFromParcel_skipZero() { - final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS]; + final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS]; final int numCustomBuckets = 2; Arrays.fill(supportedStandardBuckets, true); - final MeasuredEnergyStats stats - = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets); - // Accumulate energy in one bucket and one custom bucket, the rest should be zero - stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 200); + final MeasuredEnergyStats stats = + new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets); + // Accumulate charge in one bucket and one custom bucket, the rest should be zero + stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 200); stats.updateCustomBucket(1, 60); // Let's try parcelling with including zeros @@ -254,20 +254,20 @@ public class MeasuredEnergyStatsTest { MeasuredEnergyStats newStats = MeasuredEnergyStats.createAndReadSummaryFromParcel( includeZerosParcel); - for (int i = 0; i < NUMBER_STANDARD_ENERGY_BUCKETS; i++) { - if (i == ENERGY_BUCKET_SCREEN_ON) { + for (int i = 0; i < NUMBER_STANDARD_POWER_BUCKETS; i++) { + if (i == POWER_BUCKET_SCREEN_ON) { assertEquals(stats.isStandardBucketSupported(i), newStats.isStandardBucketSupported(i)); - assertEquals(stats.getAccumulatedStandardBucketEnergy(i), - newStats.getAccumulatedStandardBucketEnergy(i)); + assertEquals(stats.getAccumulatedStandardBucketCharge(i), + newStats.getAccumulatedStandardBucketCharge(i)); } else { assertTrue(newStats.isStandardBucketSupported(i)); - assertEquals(0L, newStats.getAccumulatedStandardBucketEnergy(i)); + assertEquals(0L, newStats.getAccumulatedStandardBucketCharge(i)); } } - assertEquals(0L, newStats.getAccumulatedCustomBucketEnergy(0)); - assertEquals(stats.getAccumulatedCustomBucketEnergy(1), - newStats.getAccumulatedCustomBucketEnergy(1)); + assertEquals(0L, newStats.getAccumulatedCustomBucketCharge(0)); + assertEquals(stats.getAccumulatedCustomBucketCharge(1), + newStats.getAccumulatedCustomBucketCharge(1)); includeZerosParcel.recycle(); // Now let's try parcelling with skipping zeros @@ -277,37 +277,37 @@ public class MeasuredEnergyStatsTest { newStats = MeasuredEnergyStats.createAndReadSummaryFromParcel(skipZerosParcel); - for (int i = 0; i < NUMBER_STANDARD_ENERGY_BUCKETS; i++) { - if (i == ENERGY_BUCKET_SCREEN_ON) { + for (int i = 0; i < NUMBER_STANDARD_POWER_BUCKETS; i++) { + if (i == POWER_BUCKET_SCREEN_ON) { assertEquals(stats.isStandardBucketSupported(i), newStats.isStandardBucketSupported(i)); - assertEquals(stats.getAccumulatedStandardBucketEnergy(i), - newStats.getAccumulatedStandardBucketEnergy(i)); + assertEquals(stats.getAccumulatedStandardBucketCharge(i), + newStats.getAccumulatedStandardBucketCharge(i)); } else { assertFalse(newStats.isStandardBucketSupported(i)); - assertEquals(ENERGY_DATA_UNAVAILABLE, - newStats.getAccumulatedStandardBucketEnergy(i)); + assertEquals(POWER_DATA_UNAVAILABLE, + newStats.getAccumulatedStandardBucketCharge(i)); } } - assertEquals(0L, newStats.getAccumulatedCustomBucketEnergy(0)); - assertEquals(stats.getAccumulatedCustomBucketEnergy(1), - newStats.getAccumulatedCustomBucketEnergy(1)); + assertEquals(0L, newStats.getAccumulatedCustomBucketCharge(0)); + assertEquals(stats.getAccumulatedCustomBucketCharge(1), + newStats.getAccumulatedCustomBucketCharge(1)); skipZerosParcel.recycle(); } @Test public void testCreateAndReadSummaryFromParcel_nullTemplate() { - final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS]; + final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS]; final int numCustomBuckets = 2; - supportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true; - supportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false; - supportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true; - - final MeasuredEnergyStats stats - = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets); - stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10); - stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5); - stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40); + supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true; + supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false; + supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true; + + final MeasuredEnergyStats stats = + new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets); + stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10); + stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5); + stats.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40); stats.updateCustomBucket(0, 50); stats.updateCustomBucket(1, 60); @@ -315,40 +315,40 @@ public class MeasuredEnergyStatsTest { MeasuredEnergyStats.writeSummaryToParcel(stats, parcel, false); parcel.setDataPosition(0); - MeasuredEnergyStats newStats - = MeasuredEnergyStats.createAndReadSummaryFromParcel(parcel, null); + MeasuredEnergyStats newStats = + MeasuredEnergyStats.createAndReadSummaryFromParcel(parcel, null); assertNull(newStats); parcel.recycle(); } @Test public void testCreateAndReadSummaryFromParcel_boring() { - final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS]; + final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS]; final int numCustomBuckets = 2; - supportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true; - supportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false; - supportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true; - - final MeasuredEnergyStats template - = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets); - template.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10); - template.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5); - template.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40); + supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true; + supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false; + supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true; + + final MeasuredEnergyStats template = + new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets); + template.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10); + template.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5); + template.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40); template.updateCustomBucket(0, 50); final MeasuredEnergyStats stats = MeasuredEnergyStats.createFromTemplate(template); - stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 0L); - stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 7L); + stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 0L); + stats.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 7L); final Parcel parcel = Parcel.obtain(); MeasuredEnergyStats.writeSummaryToParcel(stats, parcel, false); - final boolean[] newSupportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS]; - newSupportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true; - newSupportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = true; // switched false > true - newSupportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = false; // switched true > false - final MeasuredEnergyStats newTemplate - = new MeasuredEnergyStats(newSupportedStandardBuckets, numCustomBuckets); + final boolean[] newSupportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS]; + newSupportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true; + newSupportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = true; // switched false > true + newSupportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = false; // switched true > false + final MeasuredEnergyStats newTemplate = + new MeasuredEnergyStats(newSupportedStandardBuckets, numCustomBuckets); parcel.setDataPosition(0); final MeasuredEnergyStats newStats = @@ -361,35 +361,35 @@ public class MeasuredEnergyStatsTest { @Test public void testUpdateBucket() { - final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS]; + final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS]; final int numCustomBuckets = 2; - supportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true; - supportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false; - supportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true; + supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true; + supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false; + supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true; - final MeasuredEnergyStats stats - = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets); - stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10); - stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_DOZE, 30); - stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40); - stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5); + final MeasuredEnergyStats stats = + new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets); + stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10); + stats.updateStandardBucket(POWER_BUCKET_SCREEN_DOZE, 30); + stats.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40); + stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5); stats.updateCustomBucket(0, 50); stats.updateCustomBucket(1, 60); stats.updateCustomBucket(0, 3); - assertEquals(15, stats.getAccumulatedStandardBucketEnergy(ENERGY_BUCKET_SCREEN_ON)); - assertEquals(ENERGY_DATA_UNAVAILABLE, - stats.getAccumulatedStandardBucketEnergy(ENERGY_BUCKET_SCREEN_DOZE)); - assertEquals(40, stats.getAccumulatedStandardBucketEnergy(ENERGY_BUCKET_SCREEN_OTHER)); - assertEquals(50 + 3, stats.getAccumulatedCustomBucketEnergy(0)); - assertEquals(60, stats.getAccumulatedCustomBucketEnergy(1)); + assertEquals(15, stats.getAccumulatedStandardBucketCharge(POWER_BUCKET_SCREEN_ON)); + assertEquals(POWER_DATA_UNAVAILABLE, + stats.getAccumulatedStandardBucketCharge(POWER_BUCKET_SCREEN_DOZE)); + assertEquals(40, stats.getAccumulatedStandardBucketCharge(POWER_BUCKET_SCREEN_OTHER)); + assertEquals(50 + 3, stats.getAccumulatedCustomBucketCharge(0)); + assertEquals(60, stats.getAccumulatedCustomBucketCharge(1)); } @Test public void testIsValidCustomBucket() { - final MeasuredEnergyStats stats - = new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_ENERGY_BUCKETS], 3); + final MeasuredEnergyStats stats = + new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], 3); assertFalse(stats.isValidCustomBucket(-1)); assertTrue(stats.isValidCustomBucket(0)); assertTrue(stats.isValidCustomBucket(1)); @@ -397,24 +397,24 @@ public class MeasuredEnergyStatsTest { assertFalse(stats.isValidCustomBucket(3)); assertFalse(stats.isValidCustomBucket(4)); - final MeasuredEnergyStats boringStats - = new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_ENERGY_BUCKETS], 0); + final MeasuredEnergyStats boringStats = + new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], 0); assertFalse(boringStats.isValidCustomBucket(-1)); assertFalse(boringStats.isValidCustomBucket(0)); assertFalse(boringStats.isValidCustomBucket(1)); } @Test - public void testGetAccumulatedCustomBucketEnergies() { - final MeasuredEnergyStats stats - = new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_ENERGY_BUCKETS], 3); + public void testGetAccumulatedCustomBucketCharges() { + final MeasuredEnergyStats stats = + new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], 3); stats.updateCustomBucket(0, 50); stats.updateCustomBucket(1, 60); stats.updateCustomBucket(2, 13); stats.updateCustomBucket(1, 70); - final long[] output = stats.getAccumulatedCustomBucketEnergies(); + final long[] output = stats.getAccumulatedCustomBucketCharges(); assertEquals(3, output.length); assertEquals(50, output[0]); @@ -423,73 +423,73 @@ public class MeasuredEnergyStatsTest { } @Test - public void testGetAccumulatedCustomBucketEnergies_empty() { - final MeasuredEnergyStats stats - = new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_ENERGY_BUCKETS], 0); + public void testGetAccumulatedCustomBucketCharges_empty() { + final MeasuredEnergyStats stats = + new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], 0); - final long[] output = stats.getAccumulatedCustomBucketEnergies(); + final long[] output = stats.getAccumulatedCustomBucketCharges(); assertEquals(0, output.length); } @Test - public void testGetNumberCustomEnergyBuckets() { - assertEquals(0, new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_ENERGY_BUCKETS], 0) - .getNumberCustomEnergyBuckets()); - assertEquals(3, new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_ENERGY_BUCKETS], 3) - .getNumberCustomEnergyBuckets()); + public void testGetNumberCustomChargeBuckets() { + assertEquals(0, new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], 0) + .getNumberCustomPowerBuckets()); + assertEquals(3, new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_POWER_BUCKETS], 3) + .getNumberCustomPowerBuckets()); } @Test public void testReset() { - final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_ENERGY_BUCKETS]; + final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS]; final int numCustomBuckets = 2; - supportedStandardBuckets[ENERGY_BUCKET_SCREEN_ON] = true; - supportedStandardBuckets[ENERGY_BUCKET_SCREEN_DOZE] = false; - supportedStandardBuckets[ENERGY_BUCKET_SCREEN_OTHER] = true; - - final MeasuredEnergyStats stats - = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets); - stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10); - stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5); - stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40); + supportedStandardBuckets[POWER_BUCKET_SCREEN_ON] = true; + supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false; + supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true; + + final MeasuredEnergyStats stats = + new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets); + stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10); + stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5); + stats.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40); stats.updateCustomBucket(0, 50); stats.updateCustomBucket(1, 60); MeasuredEnergyStats.resetIfNotNull(stats); - // All energy should be reset to 0 - for (int i = 0; i < NUMBER_STANDARD_ENERGY_BUCKETS; i++) { + // All charges should be reset to 0 + for (int i = 0; i < NUMBER_STANDARD_POWER_BUCKETS; i++) { if (supportedStandardBuckets[i]) { assertTrue(stats.isStandardBucketSupported(i)); - assertEquals(0, stats.getAccumulatedStandardBucketEnergy(i)); + assertEquals(0, stats.getAccumulatedStandardBucketCharge(i)); } else { assertFalse(stats.isStandardBucketSupported(i)); - assertEquals(ENERGY_DATA_UNAVAILABLE, stats.getAccumulatedStandardBucketEnergy(i)); + assertEquals(POWER_DATA_UNAVAILABLE, stats.getAccumulatedStandardBucketCharge(i)); } } for (int i = 0; i < numCustomBuckets; i++) { - assertEquals(0, stats.getAccumulatedCustomBucketEnergy(i)); + assertEquals(0, stats.getAccumulatedCustomBucketCharge(i)); } // Values should increase as usual. - stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 70); - assertEquals(70L, stats.getAccumulatedStandardBucketEnergy(ENERGY_BUCKET_SCREEN_ON)); + stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 70); + assertEquals(70L, stats.getAccumulatedStandardBucketCharge(POWER_BUCKET_SCREEN_ON)); stats.updateCustomBucket(1, 12); - assertEquals(12L, stats.getAccumulatedCustomBucketEnergy(1)); + assertEquals(12L, stats.getAccumulatedCustomBucketCharge(1)); } - /** Test that states are mapped to the expected energy buckets. Beware of mapping changes. */ + /** Test that states are mapped to the expected power buckets. Beware of mapping changes. */ @Test public void testStandardBucketMapping() { int exp; - exp = ENERGY_BUCKET_SCREEN_ON; - assertEquals(exp, MeasuredEnergyStats.getDisplayEnergyBucket(Display.STATE_ON)); - assertEquals(exp, MeasuredEnergyStats.getDisplayEnergyBucket(Display.STATE_VR)); - assertEquals(exp, MeasuredEnergyStats.getDisplayEnergyBucket(Display.STATE_ON_SUSPEND)); + exp = POWER_BUCKET_SCREEN_ON; + assertEquals(exp, MeasuredEnergyStats.getDisplayPowerBucket(Display.STATE_ON)); + assertEquals(exp, MeasuredEnergyStats.getDisplayPowerBucket(Display.STATE_VR)); + assertEquals(exp, MeasuredEnergyStats.getDisplayPowerBucket(Display.STATE_ON_SUSPEND)); - exp = ENERGY_BUCKET_SCREEN_DOZE; - assertEquals(exp, MeasuredEnergyStats.getDisplayEnergyBucket(Display.STATE_DOZE)); - assertEquals(exp, MeasuredEnergyStats.getDisplayEnergyBucket(Display.STATE_DOZE_SUSPEND)); + exp = POWER_BUCKET_SCREEN_DOZE; + assertEquals(exp, MeasuredEnergyStats.getDisplayPowerBucket(Display.STATE_DOZE)); + assertEquals(exp, MeasuredEnergyStats.getDisplayPowerBucket(Display.STATE_DOZE_SUSPEND)); } } diff --git a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java index 79b4d8bc5f1c..055fc7171fa0 100644 --- a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java +++ b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java @@ -208,6 +208,11 @@ public final class DeviceStateManagerGlobalTest { } mCallbacks.add(callback); + try { + callback.onDeviceStateInfoChanged(getInfo()); + } catch (RemoteException e) { + // Do nothing. Should never happen. + } } @Override diff --git a/data/etc/car/Android.bp b/data/etc/car/Android.bp index 2f41b9084f40..89644e2320c1 100644 --- a/data/etc/car/Android.bp +++ b/data/etc/car/Android.bp @@ -146,6 +146,13 @@ prebuilt_etc { } 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/packages/SystemUI/res/drawable/end_guest_button_background.xml b/data/etc/car/com.android.car.rotary.xml index 5644b657a609..eddef1acbbc7 100644 --- a/packages/SystemUI/res/drawable/end_guest_button_background.xml +++ b/data/etc/car/com.android.car.rotary.xml @@ -1,5 +1,4 @@ <?xml version="1.0" encoding="utf-8"?> - <!-- ~ Copyright (C) 2021 The Android Open Source Project ~ @@ -13,13 +12,12 @@ ~ 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 + ~ 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> -<shape xmlns:android="http://schemas.android.com/apk/res/android" - android:shape="rectangle"> - <stroke - android:width="@dimen/end_guest_button_border_size" - android:color="?android:attr/colorControlHighlight" /> - <corners android:radius="@dimen/end_guest_button_corner_radius" /> -</shape> diff --git a/data/etc/platform.xml b/data/etc/platform.xml index ea42246e8262..77a38a9bb1a0 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/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index fae89d65ddd1..c49fe8563dab 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -486,6 +486,8 @@ applications that come with the platform <permission name="android.permission.READ_PEOPLE_DATA" /> <!-- Permission required for CTS test - UiTranslationManagerTest --> <permission name="android.permission.MANAGE_UI_TRANSLATION" /> + <!-- Permission required for CTS test - ClipboardManagerTest --> + <permission name="android.permission.SET_CLIP_SOURCE" /> </privapp-permissions> <privapp-permissions package="com.android.statementservice"> diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 30c2fce4a1ee..b7bf8ab75799 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", @@ -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 d1e94dfed4a8..a927f53e3b5f 100644 --- a/errorprone/Android.bp +++ b/errorprone/Android.bp @@ -36,11 +36,12 @@ java_library_host { 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 @@ java_test_host { "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 ee4552fb3b33..000000000000 --- a/errorprone/TEST_MAPPING +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presubmit": [ - { - "name": "error_prone_android_framework_test" - } - ] -} diff --git a/graphics/java/android/graphics/HardwareRendererObserver.java b/graphics/java/android/graphics/HardwareRendererObserver.java index da9d03c639f7..e2a05723166f 100644 --- a/graphics/java/android/graphics/HardwareRendererObserver.java +++ b/graphics/java/android/graphics/HardwareRendererObserver.java @@ -62,7 +62,7 @@ public class HardwareRendererObserver { * @param handler the Handler to use when invoking callbacks */ public HardwareRendererObserver(@NonNull OnFrameMetricsAvailableListener listener, - @NonNull long[] frameMetrics, @NonNull Handler handler) { + @NonNull long[] frameMetrics, @NonNull Handler handler, boolean waitForPresentTime) { if (handler == null || handler.getLooper() == null) { throw new NullPointerException("handler and its looper cannot be null"); } @@ -74,7 +74,7 @@ public class HardwareRendererObserver { mFrameMetrics = frameMetrics; mHandler = handler; mListener = listener; - mNativePtr = new VirtualRefBasePtr(nCreateObserver()); + mNativePtr = new VirtualRefBasePtr(nCreateObserver(waitForPresentTime)); } /*package*/ long getNativeInstance() { @@ -98,6 +98,6 @@ public class HardwareRendererObserver { }); } - private native long nCreateObserver(); + private native long nCreateObserver(boolean waitForPresentTime); private static native int nGetNextBuffer(long nativePtr, long[] data); } diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java index f6f770be3de8..da5162b9e15e 100644 --- a/graphics/java/android/graphics/RenderNode.java +++ b/graphics/java/android/graphics/RenderNode.java @@ -719,11 +719,11 @@ public final class RenderNode { /** @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 @@ public final class RenderNode { 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 0244ce97c0d4..df79912128fe 100644 --- a/keystore/java/android/security/AppUriAuthenticationPolicy.java +++ b/keystore/java/android/security/AppUriAuthenticationPolicy.java @@ -238,4 +238,21 @@ public final class AppUriAuthenticationPolicy implements Parcelable { 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 684eebe6ffde..091f5795784f 100644 --- a/keystore/java/android/security/IKeyChainService.aidl +++ b/keystore/java/android/security/IKeyChainService.aidl @@ -68,4 +68,7 @@ interface IKeyChainService { // 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 65a81cd57f41..11cb2b7c724b 100644 --- a/keystore/java/android/security/KeyChain.java +++ b/keystore/java/android/security/KeyChain.java @@ -23,6 +23,7 @@ import android.annotation.Nullable; 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 @@ public final class KeyChain { } /** + * 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 65d433abe166..9a8b659f3db4 100644 --- a/keystore/java/android/security/UrisToAliases.java +++ b/keystore/java/android/security/UrisToAliases.java @@ -30,6 +30,7 @@ import java.io.IOException; 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 final class UrisToAliases implements Parcelable { 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 c79c12cd3343..72735a787b7f 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -279,8 +279,10 @@ import javax.security.auth.x500.X500Principal; * } */ 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 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu } 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/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java index 992454285738..0006b92b1b9b 100644 --- a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java +++ b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java @@ -18,6 +18,7 @@ package android.security.keystore2; import android.app.ActivityThread; import android.hardware.biometrics.BiometricManager; +import android.hardware.security.keymint.ErrorCode; import android.security.GateKeeper; import android.security.KeyStore; import android.security.KeyStoreException; @@ -183,15 +184,19 @@ abstract class KeyStoreCryptoOperationUtils { try { operation.abort(); } catch (KeyStoreException e) { - // We log this error, but we can afford to ignore it. Dropping the reference - // to the KeyStoreOperation is enough to clean up all related resources even - // in the Keystore daemon. We log it anyway, because it may indicate some - // underlying problem that is worth debugging. - Log.w( - "KeyStoreCryptoOperationUtils", - "Encountered error trying to abort a keystore operation.", - e - ); + // Invalid operation handle is very common at this point. It occurs every time + // an already finalized operation gets aborted. + if (e.getErrorCode() != ErrorCode.INVALID_OPERATION_HANDLE) { + // This error gets logged but ignored. Dropping the reference + // to the KeyStoreOperation is enough to clean up all related resources even + // in the Keystore daemon. It gets logged anyway, because it may indicate some + // underlying problem that is worth debugging. + Log.w( + "KeyStoreCryptoOperationUtils", + "Encountered error trying to abort a keystore operation.", + e + ); + } } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java index 9ddeb2fc6e1e..cb04bd7ce02b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java @@ -28,10 +28,13 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager.RunningTaskInfo; +import android.app.TaskInfo; import android.content.Context; +import android.content.LocusId; import android.os.Binder; import android.os.IBinder; import android.util.ArrayMap; +import android.util.ArraySet; import android.util.Log; import android.util.SparseArray; import android.view.SurfaceControl; @@ -50,6 +53,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; /** * Unified task organizer for all components in the shell. @@ -96,6 +100,17 @@ public class ShellTaskOrganizer extends TaskOrganizer { } /** + * Callbacks for events on a task with a locus id. + */ + public interface LocusIdListener { + /** + * Notifies when a task with a locusId becomes visible, when a visible task's locusId + * changes, or if a previously visible task with a locusId becomes invisible. + */ + void onVisibilityChanged(int taskId, LocusId locus, boolean visible); + } + + /** * Keys map from either a task id or {@link TaskListenerType}. * @see #addListenerForTaskId * @see #addListenerForType @@ -109,6 +124,13 @@ public class ShellTaskOrganizer extends TaskOrganizer { /** @see #setPendingLaunchCookieListener */ private final ArrayMap<IBinder, TaskListener> mLaunchCookieToListener = new ArrayMap<>(); + // Keeps track of taskId's with visible locusIds. Used to notify any {@link LocusIdListener}s + // that might be set. + private final SparseArray<LocusId> mVisibleTasksWithLocusId = new SparseArray<>(); + + /** @see #addLocusIdListener */ + private final ArraySet<LocusIdListener> mLocusIdListeners = new ArraySet<>(); + private final Object mLock = new Object(); private StartingSurface mStartingSurface; @@ -162,9 +184,7 @@ public class ShellTaskOrganizer extends TaskOrganizer { * @hide */ public void initStartingSurface(StartingSurface startingSurface) { - synchronized (mLock) { - mStartingSurface = startingSurface; - } + mStartingSurface = startingSurface; } /** @@ -257,6 +277,28 @@ public class ShellTaskOrganizer extends TaskOrganizer { } } + /** + * Adds a listener to be notified for {@link LocusId} visibility changes. + */ + public void addLocusIdListener(LocusIdListener listener) { + synchronized (mLock) { + mLocusIdListeners.add(listener); + for (int i = 0; i < mVisibleTasksWithLocusId.size(); i++) { + listener.onVisibilityChanged(mVisibleTasksWithLocusId.keyAt(i), + mVisibleTasksWithLocusId.valueAt(i), true /* visible */); + } + } + } + + /** + * Removes listener. + */ + public void removeLocusIdListener(LocusIdListener listener) { + synchronized (mLock) { + mLocusIdListeners.remove(listener); + } + } + @Override public void addStartingWindow(StartingWindowInfo info, IBinder appToken) { if (mStartingSurface != null) { @@ -294,6 +336,7 @@ public class ShellTaskOrganizer extends TaskOrganizer { if (listener != null) { listener.onTaskAppeared(info.getTaskInfo(), info.getLeash()); } + notifyLocusVisibilityIfNeeded(info.getTaskInfo()); notifySizeCompatUI(info.getTaskInfo(), listener); } @@ -310,6 +353,7 @@ public class ShellTaskOrganizer extends TaskOrganizer { if (!updated && newListener != null) { newListener.onTaskInfoChanged(taskInfo); } + notifyLocusVisibilityIfNeeded(taskInfo); if (updated || !taskInfo.equalsForSizeCompat(data.getTaskInfo())) { // Notify the size compat UI if the listener or task info changed. notifySizeCompatUI(taskInfo, newListener); @@ -338,6 +382,7 @@ public class ShellTaskOrganizer extends TaskOrganizer { if (listener != null) { listener.onTaskVanished(taskInfo); } + notifyLocusVisibilityIfNeeded(taskInfo); // Pass null for listener to remove the size compat UI on this task if there is any. notifySizeCompatUI(taskInfo, null /* taskListener */); } @@ -366,6 +411,39 @@ public class ShellTaskOrganizer extends TaskOrganizer { return true; } + private void notifyLocusVisibilityIfNeeded(TaskInfo taskInfo) { + final int taskId = taskInfo.taskId; + final LocusId prevLocus = mVisibleTasksWithLocusId.get(taskId); + final boolean sameLocus = Objects.equals(prevLocus, taskInfo.mTopActivityLocusId); + if (prevLocus == null) { + // New visible locus + if (taskInfo.mTopActivityLocusId != null && taskInfo.isVisible) { + mVisibleTasksWithLocusId.put(taskId, taskInfo.mTopActivityLocusId); + notifyLocusIdChange(taskId, taskInfo.mTopActivityLocusId, true /* visible */); + } + } else if (sameLocus && !taskInfo.isVisible) { + // Hidden locus + mVisibleTasksWithLocusId.remove(taskId); + notifyLocusIdChange(taskId, taskInfo.mTopActivityLocusId, false /* visible */); + } else if (!sameLocus) { + // Changed locus + if (taskInfo.isVisible) { + mVisibleTasksWithLocusId.put(taskId, taskInfo.mTopActivityLocusId); + notifyLocusIdChange(taskId, prevLocus, false /* visible */); + notifyLocusIdChange(taskId, taskInfo.mTopActivityLocusId, true /* visible */); + } else { + mVisibleTasksWithLocusId.remove(taskInfo.taskId); + notifyLocusIdChange(taskId, prevLocus, false /* visible */); + } + } + } + + private void notifyLocusIdChange(int taskId, LocusId locus, boolean visible) { + for (int i = 0; i < mLocusIdListeners.size(); i++) { + mLocusIdListeners.valueAt(i).onVisibilityChanged(taskId, locus, visible); + } + } + /** * Notifies {@link SizeCompatUIController} about the size compat info changed on the give Task * to update the UI accordingly. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java index 8697be9db3fd..d6079b6ce984 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java @@ -28,6 +28,7 @@ import android.app.PendingIntent; import android.app.Person; import android.content.Context; import android.content.Intent; +import android.content.LocusId; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ShortcutInfo; @@ -62,13 +63,16 @@ public class Bubble implements BubbleViewProvider { private final String mKey; @Nullable private final String mGroupKey; + @Nullable + private final LocusId mLocusId; + private final Executor mMainExecutor; private long mLastUpdated; private long mLastAccessed; @Nullable - private Bubbles.NotificationSuppressionChangedListener mSuppressionListener; + private Bubbles.SuppressionChangedListener mSuppressionListener; /** Whether the bubble should show a dot for the notification indicating updated content. */ private boolean mShowBubbleUpdateDot = true; @@ -163,13 +167,14 @@ public class Bubble implements BubbleViewProvider { */ Bubble(@NonNull final String key, @NonNull final ShortcutInfo shortcutInfo, final int desiredHeight, final int desiredHeightResId, @Nullable final String title, - int taskId, Executor mainExecutor) { + int taskId, @Nullable final String locus, Executor mainExecutor) { Objects.requireNonNull(key); Objects.requireNonNull(shortcutInfo); mMetadataShortcutId = shortcutInfo.getId(); mShortcutInfo = shortcutInfo; mKey = key; mGroupKey = null; + mLocusId = locus != null ? new LocusId(locus) : null; mFlags = 0; mUser = shortcutInfo.getUserHandle(); mPackageName = shortcutInfo.getPackage(); @@ -184,11 +189,12 @@ public class Bubble implements BubbleViewProvider { @VisibleForTesting(visibility = PRIVATE) Bubble(@NonNull final BubbleEntry entry, - @Nullable final Bubbles.NotificationSuppressionChangedListener listener, + @Nullable final Bubbles.SuppressionChangedListener listener, final Bubbles.PendingIntentCanceledListener intentCancelListener, Executor mainExecutor) { mKey = entry.getKey(); mGroupKey = entry.getGroupKey(); + mLocusId = entry.getLocusId(); mSuppressionListener = listener; mIntentCancelListener = intent -> { if (mIntent != null) { @@ -216,6 +222,10 @@ public class Bubble implements BubbleViewProvider { return mGroupKey; } + public LocusId getLocusId() { + return mLocusId; + } + public UserHandle getUser() { return mUser; } @@ -550,6 +560,21 @@ public class Bubble implements BubbleViewProvider { } /** + * Whether this bubble is currently being hidden from the stack. + */ + boolean isSuppressed() { + return (mFlags & Notification.BubbleMetadata.FLAG_SUPPRESS_BUBBLE) != 0; + } + + /** + * Whether this bubble is able to be suppressed (i.e. has the developer opted into the API to + * hide the bubble when in the same content). + */ + boolean isSuppressable() { + return (mFlags & Notification.BubbleMetadata.FLAG_SHOULD_SUPPRESS_BUBBLE) != 0; + } + + /** * Whether this notification conversation is important. */ boolean isImportantConversation() { @@ -574,6 +599,26 @@ public class Bubble implements BubbleViewProvider { } /** + * Sets whether this bubble should be suppressed from the stack. + */ + public void setSuppressBubble(boolean suppressBubble) { + if (!isSuppressable()) { + Log.e(TAG, "calling setSuppressBubble on " + + getKey() + " when bubble not suppressable"); + return; + } + boolean prevSuppressed = isSuppressed(); + if (suppressBubble) { + mFlags |= Notification.BubbleMetadata.FLAG_SUPPRESS_BUBBLE; + } else { + mFlags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_BUBBLE; + } + if (prevSuppressed != suppressBubble && mSuppressionListener != null) { + mSuppressionListener.onBubbleNotificationSuppressionChange(this); + } + } + + /** * Sets whether the bubble for this notification should show a dot indicating updated content. */ void setShowDot(boolean showDot) { 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 1320780bfb8f..620c382ef183 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 @@ -16,7 +16,6 @@ package com.android.wm.shell.bubbles; -import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.service.notification.NotificationListenerService.REASON_CANCEL; import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; @@ -28,7 +27,6 @@ import static com.android.wm.shell.bubbles.BubblePositioner.TASKBAR_POSITION_BOT import static com.android.wm.shell.bubbles.BubblePositioner.TASKBAR_POSITION_LEFT; import static com.android.wm.shell.bubbles.BubblePositioner.TASKBAR_POSITION_NONE; import static com.android.wm.shell.bubbles.BubblePositioner.TASKBAR_POSITION_RIGHT; -import static com.android.wm.shell.bubbles.Bubbles.DISMISS_AGED; import static com.android.wm.shell.bubbles.Bubbles.DISMISS_BLOCKED; import static com.android.wm.shell.bubbles.Bubbles.DISMISS_GROUP_CANCELLED; import static com.android.wm.shell.bubbles.Bubbles.DISMISS_INVALID_INTENT; @@ -42,7 +40,6 @@ import static com.android.wm.shell.bubbles.Bubbles.DISMISS_USER_CHANGED; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.app.ActivityManager; -import android.app.ActivityTaskManager; import android.app.Notification; import android.app.PendingIntent; import android.content.Context; @@ -243,15 +240,15 @@ public class BubbleController { mBubbleData = data; mBubbleData.setListener(mBubbleDataListener); mBubbleData.setSuppressionChangedListener(bubble -> { - // Make sure NoMan knows it's not showing in the shade anymore so anyone querying it - // can tell. + // Make sure NoMan knows suppression state so that anyone querying it can tell. try { mBarService.onBubbleNotificationSuppressionChanged(bubble.getKey(), - !bubble.showInShade()); + !bubble.showInShade(), bubble.isSuppressed()); } catch (RemoteException e) { // Bad things have happened } }); + mBubbleData.setPendingIntentCancelledListener(bubble -> { if (bubble.getBubbleIntent() == null) { return; @@ -282,6 +279,8 @@ public class BubbleController { mBubbleIconFactory = new BubbleIconFactory(context); mTaskOrganizer = organizer; + mTaskOrganizer.addLocusIdListener((taskId, locus, visible) -> + mBubbleData.onLocusVisibilityChanged(taskId, locus, visible)); launcherApps.registerCallback(new LauncherApps.Callback() { @Override @@ -327,6 +326,10 @@ public class BubbleController { return mImpl; } + public ShellExecutor getMainExecutor() { + return mMainExecutor; + } + /** * Hides the current input method, wherever it may be focused, via InputMethodManagerInternal. */ @@ -1040,6 +1043,14 @@ public class BubbleController { } } + if (update.suppressedBubble != null && mStackView != null) { + mStackView.setBubbleVisibility(update.suppressedBubble, false); + } + + if (update.unsuppressedBubble != null && mStackView != null) { + mStackView.setBubbleVisibility(update.unsuppressedBubble, true); + } + // Expanding? Apply this last. if (update.expandedChanged && update.expanded) { if (mStackView != null) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java index 53b75373a647..f6e6b8f3b700 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java @@ -24,7 +24,10 @@ import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME import android.annotation.NonNull; import android.app.PendingIntent; import android.content.Context; +import android.content.LocusId; import android.content.pm.ShortcutInfo; +import android.util.ArrayMap; +import android.util.ArraySet; import android.util.Log; import android.util.Pair; import android.view.View; @@ -75,6 +78,8 @@ public class BubbleData { @Nullable Bubble updatedBubble; @Nullable Bubble addedOverflowBubble; @Nullable Bubble removedOverflowBubble; + @Nullable Bubble suppressedBubble; + @Nullable Bubble unsuppressedBubble; // Pair with Bubble and @DismissReason Integer final List<Pair<Bubble, Integer>> removedBubbles = new ArrayList<>(); @@ -95,7 +100,9 @@ public class BubbleData { || !removedBubbles.isEmpty() || addedOverflowBubble != null || removedOverflowBubble != null - || orderChanged; + || orderChanged + || suppressedBubble != null + || unsuppressedBubble != null; } void bubbleRemoved(Bubble bubbleToRemove, @DismissReason int reason) { @@ -125,6 +132,11 @@ public class BubbleData { private final List<Bubble> mOverflowBubbles; /** Bubbles that are being loaded but haven't been added to the stack just yet. */ private final HashMap<String, Bubble> mPendingBubbles; + /** Bubbles that are suppressed due to locusId. */ + private final ArrayMap<LocusId, Bubble> mSuppressedBubbles = new ArrayMap<>(); + /** Visible locusIds. */ + private final ArraySet<LocusId> mVisibleLocusIds = new ArraySet<>(); + private BubbleViewProvider mSelectedBubble; private final BubbleOverflow mOverflow; private boolean mShowingOverflow; @@ -141,7 +153,7 @@ public class BubbleData { private Listener mListener; @Nullable - private Bubbles.NotificationSuppressionChangedListener mSuppressionListener; + private Bubbles.SuppressionChangedListener mSuppressionListener; private Bubbles.PendingIntentCanceledListener mCancelledListener; /** @@ -173,7 +185,7 @@ public class BubbleData { } public void setSuppressionChangedListener( - Bubbles.NotificationSuppressionChangedListener listener) { + Bubbles.SuppressionChangedListener listener) { mSuppressionListener = listener; } @@ -321,6 +333,18 @@ public class BubbleData { bubble.setSuppressNotification(suppress); bubble.setShowDot(!isBubbleExpandedAndSelected /* show */); + LocusId locusId = bubble.getLocusId(); + if (locusId != null) { + boolean isSuppressed = mSuppressedBubbles.containsKey(locusId); + if (isSuppressed && (!bubble.isSuppressed() || !bubble.isSuppressable())) { + mSuppressedBubbles.remove(locusId); + mStateChange.unsuppressedBubble = bubble; + } else if (!isSuppressed && (bubble.isSuppressed() + || bubble.isSuppressable() && mVisibleLocusIds.contains(locusId))) { + mSuppressedBubbles.put(locusId, bubble); + mStateChange.suppressedBubble = bubble; + } + } dispatchPendingChanges(); } @@ -581,6 +605,43 @@ public class BubbleData { dispatchPendingChanges(); } + /** + * Called in response to the visibility of a locusId changing. A locusId is set on a task + * and if there's a matching bubble for that locusId then the bubble may be hidden or shown + * depending on the visibility of the locusId. + * + * @param taskId the taskId associated with the locusId visibility change. + * @param locusId the locusId whose visibility has changed. + * @param visible whether the task with the locusId is visible or not. + */ + public void onLocusVisibilityChanged(int taskId, LocusId locusId, boolean visible) { + Bubble matchingBubble = getBubbleInStackWithLocusId(locusId); + // Don't add the locus if it's from a bubble'd activity, we only suppress for non-bubbled. + if (visible && (matchingBubble == null || matchingBubble.getTaskId() != taskId)) { + mVisibleLocusIds.add(locusId); + } else { + mVisibleLocusIds.remove(locusId); + } + if (matchingBubble == null) { + return; + } + boolean isAlreadySuppressed = mSuppressedBubbles.get(locusId) != null; + if (visible && !isAlreadySuppressed && matchingBubble.isSuppressable() + && taskId != matchingBubble.getTaskId()) { + mSuppressedBubbles.put(locusId, matchingBubble); + matchingBubble.setSuppressBubble(true); + mStateChange.suppressedBubble = matchingBubble; + dispatchPendingChanges(); + } else if (!visible) { + Bubble unsuppressedBubble = mSuppressedBubbles.remove(locusId); + if (unsuppressedBubble != null) { + unsuppressedBubble.setSuppressBubble(false); + mStateChange.unsuppressedBubble = unsuppressedBubble; + } + dispatchPendingChanges(); + } + } + private void dispatchPendingChanges() { if (mListener != null && mStateChange.anythingChanged()) { mListener.applyUpdate(mStateChange); @@ -792,6 +853,18 @@ public class BubbleData { } @Nullable + private Bubble getBubbleInStackWithLocusId(LocusId locusId) { + if (locusId == null) return null; + for (int i = 0; i < mBubbles.size(); i++) { + Bubble bubble = mBubbles.get(i); + if (locusId.equals(bubble.getLocusId())) { + return bubble; + } + } + return null; + } + + @Nullable Bubble getBubbleWithView(View view) { for (int i = 0; i < mBubbles.size(); i++) { Bubble bubble = mBubbles.get(i); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt index 241755227af0..bfacd1cfe90e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt @@ -81,7 +81,8 @@ internal class BubbleDataRepository( b.rawDesiredHeight, b.rawDesiredHeightResId, b.title, - b.taskId + b.taskId, + b.locusId?.id ) } } @@ -172,6 +173,7 @@ internal class BubbleDataRepository( entity.desiredHeightResId, entity.title, entity.taskId, + entity.locus, mainExecutor ) } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEntry.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEntry.java index ff68861eb40c..5f428269fb06 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEntry.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEntry.java @@ -21,6 +21,7 @@ import static android.app.Notification.FLAG_BUBBLE; import android.app.Notification; import android.app.Notification.BubbleMetadata; import android.app.NotificationManager.Policy; +import android.content.LocusId; import android.service.notification.NotificationListenerService.Ranking; import android.service.notification.StatusBarNotification; @@ -75,6 +76,11 @@ public class BubbleEntry { return mSbn.getGroupKey(); } + /** @return the {@link LocusId} for this notification, if it exists. */ + public LocusId getLocusId() { + return mSbn.getNotification().getLocusId(); + } + /** @return the {@link BubbleMetadata} in the {@link StatusBarNotification}. */ @Nullable public BubbleMetadata getBubbleMetadata() { 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 2f31acd41408..9ef3fb54fb35 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 @@ public class BubbleExpandedView extends LinearLayout { 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/bubbles/BubbleOverflowContainerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java index 39e4e1a09019..8ee2b40d5985 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java @@ -20,29 +20,22 @@ import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_OVERFLOW; import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES; import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME; -import android.app.Activity; import android.content.Context; -import android.content.Intent; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Color; -import android.os.Bundle; -import android.os.IBinder; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.view.WindowManager; import android.view.accessibility.AccessibilityNodeInfo; -import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; -import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.RecyclerView; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java index 78820a8fa870..64a44ca9e7e9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java @@ -912,9 +912,6 @@ public class BubbleStackView extends FrameLayout removeOnLayoutChangeListener(mOrientationChangedListener); }; - // This must be a separate OnDrawListener since it should be called for every draw. - getViewTreeObserver().addOnDrawListener(mSystemGestureExcludeUpdater); - final ColorMatrix animatedMatrix = new ColorMatrix(); final ColorMatrix darkenMatrix = new ColorMatrix(); @@ -1274,12 +1271,14 @@ public class BubbleStackView extends FrameLayout protected void onAttachedToWindow() { super.onAttachedToWindow(); getViewTreeObserver().addOnComputeInternalInsetsListener(this); + getViewTreeObserver().addOnDrawListener(mSystemGestureExcludeUpdater); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); getViewTreeObserver().removeOnPreDrawListener(mViewUpdater); + getViewTreeObserver().removeOnDrawListener(mSystemGestureExcludeUpdater); getViewTreeObserver().removeOnComputeInternalInsetsListener(this); if (mBubbleOverflow != null) { mBubbleOverflow.cleanUpExpandedState(); @@ -1688,6 +1687,13 @@ public class BubbleStackView extends FrameLayout notifyExpansionChanged(mExpandedBubble, mIsExpanded); } + void setBubbleVisibility(Bubble b, boolean visible) { + if (b.getIconView() != null) { + b.getIconView().setVisibility(visible ? VISIBLE : GONE); + } + // TODO(b/181166384): Animate in / out & handle adjusting how the bubbles overlap + } + /** * Asks the BubbleController to hide the IME from anywhere, whether it's focused on Bubbles or * not. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java index 8e061e9c9874..98978b562011 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java @@ -234,8 +234,8 @@ public interface Bubbles { void onBubbleExpandChanged(boolean isExpanding, String key); } - /** Listener to be notified when a bubbles' notification suppression state changes.*/ - interface NotificationSuppressionChangedListener { + /** Listener to be notified when the flags for notification or bubble suppression changes.*/ + interface SuppressionChangedListener { /** Called when the notification suppression state of a bubble changes. */ void onBubbleNotificationSuppressionChange(Bubble bubble); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleEntity.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleEntity.kt index d5cab5af42e4..186b9b1efa9a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleEntity.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleEntity.kt @@ -26,5 +26,6 @@ data class BubbleEntity( val desiredHeight: Int, @DimenRes val desiredHeightResId: Int, val title: String? = null, - val taskId: Int + val taskId: Int, + val locus: String? = null ) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelper.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelper.kt index 470011b136fe..a74445bba1ab 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelper.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelper.kt @@ -40,6 +40,7 @@ private const val ATTR_DESIRED_HEIGHT = "h" private const val ATTR_DESIRED_HEIGHT_RES_ID = "hid" private const val ATTR_TITLE = "t" private const val ATTR_TASK_ID = "tid" +private const val ATTR_LOCUS = "l" /** * Writes the bubbles in xml format into given output stream. @@ -73,6 +74,7 @@ private fun writeXmlEntry(serializer: XmlSerializer, bubble: BubbleEntity) { serializer.attribute(null, ATTR_DESIRED_HEIGHT_RES_ID, bubble.desiredHeightResId.toString()) bubble.title?.let { serializer.attribute(null, ATTR_TITLE, it) } serializer.attribute(null, ATTR_TASK_ID, bubble.taskId.toString()) + bubble.locus?.let { serializer.attribute(null, ATTR_LOCUS, it) } serializer.endTag(null, TAG_BUBBLE) } catch (e: IOException) { throw RuntimeException(e) @@ -107,7 +109,8 @@ private fun readXmlEntry(parser: XmlPullParser): BubbleEntity? { parser.getAttributeWithName(ATTR_DESIRED_HEIGHT)?.toInt() ?: return null, parser.getAttributeWithName(ATTR_DESIRED_HEIGHT_RES_ID)?.toInt() ?: return null, parser.getAttributeWithName(ATTR_TITLE), - parser.getAttributeWithName(ATTR_TASK_ID)?.toInt() ?: INVALID_TASK_ID + parser.getAttributeWithName(ATTR_TASK_ID)?.toInt() ?: INVALID_TASK_ID, + parser.getAttributeWithName(ATTR_LOCUS) ) } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/annotations/ShellSplashscreenThread.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/annotations/ShellSplashscreenThread.java new file mode 100644 index 000000000000..c2fd54fd96d7 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/annotations/ShellSplashscreenThread.java @@ -0,0 +1,33 @@ +/* + * 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.wm.shell.common.annotations; + + +import java.lang.annotation.Documented; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import javax.inject.Qualifier; + +/** Annotates a method or qualifies a provider that runs on the Shell splashscreen-thread */ +@Documented +@Inherited +@Qualifier +@Retention(RetentionPolicy.RUNTIME) +public @interface ShellSplashscreenThread { +} 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 6f5f2eb5723c..aab2334f8255 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 @@ public class DragAndDropPolicy { 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 @@ public class DragAndDropPolicy { @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 @@ public class DragAndDropPolicy { } @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 05526018d73f..f4c0f9384705 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 @@ class LegacySplitScreenTaskListener implements ShellTaskOrganizer.TaskListener { 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 @@ class LegacySplitScreenTaskListener implements ShellTaskOrganizer.TaskListener { @Override public void onTaskVanished(RunningTaskInfo taskInfo) { synchronized (this) { + mPositionByTaskId.remove(taskInfo.taskId); if (taskInfo.hasParentTask()) { mLeashByTaskId.remove(taskInfo.taskId); return; @@ -200,16 +204,24 @@ class LegacySplitScreenTaskListener implements ShellTaskOrganizer.TaskListener { } 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 37a91d0c121c..d90cc4769286 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 @@ public class OneHandedBackgroundPanelOrganizer extends DisplayAreaOrganizer 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 @@ public class OneHandedBackgroundPanelOrganizer extends DisplayAreaOrganizer 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 a1b1de3faee2..5fc7c987899f 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.IOverlayManager; 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.os.SystemProperties; 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 @@ public class OneHandedController { 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 @@ public class OneHandedController { */ @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 @@ public class OneHandedController { 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 @@ public class OneHandedController { @VisibleForTesting OneHandedController(Context context, + WindowManager windowManager, DisplayController displayController, OneHandedBackgroundPanelOrganizer backgroundPanelOrganizer, OneHandedDisplayAreaOrganizer displayAreaOrganizer, @@ -187,6 +191,7 @@ public class OneHandedController { ShellExecutor mainExecutor, Handler mainHandler) { mContext = context; + mWindowManager = windowManager; mBackgroundPanelOrganizer = backgroundPanelOrganizer; mDisplayAreaOrganizer = displayAreaOrganizer; mDisplayController = displayController; @@ -269,7 +274,7 @@ public class OneHandedController { 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 @@ public class OneHandedController { } /** - * 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; } @@ -515,7 +525,7 @@ public class OneHandedController { public void dump(@NonNull PrintWriter pw) { final String innerPrefix = " "; - pw.println(TAG + "states: "); + pw.println(TAG + "States: "); pw.print(innerPrefix + "mOffSetFraction="); pw.println(mOffSetFraction); pw.print(innerPrefix + "mLockedDisabled="); @@ -525,6 +535,10 @@ public class OneHandedController { mDisplayAreaOrganizer.dump(pw); } + if (mGestureHandler != null) { + mGestureHandler.dump(pw); + } + if (mTouchHandler != null) { mTouchHandler.dump(pw); } 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 4c5cc226b40f..0238fa8a7936 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 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { 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 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { * 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 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { @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(); + } + 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 new Rect(0, 0, realSize.x, realSize.y); + 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 91e649f98292..778876c76afe 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 static android.view.Display.DEFAULT_DISPLAY; 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,18 +33,24 @@ import android.view.InputMonitor; import android.view.MotionEvent; import android.view.Surface; import android.view.ViewConfiguration; +import android.view.WindowManager; import android.window.WindowContainerTransaction; +import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import com.android.wm.shell.R; import com.android.wm.shell.common.DisplayChangeController; import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.ShellExecutor; +import java.io.PrintWriter; + /** * The class manage swipe up and down gesture for 3-Button mode navigation, * others(e.g, 2-button, full gesture mode) are handled by Launcher quick steps. + * TODO(b/160934654) Migrate to Launcher quick steps */ public class OneHandedGestureHandler implements OneHandedTransitionCallback, DisplayChangeController.OnDisplayChangingListener { @@ -59,8 +64,9 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, 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; @@ -71,7 +77,6 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, InputMonitor mInputMonitor; @VisibleForTesting InputEventReceiver mInputEventReceiver; - private final DisplayController mDisplayController; private final ShellExecutor mMainExecutor; @VisibleForTesting @Nullable @@ -86,14 +91,14 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, * @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) { - mDisplayController = displayController; + mWindowManager = windowManager; mMainExecutor = mainExecutor; displayController.addDisplayChangingController(this); - mNavGestureHeight = context.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.navigation_bar_gesture_larger_height); + mNavGestureHeight = getNavBarSize(context, + displayController.getDisplayLayout(DEFAULT_DISPLAY)); mDragDistThreshold = context.getResources().getDimensionPixelSize( R.dimen.gestures_onehanded_drag_threshold); final float slop = viewConfig.getScaledTouchSlop(); @@ -206,20 +211,27 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, return mGestureRegion.contains(Math.round(x), Math.round(y)); } + private int getNavBarSize(Context context, @Nullable DisplayLayout displayLayout) { + if (displayLayout != null) { + return displayLayout.navBarFrameHeight(); + } else { + return isRotated() + ? context.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.navigation_bar_height_landscape) + : context.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.navigation_bar_height); + } + } + private void updateIsEnabled() { 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); - } - } + // Either OHM or swipe notification shade can activate in portrait mode only + if (mIsEnabled && mIsThreeButtonModeEnabled && !isRotated()) { + 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 { @@ -243,6 +255,7 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, public void onRotateDisplay(int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) { mRotation = toRotation; + updateIsEnabled(); } // TODO: Use BatchedInputEventReceiver @@ -257,6 +270,10 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, } } + private boolean isRotated() { + return mRotation == Surface.ROTATION_90 || mRotation == Surface.ROTATION_270; + } + private boolean isValidStartAngle(float deltaX, float deltaY) { final float angle = (float) Math.toDegrees(Math.atan2(deltaY, deltaX)); return angle > -(ANGLE_MAX) && angle < -(ANGLE_MIN); @@ -271,6 +288,19 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, return x * x + y * y; } + void dump(@NonNull PrintWriter pw) { + final String innerPrefix = " "; + pw.println(TAG + "States: "); + pw.print(innerPrefix + "mIsEnabled="); + pw.println(mIsEnabled); + pw.print(innerPrefix + "mNavGestureHeight="); + pw.println(mNavGestureHeight); + pw.print(innerPrefix + "mIsThreeButtonModeEnabled="); + pw.println(mIsThreeButtonModeEnabled); + pw.print(innerPrefix + "isLandscape="); + pw.println(isRotated()); + } + /** * The touch(gesture) events to notify {@link OneHandedController} start or stop one handed */ 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 3f72b80a7dce..d539835da764 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.ContentResolver; 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 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback { 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 class OneHandedTutorialHandler implements OneHandedTransitionCallback { } }; - 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 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback { 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 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback { */ 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 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback { 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 843e27f1b651..9ec7c0d173dd 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 @@ -58,13 +58,13 @@ import android.view.SurfaceControl; import android.window.TaskOrganizer; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; -import android.window.WindowContainerTransactionCallback; import com.android.internal.annotations.VisibleForTesting; import com.android.wm.shell.R; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.ShellExecutor; +import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.annotations.ShellMainThread; import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController; import com.android.wm.shell.pip.phone.PipMotionHelper; @@ -123,6 +123,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, } } + private final SyncTransactionQueue mSyncTransactionQueue; private final PipBoundsState mPipBoundsState; private final PipBoundsAlgorithm mPipBoundsAlgorithm; private final @NonNull PipMenuController mPipMenuController; @@ -172,6 +173,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, }; 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; @@ -201,7 +206,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, */ private boolean mInSwipePipToHomeTransition; - public PipTaskOrganizer(Context context, @NonNull PipBoundsState pipBoundsState, + public PipTaskOrganizer(Context context, + @NonNull SyncTransactionQueue syncTransactionQueue, + @NonNull PipBoundsState pipBoundsState, @NonNull PipBoundsAlgorithm boundsHandler, @NonNull PipMenuController pipMenuController, @NonNull PipAnimationController pipAnimationController, @@ -212,6 +219,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, @NonNull PipUiEventLogger pipUiEventLogger, @NonNull ShellTaskOrganizer shellTaskOrganizer, @ShellMainThread ShellExecutor mainExecutor) { + mSyncTransactionQueue = syncTransactionQueue; mPipBoundsState = pipBoundsState; mPipBoundsAlgorithm = boundsHandler; mPipMenuController = pipMenuController; @@ -333,21 +341,16 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, : WINDOWING_MODE_FULLSCREEN); wct.setBounds(mToken, destinationBounds); wct.setBoundsChangeTransaction(mToken, tx); - mTaskOrganizer.applySyncTransaction(wct, new WindowContainerTransactionCallback() { - @Override - public void onTransactionReady(int id, SurfaceControl.Transaction t) { - mMainExecutor.execute(() -> { - t.apply(); - // Make sure to grab the latest source hint rect as it could have been - // updated right after applying the windowing mode change. - final Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect( - mPictureInPictureParams, destinationBounds); - scheduleAnimateResizePip(mPipBoundsState.getBounds(), destinationBounds, - 0 /* startingAngle */, sourceHintRect, direction, - animationDurationMs, null /* updateBoundsCallback */); - mState = State.EXITING_PIP; - }); - } + mSyncTransactionQueue.queue(wct); + mSyncTransactionQueue.runInSync(t -> { + // Make sure to grab the latest source hint rect as it could have been + // updated right after applying the windowing mode change. + final Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect( + mPictureInPictureParams, destinationBounds); + scheduleAnimateResizePip(mPipBoundsState.getBounds(), destinationBounds, + 0 /* startingAngle */, sourceHintRect, direction, + animationDurationMs, null /* updateBoundsCallback */); + mState = State.EXITING_PIP; }); } @@ -498,18 +501,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED); wct.setBounds(mToken, destinationBounds); wct.scheduleFinishEnterPip(mToken, destinationBounds); - // TODO: Migrate to SyncTransactionQueue - mTaskOrganizer.applySyncTransaction(wct, new WindowContainerTransactionCallback() { - @Override - public void onTransactionReady(int id, SurfaceControl.Transaction t) { - mMainExecutor.execute(() -> { - t.apply(); - if (runnable != null) { - runnable.run(); - } - }); - } - }); + mSyncTransactionQueue.queue(wct); + if (runnable != null) { + mSyncTransactionQueue.runInSync(t -> runnable.run()); + } } private void sendOnPipTransitionStarted( @@ -520,12 +515,18 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, 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 +568,11 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, @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)); @@ -936,40 +942,37 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, final SurfaceControl snapshotSurface = mTaskOrganizer.takeScreenshot(mToken); mSurfaceTransactionHelper.reparentAndShowSurfaceSnapshot( mSurfaceControlTransactionFactory.getTransaction(), mLeash, snapshotSurface); - mTaskOrganizer.applySyncTransaction(wct, new WindowContainerTransactionCallback() { - @Override - public void onTransactionReady(int id, @NonNull SurfaceControl.Transaction t) { - // Scale the snapshot from its pre-resize bounds to the post-resize bounds. - final Rect snapshotSrc = new Rect(0, 0, snapshotSurface.getWidth(), - snapshotSurface.getHeight()); - final Rect snapshotDest = new Rect(0, 0, destinationBounds.width(), - destinationBounds.height()); - mSurfaceTransactionHelper.scale(t, snapshotSurface, snapshotSrc, snapshotDest); - t.apply(); - - mMainExecutor.execute(() -> { - // Start animation to fade out the snapshot. - final ValueAnimator animator = ValueAnimator.ofFloat(1.0f, 0.0f); - animator.setDuration(mEnterExitAnimationDuration); - animator.addUpdateListener(animation -> { - final float alpha = (float) animation.getAnimatedValue(); + mSyncTransactionQueue.queue(wct); + mSyncTransactionQueue.runInSync(t -> { + // Scale the snapshot from its pre-resize bounds to the post-resize bounds. + final Rect snapshotSrc = new Rect(0, 0, snapshotSurface.getWidth(), + snapshotSurface.getHeight()); + final Rect snapshotDest = new Rect(0, 0, destinationBounds.width(), + destinationBounds.height()); + mSurfaceTransactionHelper.scale(t, snapshotSurface, snapshotSrc, snapshotDest); + + mMainExecutor.execute(() -> { + // Start animation to fade out the snapshot. + final ValueAnimator animator = ValueAnimator.ofFloat(1.0f, 0.0f); + animator.setDuration(mEnterExitAnimationDuration); + animator.addUpdateListener(animation -> { + final float alpha = (float) animation.getAnimatedValue(); + final SurfaceControl.Transaction transaction = + mSurfaceControlTransactionFactory.getTransaction(); + transaction.setAlpha(snapshotSurface, alpha); + transaction.apply(); + }); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); - tx.setAlpha(snapshotSurface, alpha); + tx.remove(snapshotSurface); tx.apply(); - }); - animator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - final SurfaceControl.Transaction tx = - mSurfaceControlTransactionFactory.getTransaction(); - tx.remove(snapshotSurface); - tx.apply(); - } - }); - animator.start(); + } }); - } + animator.start(); + }); }); } else { applyFinishBoundsResize(wct, direction); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java index d742aa688fe7..81a7ae1be482 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java @@ -37,7 +37,6 @@ import androidx.dynamicanimation.animation.SpringForce; import com.android.wm.shell.animation.FloatProperties; import com.android.wm.shell.animation.PhysicsAnimator; import com.android.wm.shell.common.FloatingContentCoordinator; -import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.magnetictarget.MagnetizedObject; import com.android.wm.shell.pip.PipBoundsState; import com.android.wm.shell.pip.PipSnapAlgorithm; @@ -64,8 +63,11 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, private static final int LEAVE_PIP_DURATION = 300; private static final int SHIFT_DURATION = 300; + private static final float PIP_STIFFNESS = 700f; + private static final float PIP_DAMPING_RATIO = SpringForce.DAMPING_RATIO_NO_BOUNCY; + /** Friction to use for PIP when it moves via physics fling animations. */ - private static final float DEFAULT_FRICTION = 2f; + private static final float DEFAULT_FRICTION = 1.9f; private final Context mContext; private final PipTaskOrganizer mPipTaskOrganizer; @@ -119,13 +121,11 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, /** SpringConfig to use for fling-then-spring animations. */ private final PhysicsAnimator.SpringConfig mSpringConfig = - new PhysicsAnimator.SpringConfig( - SpringForce.STIFFNESS_MEDIUM, SpringForce.DAMPING_RATIO_LOW_BOUNCY); + new PhysicsAnimator.SpringConfig(PIP_STIFFNESS, PIP_DAMPING_RATIO); /** SpringConfig to use for springing PIP away from conflicting floating content. */ private final PhysicsAnimator.SpringConfig mConflictResolutionSpringConfig = - new PhysicsAnimator.SpringConfig( - SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY); + new PhysicsAnimator.SpringConfig(SpringForce.STIFFNESS_LOW, PIP_DAMPING_RATIO); private final Consumer<Rect> mUpdateBoundsCallback = (Rect newBounds) -> { mMenuController.updateMenuLayout(newBounds); 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 31057f8d5fb8..c726c012c6a0 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 @@ public class PipResizeGestureHandler { 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 @@ public class PipResizeGestureHandler { 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 @@ public class PipResizeGestureHandler { } // 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 7ca569349633..25a84bd46484 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 @@ package com.android.wm.shell.splitscreen; 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 @@ public interface SplitScreen extends DragAndDropPolicy.Starter { /** 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 @@ public interface SplitScreen extends DragAndDropPolicy.Starter { @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 11548adaf5d1..bb6f6f259a1e 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.ActivityTaskManager; 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 class SplitScreenController implements DragAndDropPolicy.Starter { } } - 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 @@ public class SplitScreenController implements DragAndDropPolicy.Starter { } @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 bbfbc4098d92..b180bb52e3e3 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 @@ class StageCoordinator implements SplitLayout.LayoutChangeListener, } 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 @@ class StageCoordinator implements SplitLayout.LayoutChangeListener, } 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 @@ class StageCoordinator implements SplitLayout.LayoutChangeListener, } @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 10c742b69578..b8cdc4ab4d75 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 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { 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 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { 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 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { 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 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { 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 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { 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/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java index 76497706ce4f..2973b5080ae6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java @@ -31,7 +31,6 @@ import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; import android.os.Build; import android.util.Slog; -import android.view.Window; import android.window.SplashScreenView; import com.android.internal.R; @@ -91,12 +90,13 @@ public class SplashscreenContentDrawer { return new ColorDrawable(getSystemBGColor()); } - SplashScreenView makeSplashScreenContentView(Window win, Context context, int iconRes, + SplashScreenView makeSplashScreenContentView(Context context, int iconRes, int splashscreenContentResId) { updateDensity(); // splash screen content will be deprecated after S. final SplashScreenView ssc = - makeSplashscreenContentDrawable(win, context, splashscreenContentResId); + makeSplashscreenContentDrawable(context, splashscreenContentResId); + if (ssc != null) { return ssc; } @@ -127,7 +127,6 @@ public class SplashscreenContentDrawer { } // TODO (b/173975965) Tracking the performance on improved splash screen. return builder - .setWindow(win) .setContext(context) .setThemeDrawable(themeBGDrawable) .setIconDrawable(iconDrawable) @@ -169,7 +168,6 @@ public class SplashscreenContentDrawer { private class StartingWindowViewBuilder { private Drawable mThemeBGDrawable; private Drawable mIconDrawable; - private Window mWindow; private int mIconAnimationDuration; private Context mContext; private Drawable mBrandingDrawable; @@ -193,12 +191,6 @@ public class SplashscreenContentDrawer { return this; } - StartingWindowViewBuilder setWindow(Window window) { - mWindow = window; - mBuildComplete = false; - return this; - } - StartingWindowViewBuilder setIconAnimationDuration(int iconAnimationDuration) { mIconAnimationDuration = iconAnimationDuration; mBuildComplete = false; @@ -221,7 +213,7 @@ public class SplashscreenContentDrawer { if (mBuildComplete) { return mCachedResult; } - if (mWindow == null || mContext == null) { + if (mContext == null) { Slog.e(TAG, "Unable to create StartingWindowView, lack of materials!"); return null; } @@ -237,7 +229,7 @@ public class SplashscreenContentDrawer { mFinalIconDrawable = mIconDrawable; } final int iconSize = mFinalIconDrawable != null ? (int) (mIconSize * mScale) : 0; - mCachedResult = fillViewWithIcon(mWindow, mContext, iconSize, mFinalIconDrawable); + mCachedResult = fillViewWithIcon(mContext, iconSize, mFinalIconDrawable); mBuildComplete = true; return mCachedResult; } @@ -313,7 +305,7 @@ public class SplashscreenContentDrawer { return true; } - private SplashScreenView fillViewWithIcon(Window win, Context context, + private SplashScreenView fillViewWithIcon(Context context, int iconSize, Drawable iconDrawable) { final SplashScreenView.Builder builder = new SplashScreenView.Builder(context); builder.setIconSize(iconSize).setBackgroundColor(mThemeColor); @@ -329,8 +321,6 @@ public class SplashscreenContentDrawer { if (DEBUG) { Slog.d(TAG, "fillViewWithIcon surfaceWindowView " + splashScreenView); } - win.setContentView(splashScreenView); - splashScreenView.cacheRootWindow(win); splashScreenView.makeSystemUIColorsTransparent(); return splashScreenView; } @@ -363,8 +353,8 @@ public class SplashscreenContentDrawer { return root < 0.1; } - private static SplashScreenView makeSplashscreenContentDrawable(Window win, - Context ctx, int splashscreenContentResId) { + private static SplashScreenView makeSplashscreenContentDrawable(Context ctx, + int splashscreenContentResId) { // doesn't support windowSplashscreenContent after S // TODO add an allowlist to skip some packages if needed final int targetSdkVersion = ctx.getApplicationInfo().targetSdkVersion; @@ -384,7 +374,6 @@ public class SplashscreenContentDrawer { SplashScreenView view = new SplashScreenView(ctx); view.setNotCopyable(); view.setBackground(drawable); - win.setContentView(view); return view; } 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 2c4ceffcb8f5..a594a9f31dde 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 @@ package com.android.wm.shell.startingsurface; import android.os.IBinder; import android.window.StartingWindowInfo; +import java.util.function.BiConsumer; /** * Interface to engage starting window feature. */ @@ -36,4 +37,11 @@ public interface StartingSurface { * @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/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java index 814407164750..2d1d65b87718 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java @@ -33,8 +33,10 @@ import android.hardware.display.DisplayManager; import android.os.IBinder; import android.util.Slog; import android.util.SparseArray; +import android.view.Choreographer; import android.view.Display; import android.view.View; +import android.view.Window; import android.view.WindowManager; import android.window.SplashScreenView; import android.window.SplashScreenView.SplashScreenViewParcelable; @@ -58,20 +60,25 @@ public class StartingSurfaceDrawer { private final Context mContext; private final DisplayManager mDisplayManager; - final ShellExecutor mMainExecutor; + private final ShellExecutor mSplashScreenExecutor; private final SplashscreenContentDrawer mSplashscreenContentDrawer; + protected Choreographer mChoreographer; // TODO(b/131727939) remove this when clearing ActivityRecord private static final int REMOVE_WHEN_TIMEOUT = 2000; - public StartingSurfaceDrawer(Context context, ShellExecutor mainExecutor) { + public StartingSurfaceDrawer(Context context, ShellExecutor splashScreenExecutor) { mContext = context; mDisplayManager = mContext.getSystemService(DisplayManager.class); - mMainExecutor = mainExecutor; - + mSplashScreenExecutor = splashScreenExecutor; final int maxIconAnimDuration = context.getResources().getInteger( com.android.wm.shell.R.integer.max_starting_window_intro_icon_anim_duration); mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext, maxIconAnimDuration); + mSplashScreenExecutor.execute(this::initChoreographer); + } + + protected void initChoreographer() { + mChoreographer = Choreographer.getInstance(); } private final SparseArray<StartingWindowRecord> mStartingWindowRecords = new SparseArray<>(); @@ -170,7 +177,9 @@ public class StartingSurfaceDrawer { } int windowFlags = 0; - if ((activityInfo.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0) { + final boolean enableHardAccelerated = + (activityInfo.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0; + if (enableHardAccelerated) { windowFlags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; } @@ -247,22 +256,100 @@ public class StartingSurfaceDrawer { } params.setTitle("Splash Screen " + activityInfo.packageName); - final SplashScreenView splashScreenView = - mSplashscreenContentDrawer.makeSplashScreenContentView(win, context, iconRes, - splashscreenContentResId[0]); - if (splashScreenView == null) { - Slog.w(TAG, "Adding splash screen window for " + activityInfo.packageName + " failed!"); - return; + + // TODO(b/173975965) If the target activity doesn't request FLAG_HARDWARE_ACCELERATED, we + // cannot replace the content view after first view was drawn, sounds like an issue. + new AddSplashScreenViewRunnable(taskInfo.taskId, win, context, appToken, params, iconRes, + splashscreenContentResId[0], enableHardAccelerated).run(); + } + + private class AddSplashScreenViewRunnable implements Runnable { + private final int mTaskId; + private final Window mWin; + private final IBinder mAppToken; + private final WindowManager.LayoutParams mLayoutParams; + private final Context mContext; + private final int mIconRes; + private final int mSplashscreenContentResId; + private final boolean mReplaceSplashScreenView; + private int mSequence; + + AddSplashScreenViewRunnable(int taskId, Window window, Context context, + IBinder appToken, WindowManager.LayoutParams params, int iconRes, + int splashscreenContentResId, boolean replaceSplashScreenView) { + mTaskId = taskId; + mWin = window; + mAppToken = appToken; + mContext = context; + mLayoutParams = params; + mIconRes = iconRes; + mSplashscreenContentResId = splashscreenContentResId; + mReplaceSplashScreenView = replaceSplashScreenView; } - final View view = win.getDecorView(); + private void createInitialView() { + View tempView = new View(mContext); + mWin.setContentView(tempView); + mSequence++; + final View view = mWin.getDecorView(); + final WindowManager wm = mContext.getSystemService(WindowManager.class); + if (postAddWindow(mTaskId, mAppToken, view, wm, mLayoutParams)) { + mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, this, null); + } + } - if (DEBUG_SPLASH_SCREEN) { - Slog.d(TAG, "Adding splash screen window for " - + activityInfo.packageName + " / " + appToken + ": " + view); + private SplashScreenView replaceRealView() { + final SplashScreenView sView = + mSplashscreenContentDrawer.makeSplashScreenContentView(mContext, + mIconRes, mSplashscreenContentResId); + mWin.setContentView(sView); + sView.cacheRootWindow(mWin); + return sView; + } + + private SplashScreenView initiateOnce() { + final SplashScreenView sView = + mSplashscreenContentDrawer.makeSplashScreenContentView(mContext, mIconRes, + mSplashscreenContentResId); + final View view = mWin.getDecorView(); + final WindowManager wm = mContext.getSystemService(WindowManager.class); + if (postAddWindow(mTaskId, mAppToken, view, wm, mLayoutParams)) { + mWin.setContentView(sView); + sView.cacheRootWindow(mWin); + } + return sView; + } + + @Override + public void run() { + SplashScreenView view = null; + boolean setRecord = false; + try { + if (mReplaceSplashScreenView) { + // Tricky way to make animation start faster... create the real content after + // first window drawn. The first empty window won't been see because wm will + // still need to wait for transition ready. + if (mSequence == 0) { + createInitialView(); + } else if (mSequence == 1) { + setRecord = true; + view = replaceRealView(); + } + } else { + setRecord = true; + view = initiateOnce(); + } + } catch (RuntimeException e) { + // don't crash if something else bad happens, for example a + // failure loading resources because we are loading from an app + // on external storage that has been unmounted. + Slog.w(TAG, " failed creating starting window", e); + } finally { + if (setRecord) { + setSplashScreenRecord(mTaskId, view); + } + } } - final WindowManager wm = context.getSystemService(WindowManager.class); - postAddWindow(taskInfo.taskId, appToken, view, wm, params, splashScreenView); } /** @@ -272,10 +359,10 @@ public class StartingSurfaceDrawer { TaskSnapshot snapshot) { final int taskId = startingWindowInfo.taskInfo.taskId; final TaskSnapshotWindow surface = TaskSnapshotWindow.create(startingWindowInfo, appToken, - snapshot, mMainExecutor, () -> removeWindowSynced(taskId) /* clearWindow */); - mMainExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT); + snapshot, mSplashScreenExecutor, () -> removeWindowSynced(taskId)); + mSplashScreenExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT); final StartingWindowRecord tView = - new StartingWindowRecord(null/* decorView */, surface, null /* splashScreenView */); + new StartingWindowRecord(null/* decorView */, surface); mStartingWindowRecords.put(taskId, tView); } @@ -296,6 +383,13 @@ public class StartingSurfaceDrawer { public void copySplashScreenView(int taskId) { final StartingWindowRecord preView = mStartingWindowRecords.get(taskId); SplashScreenViewParcelable parcelable; + if (preView != null) { + if (preView.isWaitForContent()) { + mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, + () -> copySplashScreenView(taskId), null); + return; + } + } if (preView != null && preView.mContentView != null && preView.mContentView.isCopyable()) { parcelable = new SplashScreenViewParcelable(preView.mContentView); @@ -309,45 +403,63 @@ public class StartingSurfaceDrawer { ActivityTaskManager.getInstance().onSplashScreenViewCopyFinished(taskId, parcelable); } - protected void postAddWindow(int taskId, IBinder appToken, - View view, WindowManager wm, WindowManager.LayoutParams params, - SplashScreenView splashScreenView) { - mMainExecutor.execute(() -> { - boolean shouldSaveView = true; - try { - wm.addView(view, params); - } catch (WindowManager.BadTokenException e) { - // ignore - Slog.w(TAG, appToken + " already running, starting window not displayed. " - + e.getMessage()); + protected boolean postAddWindow(int taskId, IBinder appToken, View view, WindowManager wm, + WindowManager.LayoutParams params) { + boolean shouldSaveView = true; + try { + wm.addView(view, params); + } catch (WindowManager.BadTokenException e) { + // ignore + Slog.w(TAG, appToken + " already running, starting window not displayed. " + + e.getMessage()); + shouldSaveView = false; + } catch (RuntimeException e) { + // don't crash if something else bad happens, for example a + // failure loading resources because we are loading from an app + // on external storage that has been unmounted. + Slog.w(TAG, appToken + " failed creating starting window", e); + shouldSaveView = false; + } finally { + if (view != null && view.getParent() == null) { + Slog.w(TAG, "view not successfully added to wm, removing view"); + wm.removeViewImmediate(view); shouldSaveView = false; - } catch (RuntimeException e) { - // don't crash if something else bad happens, for example a - // failure loading resources because we are loading from an app - // on external storage that has been unmounted. - Slog.w(TAG, appToken + " failed creating starting window", e); - shouldSaveView = false; - } finally { - if (view != null && view.getParent() == null) { - Slog.w(TAG, "view not successfully added to wm, removing view"); - wm.removeViewImmediate(view); - shouldSaveView = false; - } } - if (shouldSaveView) { - removeWindowSynced(taskId); - mMainExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT); - final StartingWindowRecord tView = new StartingWindowRecord(view, - null /* TaskSnapshotWindow */, splashScreenView); - splashScreenView.startIntroAnimation(); - mStartingWindowRecords.put(taskId, tView); - } - }); + } + if (shouldSaveView) { + removeWindowSynced(taskId); + mSplashScreenExecutor.executeDelayed(() -> removeWindowSynced(taskId), + REMOVE_WHEN_TIMEOUT); + saveSplashScreenRecord(taskId, view); + } + return shouldSaveView; + } + + private void saveSplashScreenRecord(int taskId, View view) { + final StartingWindowRecord tView = new StartingWindowRecord(view, + null/* TaskSnapshotWindow */); + mStartingWindowRecords.put(taskId, tView); + } + + private void setSplashScreenRecord(int taskId, SplashScreenView splashScreenView) { + final StartingWindowRecord record = mStartingWindowRecords.get(taskId); + if (record != null) { + record.setSplashScreenView(splashScreenView); + splashScreenView.startIntroAnimation(); + } } protected void removeWindowSynced(int taskId) { final StartingWindowRecord record = mStartingWindowRecords.get(taskId); if (record != null) { + if (record.isWaitForContent()) { + if (DEBUG_SPLASH_SCREEN) { + Slog.v(TAG, "splash screen window haven't been draw yet"); + } + mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, + () -> removeWindowSynced(taskId), null); + return; + } if (record.mDecorView != null) { if (DEBUG_SPLASH_SCREEN) { Slog.v(TAG, "Removing splash screen window for task: " + taskId); @@ -378,13 +490,24 @@ public class StartingSurfaceDrawer { private static class StartingWindowRecord { private final View mDecorView; private final TaskSnapshotWindow mTaskSnapshotWindow; - private final SplashScreenView mContentView; + private SplashScreenView mContentView; + private boolean mSetSplashScreen; - StartingWindowRecord(View decorView, TaskSnapshotWindow taskSnapshotWindow, - SplashScreenView splashScreenView) { + StartingWindowRecord(View decorView, TaskSnapshotWindow taskSnapshotWindow) { mDecorView = decorView; mTaskSnapshotWindow = taskSnapshotWindow; + } + + private void setSplashScreenView(SplashScreenView splashScreenView) { + if (mSetSplashScreen) { + return; + } mContentView = splashScreenView; + mSetSplashScreen = true; + } + + private boolean isWaitForContent() { + return mDecorView != null && !mSetSplashScreen; } } } 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 73bf8ac90c29..5eb7071fbd63 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_NEW_TASK; 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 android.window.TaskSnapshot; 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. @@ -44,6 +47,12 @@ import com.android.wm.shell.common.ShellExecutor; * starting window and attached to the Task, then when the Task want to remove the starting window, * the TaskOrganizer will receive {@link TaskOrganizer#removeStartingWindow} callback then use this * class to remove the starting window of the Task. + * Besides add/remove starting window, There is an API #setStartingWindowListener to register + * a callback when starting window is about to create which let the registerer knows the next + * starting window's type. + * So far all classes in this package is an enclose system so there is no interact with other shell + * component, all the methods must be executed in splash screen thread or the thread used in + * constructor to keep everything synchronized. * @hide */ public class StartingWindowController { @@ -53,10 +62,14 @@ public class StartingWindowController { private final StartingSurfaceDrawer mStartingSurfaceDrawer; private final StartingTypeChecker mStartingTypeChecker = new StartingTypeChecker(); + + private BiConsumer<Integer, Integer> mTaskLaunchingCallback; private final StartingSurfaceImpl mImpl = new StartingSurfaceImpl(); + private final ShellExecutor mSplashScreenExecutor; - public StartingWindowController(Context context, ShellExecutor mainExecutor) { - mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, mainExecutor); + public StartingWindowController(Context context, ShellExecutor splashScreenExecutor) { + mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, splashScreenExecutor); + mSplashScreenExecutor = splashScreenExecutor; } /** @@ -151,11 +164,24 @@ public class StartingWindowController { } } + /* + * 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) { @@ -180,17 +206,26 @@ public class StartingWindowController { @Override public void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) { - StartingWindowController.this.addStartingWindow(windowInfo, appToken); + mSplashScreenExecutor.execute(() -> + StartingWindowController.this.addStartingWindow(windowInfo, appToken)); } @Override public void removeStartingWindow(int taskId) { - StartingWindowController.this.removeStartingWindow(taskId); + mSplashScreenExecutor.execute(() -> + StartingWindowController.this.removeStartingWindow(taskId)); } @Override public void copySplashScreenView(int taskId) { - StartingWindowController.this.copySplashScreenView(taskId); + mSplashScreenExecutor.execute(() -> + StartingWindowController.this.copySplashScreenView(taskId)); + } + + @Override + public void setStartingWindowListener(BiConsumer<Integer, Integer> listener) { + mSplashScreenExecutor.execute(() -> + StartingWindowController.this.setStartingWindowListener(listener)); } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java index b7fd3cb67b2b..6e437411dcf8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java @@ -83,7 +83,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.DecorView; import com.android.internal.view.BaseIWindow; import com.android.wm.shell.common.ShellExecutor; -import com.android.wm.shell.common.annotations.ExternalThread; /** * This class represents a starting window that shows a snapshot. @@ -123,7 +122,7 @@ public class TaskSnapshotWindow { private final Window mWindow; private final Surface mSurface; private final Runnable mClearWindowHandler; - private final ShellExecutor mMainExecutor; + private final ShellExecutor mSplashScreenExecutor; private SurfaceControl mSurfaceControl; private SurfaceControl mChildSurfaceControl; private final IWindowSession mSession; @@ -252,8 +251,8 @@ public class TaskSnapshotWindow { TaskSnapshot snapshot, CharSequence title, TaskDescription taskDescription, int appearance, int windowFlags, int windowPrivateFlags, Rect taskBounds, int currentOrientation, int activityType, InsetsState topWindowInsetsState, - Runnable clearWindowHandler, ShellExecutor mainExecutor) { - mMainExecutor = mainExecutor; + Runnable clearWindowHandler, ShellExecutor splashScreenExecutor) { + mSplashScreenExecutor = splashScreenExecutor; mSurface = new Surface(); mSession = WindowManagerGlobal.getWindowSession(); mWindow = new Window(); @@ -296,7 +295,7 @@ public class TaskSnapshotWindow { // Show the latest content as soon as possible for unlocking to home. && mActivityType != ACTIVITY_TYPE_HOME) { final long delayTime = mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS - now; - mMainExecutor.executeDelayed(() -> remove(), delayTime); + mSplashScreenExecutor.executeDelayed(() -> remove(), delayTime); if (DEBUG) { Slog.d(TAG, "Defer removing snapshot surface in " + delayTime); } @@ -512,7 +511,7 @@ public class TaskSnapshotWindow { MergedConfiguration mergedConfiguration, boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId) { if (mOuter != null) { - mOuter.mMainExecutor.execute(() -> { + mOuter.mSplashScreenExecutor.execute(() -> { if (mergedConfiguration != null && mOuter.mOrientationOnCreation != mergedConfiguration.getMergedConfiguration().orientation) { 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 2182ee5590e1..629ff0db6b4a 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 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { 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 89eee67bf5af..677db10d07a7 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 @@ public class Transitions { 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 @@ public class Transitions { 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/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java index 06b492dcb409..df0a856db73c 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java @@ -27,6 +27,7 @@ import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_FULLSCR import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_MULTI_WINDOW; import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_PIP; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -37,10 +38,12 @@ import static org.mockito.Mockito.verify; import android.app.ActivityManager.RunningTaskInfo; import android.content.Context; +import android.content.LocusId; import android.content.pm.ParceledListSlice; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; +import android.util.SparseArray; import android.view.SurfaceControl; import android.window.ITaskOrganizer; import android.window.ITaskOrganizerController; @@ -105,6 +108,20 @@ public class ShellTaskOrganizerTests { } } + private class TrackingLocusIdListener implements ShellTaskOrganizer.LocusIdListener { + final SparseArray<LocusId> visibleLocusTasks = new SparseArray<>(); + final SparseArray<LocusId> invisibleLocusTasks = new SparseArray<>(); + @Override + public void onVisibilityChanged(int taskId, LocusId locus, boolean visible) { + if (visible) { + visibleLocusTasks.put(taskId, locus); + } else { + invisibleLocusTasks.put(taskId, locus); + } + } + } + + @Before public void setUp() { MockitoAnnotations.initMocks(this); @@ -299,6 +316,123 @@ public class ShellTaskOrganizerTests { null /* taskConfig */, null /* sizeCompatActivity*/, null /* taskListener */); } + @Test + public void testAddLocusListener() { + RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_MULTI_WINDOW); + task1.isVisible = true; + task1.mTopActivityLocusId = new LocusId("10"); + + RunningTaskInfo task2 = createTaskInfo(2, WINDOWING_MODE_FULLSCREEN); + task2.isVisible = true; + task2.mTopActivityLocusId = new LocusId("20"); + + RunningTaskInfo task3 = createTaskInfo(3, WINDOWING_MODE_FULLSCREEN); + task3.isVisible = true; + + mOrganizer.onTaskAppeared(task1, null); + mOrganizer.onTaskAppeared(task2, null); + mOrganizer.onTaskAppeared(task3, null); + + TrackingLocusIdListener listener = new TrackingLocusIdListener(); + mOrganizer.addLocusIdListener(listener); + + // Listener should have the locus tasks even if added after the tasks appear + assertEquals(listener.visibleLocusTasks.get(task1.taskId), task1.mTopActivityLocusId); + assertEquals(listener.visibleLocusTasks.get(task2.taskId), task2.mTopActivityLocusId); + assertFalse(listener.visibleLocusTasks.contains(task3.taskId)); + } + + @Test + public void testLocusListener_appearVanish() { + TrackingLocusIdListener listener = new TrackingLocusIdListener(); + mOrganizer.addLocusIdListener(listener); + + RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_FULLSCREEN); + task1.mTopActivityLocusId = new LocusId("10"); + + task1.isVisible = true; + mOrganizer.onTaskAppeared(task1, null); + assertTrue(listener.visibleLocusTasks.contains(task1.taskId)); + assertEquals(listener.visibleLocusTasks.get(task1.taskId), task1.mTopActivityLocusId); + + task1.isVisible = false; + mOrganizer.onTaskVanished(task1); + assertTrue(listener.invisibleLocusTasks.contains(task1.taskId)); + assertEquals(listener.invisibleLocusTasks.get(task1.taskId), task1.mTopActivityLocusId); + } + + @Test + public void testLocusListener_infoChanged() { + TrackingLocusIdListener listener = new TrackingLocusIdListener(); + mOrganizer.addLocusIdListener(listener); + + RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_MULTI_WINDOW); + task1.isVisible = true; + mOrganizer.onTaskAppeared(task1, null); + assertEquals(listener.visibleLocusTasks.size(), 0); + + task1.mTopActivityLocusId = new LocusId("10"); + mOrganizer.onTaskInfoChanged(task1); + assertTrue(listener.visibleLocusTasks.contains(task1.taskId)); + assertEquals(listener.visibleLocusTasks.get(task1.taskId), task1.mTopActivityLocusId); + + LocusId prevLocus = task1.mTopActivityLocusId; + task1.mTopActivityLocusId = new LocusId("20"); + mOrganizer.onTaskInfoChanged(task1); + + // New locus is in visible list + assertTrue(listener.visibleLocusTasks.contains(task1.taskId)); + assertEquals(listener.visibleLocusTasks.get(task1.taskId), task1.mTopActivityLocusId); + // Old locus in invisible list + assertTrue(listener.invisibleLocusTasks.contains(task1.taskId)); + assertEquals(listener.invisibleLocusTasks.get(task1.taskId), prevLocus); + } + + @Test + public void testLocusListener_infoChanged_notVisible() { + TrackingLocusIdListener listener = new TrackingLocusIdListener(); + mOrganizer.addLocusIdListener(listener); + + RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_FULLSCREEN); + task1.isVisible = true; + mOrganizer.onTaskAppeared(task1, null); + + task1.mTopActivityLocusId = new LocusId("10"); + mOrganizer.onTaskInfoChanged(task1); + assertTrue(listener.visibleLocusTasks.contains(task1.taskId)); + assertEquals(listener.visibleLocusTasks.get(task1.taskId), task1.mTopActivityLocusId); + + LocusId prevLocus = task1.mTopActivityLocusId; + task1.mTopActivityLocusId = new LocusId("20"); + task1.isVisible = false; + mOrganizer.onTaskInfoChanged(task1); + + // New locus for previously reported task in invisible list (since the task wasn't visible). + assertTrue(listener.invisibleLocusTasks.contains(task1.taskId)); + assertEquals(listener.invisibleLocusTasks.get(task1.taskId), prevLocus); + } + + @Test + public void testLocusListener_noLocusNotNotified() { + TrackingLocusIdListener listener = new TrackingLocusIdListener(); + mOrganizer.addLocusIdListener(listener); + + RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_MULTI_WINDOW); + task1.isVisible = true; + mOrganizer.onTaskAppeared(task1, null); + assertEquals(listener.visibleLocusTasks.size(), 0); + assertEquals(listener.invisibleLocusTasks.size(), 0); + + mOrganizer.onTaskInfoChanged(task1); + assertEquals(listener.visibleLocusTasks.size(), 0); + assertEquals(listener.invisibleLocusTasks.size(), 0); + + task1.isVisible = false; + mOrganizer.onTaskVanished(task1); + assertEquals(listener.visibleLocusTasks.size(), 0); + assertEquals(listener.invisibleLocusTasks.size(), 0); + } + private static RunningTaskInfo createTaskInfo(int taskId, int windowingMode) { RunningTaskInfo taskInfo = new RunningTaskInfo(); taskInfo.taskId = taskId; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java index d3a736e9153e..9a80a5545984 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java @@ -106,7 +106,7 @@ public class BubbleDataTest extends ShellTestCase { private ArgumentCaptor<BubbleData.Update> mUpdateCaptor; @Mock - private Bubbles.NotificationSuppressionChangedListener mSuppressionListener; + private Bubbles.SuppressionChangedListener mSuppressionListener; @Mock private Bubbles.PendingIntentCanceledListener mPendingIntentCanceledListener; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java index fc828b30279f..819a984b4a77 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java @@ -63,7 +63,7 @@ public class BubbleTest extends ShellTestCase { private Bubble mBubble; @Mock - private Bubbles.NotificationSuppressionChangedListener mSuppressionListener; + private Bubbles.SuppressionChangedListener mSuppressionListener; @Before public void setUp() { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt index bdf75fcd8816..2f064ac95204 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt @@ -32,10 +32,12 @@ import org.junit.runner.RunWith class BubblePersistentRepositoryTest : ShellTestCase() { private val bubbles = listOf( - BubbleEntity(0, "com.example.messenger", "shortcut-1", "key-1", 120, 0, null, 1), - BubbleEntity(10, "com.example.chat", "alice and bob", "key-2", 0, 16537428, "title", 2), + // user, package, shortcut, notification key, height, res-height, title, taskId, locusId + BubbleEntity(0, "com.example.messenger", "shortcut-1", "key-1", 120, 0, null, 1, null), + BubbleEntity(10, "com.example.chat", "alice and bob", "key-2", 0, 16537428, "title", + 2, null), BubbleEntity(0, "com.example.messenger", "shortcut-2", "key-3", 120, 0, null, - INVALID_TASK_ID) + INVALID_TASK_ID, "key-3") ) private lateinit var repository: BubblePersistentRepository diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt index 05795fde7d6c..03aa6c2eba12 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt @@ -38,12 +38,13 @@ class BubbleVolatileRepositoryTest : ShellTestCase() { private val user0 = UserHandle.of(0) private val user10 = UserHandle.of(10) + // user, package, shortcut, notification key, height, res-height, title, taskId, locusId private val bubble1 = BubbleEntity(0, "com.example.messenger", "shortcut-1", "key-1", 120, 0, - null, 1) + null, 1, null) private val bubble2 = BubbleEntity(10, "com.example.chat", "alice and bob", - "key-2", 0, 16537428, "title", 2) + "key-2", 0, 16537428, "title", 2, null) private val bubble3 = BubbleEntity(0, "com.example.messenger", "shortcut-2", "key-3", 120, 0, - null, INVALID_TASK_ID) + null, INVALID_TASK_ID, "key-3") private val bubbles = listOf(bubble1, bubble2, bubble3) @@ -108,13 +109,14 @@ class BubbleVolatileRepositoryTest : ShellTestCase() { @Test fun testAddBubbleMatchesByKey() { - val bubble = BubbleEntity(0, "com.example.pkg", "shortcut-id", "key", 120, 0, "title", 1) + val bubble = BubbleEntity(0, "com.example.pkg", "shortcut-id", "key", 120, 0, "title", + 1, null) repository.addBubbles(listOf(bubble)) assertEquals(bubble, repository.bubbles.get(0)) // Same key as first bubble but different entry val bubbleModified = BubbleEntity(0, "com.example.pkg", "shortcut-id", "key", 120, 0, - "different title", 2) + "different title", 2, null) repository.addBubbles(listOf(bubbleModified)) assertEquals(bubbleModified, repository.bubbles.get(0)) } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelperTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelperTest.kt index 839b873d0c23..8d719e7a7378 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelperTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelperTest.kt @@ -32,10 +32,12 @@ import java.io.ByteArrayOutputStream class BubbleXmlHelperTest : ShellTestCase() { private val bubbles = listOf( + // user, package, shortcut, notification key, height, res-height, title, taskId, locusId BubbleEntity(0, "com.example.messenger", "shortcut-1", "k1", 120, 0, null, 1), - BubbleEntity(10, "com.example.chat", "alice and bob", "k2", 0, 16537428, "title", 2), + BubbleEntity(10, "com.example.chat", "alice and bob", "k2", 0, 16537428, "title", + 2, null), BubbleEntity(0, "com.example.messenger", "shortcut-2", "k3", 120, 0, null, - INVALID_TASK_ID) + INVALID_TASK_ID, "l3") ) @Test @@ -43,7 +45,7 @@ class BubbleXmlHelperTest : ShellTestCase() { val expectedEntries = """ <bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" h="120" hid="0" tid="1" /> <bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" h="0" hid="16537428" t="title" tid="2" /> -<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" tid="-1" /> +<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" tid="-1" l="l3" /> """.trimIndent() ByteArrayOutputStream().use { writeXml(it, bubbles) @@ -60,7 +62,7 @@ class BubbleXmlHelperTest : ShellTestCase() { <bs v="1"> <bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" h="120" hid="0" tid="1" /> <bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" h="0" hid="16537428" t="title" tid="2" /> -<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" tid="-1" /> +<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" tid="-1" l="l3" /> </bs> """.trimIndent() val actual = readXml(ByteArrayInputStream(src.toByteArray(Charsets.UTF_8))) @@ -97,7 +99,32 @@ class BubbleXmlHelperTest : ShellTestCase() { BubbleEntity(0, "com.example.messenger", "shortcut-2", "k3", 120, 0, null, INVALID_TASK_ID) ) + val src = """ +<?xml version='1.0' encoding='utf-8' standalone='yes' ?> +<bs v="1"> +<bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" h="120" hid="0" /> +<bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" h="0" hid="16537428" t="title" /> +<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" /> +</bs> + """.trimIndent() + val actual = readXml(ByteArrayInputStream(src.toByteArray(Charsets.UTF_8))) + assertEquals("failed parsing bubbles from xml\n$src", expectedBubbles, actual) + } + /** + * LocusId is optional so it can be added without a version change, this test makes sure that + * works. + */ + @Test + fun testXMLWithoutLocusToLocus() { + val expectedBubbles = listOf( + BubbleEntity(0, "com.example.messenger", "shortcut-1", "k1", 120, 0, null, + INVALID_TASK_ID, null), + BubbleEntity(10, "com.example.chat", "alice and bob", "k2", 0, 16537428, "title", + INVALID_TASK_ID, null), + BubbleEntity(0, "com.example.messenger", "shortcut-2", "k3", 120, 0, null, + INVALID_TASK_ID, null) + ) val src = """ <?xml version='1.0' encoding='utf-8' standalone='yes' ?> <bs v="1"> 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 19ecc49513e5..c1c4c6dd08d7 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 @@ public class DragAndDropPolicyTest { 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 @@ public class DragAndDropPolicyTest { 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 @@ public class DragAndDropPolicyTest { 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 @@ public class DragAndDropPolicyTest { 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 @@ public class DragAndDropPolicyTest { 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 @@ public class DragAndDropPolicyTest { 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 @@ public class DragAndDropPolicyTest { 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 b0f52cf656f8..d6bcf0375f32 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 @@ public class OneHandedBackgroundPanelOrganizerTest extends OneHandedTestCase { 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 1ad8fd3e7298..c5221dee9216 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 @@ public class OneHandedControllerTest extends OneHandedTestCase { mSpiedOneHandedController = spy(new OneHandedController( mContext, + mWindowManager, mMockDisplayController, mMockBackgroundOrganizer, mMockDisplayAreaOrganizer, @@ -120,8 +121,8 @@ public class OneHandedControllerTest extends OneHandedTestCase { 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 7a826c1be4d3..1fa1e2ff69b6 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 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase { 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 b275b701f87a..f683e4af41bd 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 @@ -16,14 +16,22 @@ package com.android.wm.shell.onehanded; +import static android.view.Display.DEFAULT_DISPLAY; + import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.when; + import android.testing.AndroidTestingRunner; +import android.view.Surface; import android.view.ViewConfiguration; +import android.window.WindowContainerTransaction; import androidx.test.filters.SmallTest; import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.ShellExecutor; import org.junit.Before; @@ -39,13 +47,21 @@ public class OneHandedGestureHandlerTest extends OneHandedTestCase { @Mock DisplayController mMockDisplayController; @Mock + DisplayLayout mMockDisplayLayout; + @Mock ShellExecutor mMockShellMainExecutor; + @Mock + WindowContainerTransaction mMockWct; @Before public void setUp() { + final int mockNavBarHeight = 100; MockitoAnnotations.initMocks(this); - mGestureHandler = new OneHandedGestureHandler(mContext, mMockDisplayController, - ViewConfiguration.get(mTestContext), mMockShellMainExecutor); + mGestureHandler = new OneHandedGestureHandler(mContext, mWindowManager, + mMockDisplayController, ViewConfiguration.get(mTestContext), + mMockShellMainExecutor); + when(mMockDisplayLayout.navBarFrameHeight()).thenReturn(mockNavBarHeight); + when(mMockDisplayController.getDisplayLayout(anyInt())).thenReturn(mMockDisplayLayout); } @Test @@ -79,4 +95,14 @@ public class OneHandedGestureHandlerTest extends OneHandedTestCase { assertThat(mGestureHandler.mInputMonitor).isNull(); assertThat(mGestureHandler.mInputEventReceiver).isNull(); } + + @Test + public void testOnlyHandleGestureInPortraitMode() { + mGestureHandler.onOneHandedEnabled(true); + mGestureHandler.onRotateDisplay(DEFAULT_DISPLAY, Surface.ROTATION_0, Surface.ROTATION_90, + mMockWct); + + assertThat(mGestureHandler.mInputMonitor).isNull(); + assertThat(mGestureHandler.mInputEventReceiver).isNull(); + } } 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 32a188d02cf0..8b03dc58c3bf 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.content.Context; 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 abstract class OneHandedTestCase { 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 @@ public abstract class OneHandedTestCase { 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 024cf7ffc1f3..69c537c2efbe 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 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase { @Mock OneHandedUiEventLogger mMockUiEventLogger; - @Before public void setUp() { MockitoAnnotations.initMocks(this); @@ -73,7 +72,8 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase { 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 79ec624a1557..d687e8d76d91 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; @@ -43,6 +45,7 @@ import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.TestShellExecutor; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayLayout; +import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController; import com.android.wm.shell.pip.phone.PhonePipMenuController; @@ -63,8 +66,8 @@ import java.util.Optional; public class PipTaskOrganizerTest extends ShellTestCase { private PipTaskOrganizer mSpiedPipTaskOrganizer; - @Mock private DisplayController mMockdDisplayController; - + @Mock private DisplayController mMockDisplayController; + @Mock private SyncTransactionQueue mMockSyncTransactionQueue; @Mock private PhonePipMenuController mMockPhonePipMenuController; @Mock private PipAnimationController mMockPipAnimationController; @Mock private PipTransitionController mMockPipTransitionController; @@ -87,10 +90,11 @@ public class PipTaskOrganizerTest extends ShellTestCase { mPipBoundsState = new PipBoundsState(mContext); mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState); mMainExecutor = new TestShellExecutor(); - mSpiedPipTaskOrganizer = spy(new PipTaskOrganizer(mContext, mPipBoundsState, + mSpiedPipTaskOrganizer = spy(new PipTaskOrganizer(mContext, + mMockSyncTransactionQueue, mPipBoundsState, mPipBoundsAlgorithm, mMockPhonePipMenuController, mMockPipAnimationController, mMockPipSurfaceTransactionHelper, - mMockPipTransitionController, mMockOptionalSplitScreen, mMockdDisplayController, + mMockPipTransitionController, mMockOptionalSplitScreen, mMockDisplayController, mMockPipUiEventLogger, mMockShellTaskOrganizer, mMainExecutor)); mMainExecutor.flushAll(); preparePipTaskOrg(); @@ -103,7 +107,7 @@ public class PipTaskOrganizerTest extends ShellTestCase { @Test public void instantiatePipTaskOrganizer_addsDisplayWindowListener() { - verify(mMockdDisplayController).addDisplayWindowListener(any()); + verify(mMockDisplayController).addDisplayWindowListener(any()); } @Test @@ -162,11 +166,29 @@ public class PipTaskOrganizerTest extends ShellTestCase { } @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 +197,10 @@ public class PipTaskOrganizerTest extends ShellTestCase { } @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 +209,10 @@ public class PipTaskOrganizerTest extends ShellTestCase { } @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/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java index b9af9ce8895d..a531ef58725d 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java @@ -37,10 +37,10 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.testing.TestableContext; +import android.view.Choreographer; import android.view.View; import android.view.WindowManager; import android.view.WindowMetrics; -import android.window.SplashScreenView; import android.window.StartingWindowInfo; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -67,6 +67,8 @@ public class StartingSurfaceDrawerTests { private IBinder mBinder; @Mock private WindowManager mMockWindowManager; + @Mock + private static Choreographer sFakeChoreographer; TestStartingSurfaceDrawer mStartingSurfaceDrawer; @@ -79,12 +81,17 @@ public class StartingSurfaceDrawerTests { } @Override - protected void postAddWindow(int taskId, IBinder appToken, - View view, WindowManager wm, WindowManager.LayoutParams params, - SplashScreenView splashScreenView) { + protected void initChoreographer() { + mChoreographer = sFakeChoreographer; + } + + @Override + protected boolean postAddWindow(int taskId, IBinder appToken, + View view, WindowManager wm, WindowManager.LayoutParams params) { // listen for addView mAddWindowForTask = taskId; mViewThemeResId = view.getContext().getThemeResId(); + return true; } @Override @@ -127,8 +134,7 @@ public class StartingSurfaceDrawerTests { createWindowInfo(taskId, android.R.style.Theme); mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, mBinder); waitHandlerIdle(mainLoop); - verify(mStartingSurfaceDrawer).postAddWindow( - eq(taskId), eq(mBinder), any(), any(), any(), any()); + verify(mStartingSurfaceDrawer).postAddWindow(eq(taskId), eq(mBinder), any(), any(), any()); assertEquals(mStartingSurfaceDrawer.mAddWindowForTask, taskId); mStartingSurfaceDrawer.removeStartingWindow(windowInfo.taskInfo.taskId); @@ -145,8 +151,7 @@ public class StartingSurfaceDrawerTests { createWindowInfo(taskId, 0); mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, mBinder); waitHandlerIdle(mainLoop); - verify(mStartingSurfaceDrawer).postAddWindow( - eq(taskId), eq(mBinder), any(), any(), any(), any()); + verify(mStartingSurfaceDrawer).postAddWindow(eq(taskId), eq(mBinder), any(), any(), any()); assertNotEquals(mStartingSurfaceDrawer.mViewThemeResId, 0); } diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 77ceda91898e..d663c52b2c08 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -421,7 +421,6 @@ cc_defaults { "libstatspull", "libstatssocket", "libpdfium", - "libbinder_ndk", ], static_libs: [ "libgif", diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h index 912d04c5d87d..e9b2f4a9bb3b 100644 --- a/libs/hwui/FrameInfo.h +++ b/libs/hwui/FrameInfo.h @@ -80,6 +80,10 @@ public: 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/FrameMetricsObserver.h b/libs/hwui/FrameMetricsObserver.h index b93f07853242..ef1f5aabcbd8 100644 --- a/libs/hwui/FrameMetricsObserver.h +++ b/libs/hwui/FrameMetricsObserver.h @@ -24,6 +24,24 @@ namespace uirenderer { class FrameMetricsObserver : public VirtualLightRefBase { public: virtual void notify(const int64_t* buffer) = 0; + bool waitForPresentTime() const { return mWaitForPresentTime; }; + + /** + * Create a new metrics observer. An observer that watches present time gets notified at a + * different time than the observer that doesn't. + * + * The observer that doesn't want present time is notified about metrics just after the frame + * is completed. This is the default behaviour that's used by public API's. + * + * An observer that watches present time is notified about metrics after the actual display + * present time is known. + * WARNING! This observer may not receive metrics for the last several frames that the app + * produces. + */ + FrameMetricsObserver(bool waitForPresentTime) : mWaitForPresentTime(waitForPresentTime) {} + +private: + const bool mWaitForPresentTime; }; } // namespace uirenderer diff --git a/libs/hwui/FrameMetricsReporter.h b/libs/hwui/FrameMetricsReporter.h index 0643e790d00b..3f2dc1244085 100644 --- a/libs/hwui/FrameMetricsReporter.h +++ b/libs/hwui/FrameMetricsReporter.h @@ -55,13 +55,24 @@ public: return mObservers.size() > 0; } - void reportFrameMetrics(const int64_t* stats) { + /** + * Notify observers about the metrics contained in 'stats'. + * If an observer is waiting for present time, notify when 'stats' has present time. + * + * If an observer does not want present time, only notify when 'hasPresentTime' is false. + * Never notify both types of observers from the same callback, because the callback with + * 'hasPresentTime' is sent at a different time than the one without. + */ + void reportFrameMetrics(const int64_t* stats, bool hasPresentTime) { FatVector<sp<FrameMetricsObserver>, 10> copy; { std::lock_guard lock(mObserversLock); copy.reserve(mObservers.size()); for (size_t i = 0; i < mObservers.size(); i++) { - copy.push_back(mObservers[i]); + const bool wantsPresentTime = mObservers[i]->waitForPresentTime(); + if (hasPresentTime == wantsPresentTime) { + copy.push_back(mObservers[i]); + } } } for (size_t i = 0; i < copy.size(); i++) { diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h index 609706e2e49d..5540e2da78d9 100644 --- a/libs/hwui/RenderProperties.h +++ b/libs/hwui/RenderProperties.h @@ -552,8 +552,8 @@ public: 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 51cbc7592861..d4fd1053b17f 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 7dfd6398765a..d2da06b31f68 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 @@ public: 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 @@ public: *this = other; return; } - stretchDirection += other.stretchDirection; + setStretchDirection(mStretchDirection + other.mStretchDirection); if (isEmpty()) { return setEmpty(); } @@ -56,11 +70,23 @@ public: 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_HardwareRendererObserver.cpp b/libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp index 5b3e65648981..e5d5e75d0f3b 100644 --- a/libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp +++ b/libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp @@ -35,7 +35,9 @@ static JNIEnv* getenv(JavaVM* vm) { return env; } -HardwareRendererObserver::HardwareRendererObserver(JavaVM *vm, jobject observer) : mVm(vm) { +HardwareRendererObserver::HardwareRendererObserver(JavaVM* vm, jobject observer, + bool waitForPresentTime) + : uirenderer::FrameMetricsObserver(waitForPresentTime), mVm(vm) { mObserverWeak = getenv(mVm)->NewWeakGlobalRef(observer); LOG_ALWAYS_FATAL_IF(mObserverWeak == nullptr, "unable to create frame stats observer reference"); @@ -86,14 +88,16 @@ void HardwareRendererObserver::notify(const int64_t* stats) { } static jlong android_graphics_HardwareRendererObserver_createObserver(JNIEnv* env, - jobject observerObj) { + jobject observerObj, + jboolean waitForPresentTime) { JavaVM* vm = nullptr; if (env->GetJavaVM(&vm) != JNI_OK) { LOG_ALWAYS_FATAL("Unable to get Java VM"); return 0; } - HardwareRendererObserver* observer = new HardwareRendererObserver(vm, observerObj); + HardwareRendererObserver* observer = + new HardwareRendererObserver(vm, observerObj, waitForPresentTime); return reinterpret_cast<jlong>(observer); } @@ -110,10 +114,10 @@ static jint android_graphics_HardwareRendererObserver_getNextBuffer(JNIEnv* env, } static const std::array gMethods = { - MAKE_JNI_NATIVE_METHOD("nCreateObserver", "()J", - android_graphics_HardwareRendererObserver_createObserver), - MAKE_JNI_NATIVE_METHOD("nGetNextBuffer", "(J[J)I", - android_graphics_HardwareRendererObserver_getNextBuffer), + MAKE_JNI_NATIVE_METHOD("nCreateObserver", "(Z)J", + android_graphics_HardwareRendererObserver_createObserver), + MAKE_JNI_NATIVE_METHOD("nGetNextBuffer", "(J[J)I", + android_graphics_HardwareRendererObserver_getNextBuffer), }; int register_android_graphics_HardwareRendererObserver(JNIEnv* env) { diff --git a/libs/hwui/jni/android_graphics_HardwareRendererObserver.h b/libs/hwui/jni/android_graphics_HardwareRendererObserver.h index 62111fd7d7a1..d3076140541b 100644 --- a/libs/hwui/jni/android_graphics_HardwareRendererObserver.h +++ b/libs/hwui/jni/android_graphics_HardwareRendererObserver.h @@ -26,7 +26,7 @@ namespace android { */ class HardwareRendererObserver : public uirenderer::FrameMetricsObserver { public: - HardwareRendererObserver(JavaVM *vm, jobject observer); + HardwareRendererObserver(JavaVM* vm, jobject observer, bool waitForPresentTime); ~HardwareRendererObserver(); /** diff --git a/libs/hwui/jni/android_graphics_RenderNode.cpp b/libs/hwui/jni/android_graphics_RenderNode.cpp index 5f60437b5cc7..fc7d0d181949 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_clearStretch(CRITICAL_JNI_PARAMS_COMMA j } 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 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject, 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 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject, 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 }, - -// ---------------------------------------------------------------------------- -// 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 }, - - { "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 }, - - { "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 }, + // ---------------------------------------------------------------------------- + // 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}, + + {"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}, + + {"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}, + + {"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 c01021221f37..cb0ff8d871d4 100644 --- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp +++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp @@ -169,8 +169,8 @@ void RenderNodeDrawable::forceDraw(SkCanvas* canvas) const { 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 @@ static bool layerNeedsPaint(const LayerProperties& properties, float alphaMultip 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 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const { 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 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const { 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/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index f69ddacf7ca1..9793300b406d 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -599,10 +599,41 @@ void CanvasContext::finishFrame(FrameInfo* frameInfo) { // TODO (b/169858044): Move this into JankTracker to adjust deadline when queue is // double-stuffed. if (CC_UNLIKELY(mFrameMetricsReporter.get() != nullptr)) { - mFrameMetricsReporter->reportFrameMetrics(frameInfo->data()); + mFrameMetricsReporter->reportFrameMetrics(frameInfo->data(), false /*hasPresentTime*/); } } +void CanvasContext::reportMetricsWithPresentTime() { + if (mFrameMetricsReporter == nullptr) { + return; + } + if (mNativeSurface == nullptr) { + return; + } + FrameInfo* forthBehind; + int64_t frameNumber; + { // acquire lock + std::scoped_lock lock(mLast4FrameInfosMutex); + if (mLast4FrameInfos.size() != mLast4FrameInfos.capacity()) { + // Not enough frames yet + return; + } + // Surface object keeps stats for the last 8 frames. + std::tie(forthBehind, frameNumber) = mLast4FrameInfos.front(); + } // release lock + + nsecs_t presentTime = 0; + native_window_get_frame_timestamps( + mNativeSurface->getNativeWindow(), frameNumber, nullptr /*outRequestedPresentTime*/, + nullptr /*outAcquireTime*/, nullptr /*outLatchTime*/, + nullptr /*outFirstRefreshStartTime*/, nullptr /*outLastRefreshStartTime*/, + nullptr /*outGpuCompositionDoneTime*/, &presentTime, nullptr /*outDequeueReadyTime*/, + nullptr /*outReleaseTime*/); + + forthBehind->set(FrameInfoIndex::DisplayPresentTime) = presentTime; + mFrameMetricsReporter->reportFrameMetrics(forthBehind->data(), true /*hasPresentTime*/); +} + void CanvasContext::onSurfaceStatsAvailable(void* context, ASurfaceControl* control, ASurfaceControlStats* stats) { @@ -624,6 +655,9 @@ void CanvasContext::onSurfaceStatsAvailable(void* context, ASurfaceControl* cont } } } + + instance->reportMetricsWithPresentTime(); + if (frameInfo != nullptr) { if (gpuCompleteTime == -1) { gpuCompleteTime = frameInfo->get(FrameInfoIndex::SwapBuffersCompleted); diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 2e7b2f618a8a..74f426ead912 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -219,6 +219,12 @@ private: SkRect computeDirtyRect(const Frame& frame, SkRect* dirty); void finishFrame(FrameInfo* frameInfo); + /** + * Invoke 'reportFrameMetrics' on the last frame stored in 'mLast4FrameInfos'. + * Populate the 'presentTime' field before calling. + */ + void reportMetricsWithPresentTime(); + // The same type as Frame.mWidth and Frame.mHeight int32_t mLastFrameWidth = 0; int32_t mLastFrameHeight = 0; diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp index c9146b2fc2d1..3408ffda3f9d 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::postAndWait() { } 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/location/java/android/location/CorrelationVector.java b/location/java/android/location/CorrelationVector.java index eca35dd69362..4b6e6882b50a 100644 --- a/location/java/android/location/CorrelationVector.java +++ b/location/java/android/location/CorrelationVector.java @@ -17,7 +17,6 @@ package android.location; import android.annotation.FloatRange; -import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.SystemApi; import android.os.Parcel; @@ -39,7 +38,7 @@ public final class CorrelationVector implements Parcelable { private final double mSamplingWidthMeters; private final double mSamplingStartMeters; - private final int mFrequencyOffsetMetersPerSecond; + private final double mFrequencyOffsetMetersPerSecond; @NonNull private final int[] mMagnitude; /** @@ -66,8 +65,8 @@ public final class CorrelationVector implements Parcelable { /** * Returns the frequency offset from reported pseudorange rate for this CorrelationVector. */ - @IntRange(from = 0) - public int getFrequencyOffsetMetersPerSecond() { + @FloatRange(from = 0.0f) + public double getFrequencyOffsetMetersPerSecond() { return mFrequencyOffsetMetersPerSecond; } @@ -88,7 +87,7 @@ public final class CorrelationVector implements Parcelable { Preconditions.checkNotNull(builder.mMagnitude, "Magnitude array must not be null"); Preconditions.checkArgumentPositive(builder.mMagnitude.length, "Magnitude array must have non-zero length"); - Preconditions.checkArgumentNonNegative(builder.mFrequencyOffsetMetersPerSecond, + Preconditions.checkArgument(builder.mFrequencyOffsetMetersPerSecond >= 0.0, "FrequencyOffsetMetersPerSecond must be non-negative (greater than or equal to 0)"); Preconditions.checkArgument(builder.mSamplingWidthMeters > 0.0, "SamplingWidthMeters must be positive (greater than 0)"); @@ -103,7 +102,7 @@ public final class CorrelationVector implements Parcelable { private CorrelationVector(Parcel in) { mSamplingWidthMeters = in.readDouble(); mSamplingStartMeters = in.readDouble(); - mFrequencyOffsetMetersPerSecond = in.readInt(); + mFrequencyOffsetMetersPerSecond = in.readDouble(); mMagnitude = new int[in.readInt()]; in.readIntArray(mMagnitude); } @@ -144,7 +143,7 @@ public final class CorrelationVector implements Parcelable { public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeDouble(mSamplingWidthMeters); dest.writeDouble(mSamplingStartMeters); - dest.writeInt(mFrequencyOffsetMetersPerSecond); + dest.writeDouble(mFrequencyOffsetMetersPerSecond); dest.writeInt(mMagnitude.length); dest.writeIntArray(mMagnitude); } @@ -165,7 +164,7 @@ public final class CorrelationVector implements Parcelable { return Arrays.equals(mMagnitude, c.getMagnitude()) && Double.compare(mSamplingWidthMeters, c.getSamplingWidthMeters()) == 0 && Double.compare(mSamplingStartMeters, c.getSamplingStartMeters()) == 0 - && Integer.compare(mFrequencyOffsetMetersPerSecond, + && Double.compare(mFrequencyOffsetMetersPerSecond, c.getFrequencyOffsetMetersPerSecond()) == 0; } @@ -182,7 +181,7 @@ public final class CorrelationVector implements Parcelable { private double mSamplingWidthMeters; private double mSamplingStartMeters; - private int mFrequencyOffsetMetersPerSecond; + private double mFrequencyOffsetMetersPerSecond; @NonNull private int[] mMagnitude; /** Sets the space between correlation samples in meters. */ @@ -203,7 +202,7 @@ public final class CorrelationVector implements Parcelable { /** Sets the frequency offset from reported pseudorange rate for this CorrelationVector */ @NonNull public Builder setFrequencyOffsetMetersPerSecond( - @IntRange(from = 0) int frequencyOffsetMetersPerSecond) { + @FloatRange(from = 0.0f) double frequencyOffsetMetersPerSecond) { mFrequencyOffsetMetersPerSecond = frequencyOffsetMetersPerSecond; return this; } diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index b2de49deefca..1cef0922a48e 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -7062,20 +7062,12 @@ public class AudioManager { * Selects the audio device that should be used for communication use cases, for instance voice * or video calls. This method can be used by voice or video chat applications to select a * different audio device than the one selected by default by the platform. - * <p>The device selection is expressed as an {@link AudioDeviceInfo}, of role sink - * ({@link AudioDeviceInfo#isSink()} is <code>true</code>) and of one of the following types: - * <ul> - * <li> {@link AudioDeviceInfo#TYPE_BUILTIN_EARPIECE} - * <li> {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER} - * <li> {@link AudioDeviceInfo#TYPE_WIRED_HEADSET} - * <li> {@link AudioDeviceInfo#TYPE_BLUETOOTH_SCO} - * <li> {@link AudioDeviceInfo#TYPE_USB_HEADSET} - * <li> {@link AudioDeviceInfo#TYPE_BLE_HEADSET} - * </ul> - * The selection is active as long as the requesting application lives, until - * {@link #clearDeviceForCommunication} is called or until the device is disconnected. + * <p>The device selection is expressed as an {@link AudioDeviceInfo} among devices returned by + * {@link #getAvailableCommunicationDevices()}. + * The selection is active as long as the requesting application process lives, until + * {@link #clearCommunicationDevice} is called or until the device is disconnected. * It is therefore important for applications to clear the request when a call ends or the - * application is paused. + * the requesting activity or service is stopped or destroyed. * <p>In case of simultaneous requests by multiple applications the priority is given to the * application currently controlling the audio mode (see {@link #setMode(int)}). This is the * latest application having selected mode {@link #MODE_IN_COMMUNICATION} or mode @@ -7097,7 +7089,7 @@ public class AudioManager { * AudioManager audioManager = Context.getSystemService(AudioManager.class); * try { * AudioDeviceInfo speakerDevice = null; - * AudioDeviceInfo[] devices = audioManager.getDevices(GET_DEVICES_OUTPUTS); + * List<AudioDeviceInfo> devices = audioManager.getAvailableCommunicationDevices(); * for (AudioDeviceInfo device : devices) { * if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) { * speakerDevice = device; @@ -7106,12 +7098,12 @@ public class AudioManager { * } * if (speakerDevice != null) { * // Turn speakerphone ON. - * boolean result = audioManager.setDeviceForCommunication(speakerDevice); + * boolean result = audioManager.setCommunicationDevice(speakerDevice); * if (!result) { * // Handle error. * } * // Turn speakerphone OFF. - * audioManager.clearDeviceForCommunication(); + * audioManager.clearCommunicationDevice(); * } * } catch (IllegalArgumentException e) { * // Handle exception. @@ -7121,13 +7113,13 @@ public class AudioManager { * @return <code>true</code> if the request was accepted, <code>false</code> otherwise. * @throws IllegalArgumentException If an invalid device is specified. */ - public boolean setDeviceForCommunication(@NonNull AudioDeviceInfo device) { + public boolean setCommunicationDevice(@NonNull AudioDeviceInfo device) { Objects.requireNonNull(device); try { if (device.getId() == 0) { throw new IllegalArgumentException("In valid device: " + device); } - return getService().setDeviceForCommunication(mICallBack, device.getId()); + return getService().setCommunicationDevice(mICallBack, device.getId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -7135,11 +7127,11 @@ public class AudioManager { /** * Cancels previous communication device selection made with - * {@link #setDeviceForCommunication(AudioDeviceInfo)}. + * {@link #setCommunicationDevice(AudioDeviceInfo)}. */ - public void clearDeviceForCommunication() { + public void clearCommunicationDevice() { try { - getService().setDeviceForCommunication(mICallBack, 0); + getService().setCommunicationDevice(mICallBack, 0); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -7153,14 +7145,38 @@ public class AudioManager { * <li> {@link #isSpeakerphoneOn()} * </ul> * @return an {@link AudioDeviceInfo} indicating which audio device is - * currently selected or communication use cases or null if default selection + * currently selected for communication use cases. Can be null on platforms + * not supporting {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}. * is used. */ @Nullable - public AudioDeviceInfo getDeviceForCommunication() { + public AudioDeviceInfo getCommunicationDevice() { try { return getDeviceForPortId( - getService().getDeviceForCommunication(), GET_DEVICES_OUTPUTS); + getService().getCommunicationDevice(), GET_DEVICES_OUTPUTS); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns a list of audio devices that can be selected for communication use cases via + * {@link #setCommunicationDevice(AudioDeviceInfo)}. + * @return a list of {@link AudioDeviceInfo} suitable for use with setCommunicationDevice(). + */ + @NonNull + public List<AudioDeviceInfo> getAvailableCommunicationDevices() { + try { + ArrayList<AudioDeviceInfo> devices = new ArrayList<>(); + int[] portIds = getService().getAvailableCommunicationDeviceIds(); + for (int portId : portIds) { + AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS); + if (device == null) { + continue; + } + devices.add(device); + } + return devices; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -7175,7 +7191,7 @@ public class AudioManager { * If more than one device of the provided type is connected, an object corresponding to the * first device encountered in the enumeration list will be returned. * @param deviceType The device device for which an <code>AudioDeviceInfo</code> - * object is queried. + * object is queried. * @return An AudioDeviceInfo object or null if no device with the requested type is connected. * @throws IllegalArgumentException If an invalid device type is specified. */ @@ -7183,30 +7199,59 @@ public class AudioManager { @Nullable public static AudioDeviceInfo getDeviceInfoFromType( @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) { + return getDeviceInfoFromTypeAndAddress(deviceType, null); + } + + /** + * @hide + * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type and + * address provided. + * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class, + * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}. + * If a null address is provided, the matching will happen on the type only. + * The method will return null if no device of the provided type and address is connected. + * If more than one device of the provided type is connected, an object corresponding to the + * first device encountered in the enumeration list will be returned. + * @param type The device device for which an <code>AudioDeviceInfo</code> + * object is queried. + * @param address The device address for which an <code>AudioDeviceInfo</code> + * object is queried or null if requesting match on type only. + * @return An AudioDeviceInfo object or null if no matching device is connected. + * @throws IllegalArgumentException If an invalid device type is specified. + */ + @Nullable + public static AudioDeviceInfo getDeviceInfoFromTypeAndAddress( + @AudioDeviceInfo.AudioDeviceTypeOut int type, @Nullable String address) { AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_OUTPUTS); + AudioDeviceInfo deviceForType = null; for (AudioDeviceInfo device : devices) { - if (device.getType() == deviceType) { - return device; + if (device.getType() == type) { + deviceForType = device; + if (address == null || address.equals(device.getAddress())) { + return device; + } } } - return null; + return deviceForType; } /** * Listener registered by client to be notified upon communication audio device change. - * See {@link #setDeviceForCommunication(AudioDeviceInfo)}. + * See {@link #setCommunicationDevice(AudioDeviceInfo)}. */ public interface OnCommunicationDeviceChangedListener { /** * Callback method called upon communication audio device change. - * @param device the audio device selected for communication use cases + * @param device the audio device requested for communication use cases. + * Can be null on platforms not supporting + * {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}. */ void onCommunicationDeviceChanged(@Nullable AudioDeviceInfo device); } /** * Adds a listener for being notified of changes to the communication audio device. - * See {@link #setDeviceForCommunication(AudioDeviceInfo)}. + * See {@link #setCommunicationDevice(AudioDeviceInfo)}. * @param executor * @param listener */ @@ -7243,7 +7288,7 @@ public class AudioManager { /** * Removes a previously added listener of changes to the communication audio device. - * See {@link #setDeviceForCommunication(AudioDeviceInfo)}. + * See {@link #setCommunicationDevice(AudioDeviceInfo)}. * @param listener */ public void removeOnCommunicationDeviceChangedListener( diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 0073b5cc93b9..4f87fe6c5f8c 100755 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -342,9 +342,11 @@ interface IAudioService { int getDevicesForStream(in int streamType); - boolean setDeviceForCommunication(IBinder cb, int portId); + int[] getAvailableCommunicationDeviceIds(); - int getDeviceForCommunication(); + boolean setCommunicationDevice(IBinder cb, int portId); + + int getCommunicationDevice(); void registerCommunicationDeviceDispatcher(ICommunicationDeviceDispatcher dispatcher); diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java index f5b204a4a908..5656dffe1d4a 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.ImageFormat.Format; 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.ByteBuffer; 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 @@ public class ImageReader implements AutoCloseable { // 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 @@ public class ImageReader implements AutoCloseable { // 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 @@ public class ImageReader implements AutoCloseable { if (image != null) { image.close(); } + if (mParent != null) { + mParent.flushOther(this); + } } } @@ -584,12 +611,38 @@ public class ImageReader implements AutoCloseable { } 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 @@ public class ImageReader implements AutoCloseable { 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 @@ public class ImageReader implements AutoCloseable { 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 class ImageReader implements AutoCloseable { public ListenerHandler(Looper looper) { super(looper, null, true /*async*/); } + } - @Override - public void handleMessage(Message msg) { - OnImageAvailableListener listener; - synchronized (mListenerLock) { - listener = mListener; - } + /** + * 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); + } - // 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); - } + @Override + 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 f7467a636024..548b415fce74 100644 --- a/media/java/android/media/MediaDrm.java +++ b/media/java/android/media/MediaDrm.java @@ -558,12 +558,20 @@ public final class MediaDrm implements AutoCloseable { 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 @@ public final class MediaDrm implements AutoCloseable { * <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 @@ public final class MediaDrm implements AutoCloseable { * 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 @@ public final class MediaDrm implements AutoCloseable { * 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 @@ public final class MediaDrm implements AutoCloseable { * 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 @@ public final class MediaDrm implements AutoCloseable { * 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 @@ public final class MediaDrm implements AutoCloseable { 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/MediaRouter2.java b/media/java/android/media/MediaRouter2.java index ff52a1abc6f4..dc9c58ebf18c 100644 --- a/media/java/android/media/MediaRouter2.java +++ b/media/java/android/media/MediaRouter2.java @@ -23,6 +23,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; import android.content.Context; +import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Handler; import android.os.Looper; @@ -67,6 +68,10 @@ public final class MediaRouter2 { private static final long MANAGER_REQUEST_ID_NONE = MediaRoute2ProviderService.REQUEST_ID_NONE; @GuardedBy("sRouterLock") + private static Map<String, MediaRouter2> sMediaRouter2Map = new ArrayMap<>(); + private static MediaRouter2Manager sManager; + + @GuardedBy("sRouterLock") private static MediaRouter2 sInstance; private final Context mContext; @@ -82,7 +87,9 @@ public final class MediaRouter2 { private final CopyOnWriteArrayList<ControllerCreationRequest> mControllerCreationRequests = new CopyOnWriteArrayList<>(); + private final String mClientPackageName; private final String mPackageName; + @GuardedBy("sRouterLock") final Map<String, MediaRoute2Info> mRoutes = new ArrayMap<>(); @@ -120,6 +127,42 @@ public final class MediaRouter2 { } } + /** + * Gets an instance of the media router which controls the app's media routing. + * Returns {@code null} if the given package name is invalid. + * + * @param clientPackageName the package name of the app to control + * @hide + */ + //@SystemApi + @Nullable + public static MediaRouter2 getInstance(@NonNull Context context, + @NonNull String clientPackageName) { + Objects.requireNonNull(context, "context must not be null"); + Objects.requireNonNull(clientPackageName, "clientPackageName must not be null"); + + PackageManager pm = context.getPackageManager(); + try { + pm.getPackageInfo(clientPackageName, 0); + } catch (PackageManager.NameNotFoundException ex) { + Log.e(TAG, "Package " + clientPackageName + " not found. Ignoring."); + return null; + } + + synchronized (sRouterLock) { + MediaRouter2 instance = sMediaRouter2Map.get(clientPackageName); + if (instance == null) { + // TODO: Add permission check here using MODIFY_AUDIO_ROUTING. + if (sManager == null) { + sManager = MediaRouter2Manager.getInstance(context.getApplicationContext()); + } + instance = new MediaRouter2(context, clientPackageName); + sMediaRouter2Map.put(clientPackageName, instance); + } + return instance; + } + } + private MediaRouter2(Context appContext) { mContext = appContext; mMediaRouterService = IMediaRouterService.Stub.asInterface( @@ -148,6 +191,17 @@ public final class MediaRouter2 { mRoutes.put(route.getId(), route); } mSystemController = new SystemRoutingController(currentSystemSessionInfo); + + mClientPackageName = null; + } + + private MediaRouter2(Context context, String clientPackageName) { + mClientPackageName = clientPackageName; + mContext = context; + mMediaRouterService = null; + mPackageName = null; + mHandler = new Handler(Looper.getMainLooper()); + mSystemController = null; } /** @@ -166,6 +220,19 @@ public final class MediaRouter2 { } /** + * Gets the target package name of the app which this media router controls. + * This is only non-null when the router instance is created with the target package name. + * + * @see #getInstance(Context, String) + * @hide + */ + //@SystemApi + @Nullable + public String getClientPackageName() { + return mClientPackageName; + } + + /** * Registers a callback to discover routes and to receive events when they change. * <p> * If the specified callback is already registered, its registration will be updated for the @@ -270,6 +337,10 @@ public final class MediaRouter2 { */ @NonNull public List<MediaRoute2Info> getRoutes() { + if (mClientPackageName != null) { + return sManager.getAvailableRoutes(mClientPackageName); + } + synchronized (sRouterLock) { if (mShouldUpdateRoutes) { mShouldUpdateRoutes = false; @@ -378,6 +449,11 @@ public final class MediaRouter2 { * @see TransferCallback#onTransferFailure */ public void transferTo(@NonNull MediaRoute2Info route) { + if (mClientPackageName != null) { + sManager.selectRoute(mClientPackageName, route); + return; + } + Objects.requireNonNull(route, "route must not be null"); Log.v(TAG, "Transferring to route: " + route); transfer(getCurrentController(), route); @@ -388,6 +464,12 @@ public final class MediaRouter2 { * controls the media routing, this method is a no-op. */ public void stop() { + if (mClientPackageName != null) { + List<RoutingSessionInfo> sessionInfos = sManager.getRoutingSessions(mClientPackageName); + RoutingSessionInfo sessionToRelease = sessionInfos.get(sessionInfos.size() - 1); + sManager.releaseSession(sessionToRelease); + return; + } getCurrentController().release(); } @@ -397,7 +479,13 @@ public final class MediaRouter2 { * @param route the route you want to transfer the media to. * @hide */ - void transfer(@NonNull RoutingController controller, @NonNull MediaRoute2Info route) { + //@SystemApi + public void transfer(@NonNull RoutingController controller, @NonNull MediaRoute2Info route) { + if (mClientPackageName != null) { + sManager.transfer(controller.getRoutingSessionInfo(), route); + return; + } + Objects.requireNonNull(controller, "controller must not be null"); Objects.requireNonNull(route, "route must not be null"); @@ -486,6 +574,14 @@ public final class MediaRouter2 { */ @NonNull public List<RoutingController> getControllers() { + // TODO: Do not create the controller instances every time, + // Instead, update the list using the sessions' ID and session related callbacks. + if (mClientPackageName != null) { + return sManager.getRoutingSessions(mClientPackageName).stream() + .map(info -> new RoutingController(info)) + .collect(Collectors.toList()); + } + List<RoutingController> result = new ArrayList<>(); result.add(0, mSystemController); synchronized (sRouterLock) { diff --git a/media/java/android/media/RoutingSessionInfo.java b/media/java/android/media/RoutingSessionInfo.java index a5d25e0771fd..3bea73febc24 100644 --- a/media/java/android/media/RoutingSessionInfo.java +++ b/media/java/android/media/RoutingSessionInfo.java @@ -326,6 +326,7 @@ public final class RoutingSessionInfo implements Parcelable { .append("RoutingSessionInfo{ ") .append("sessionId=").append(getId()) .append(", name=").append(getName()) + .append(", clientPackageName=").append(getClientPackageName()) .append(", selectedRoutes={") .append(String.join(",", getSelectedRoutes())) .append("}") diff --git a/media/java/android/media/metrics/Event.java b/media/java/android/media/metrics/Event.java index 5646dcdb6c9c..96b61d2eaf4d 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 abstract class Event { 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 2cb2ab5c42b5..f2c0d44a00b1 100644 --- a/media/java/android/media/metrics/IMediaMetricsManager.aidl +++ b/media/java/android/media/metrics/IMediaMetricsManager.aidl @@ -28,7 +28,8 @@ import android.media.metrics.TrackChangeEvent; */ 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 000000000000..7ddb259f7f28 --- /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 de780f672b28..9710e88cf24b 100644 --- a/media/java/android/media/metrics/MediaMetricsManager.java +++ b/media/java/android/media/metrics/MediaMetricsManager.java @@ -94,7 +94,7 @@ public class MediaMetricsManager { @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 @@ public class MediaMetricsManager { } /** + * 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 029edeb93374..098885cc9bdd 100644 --- a/media/java/android/media/metrics/NetworkEvent.java +++ b/media/java/android/media/metrics/NetworkEvent.java @@ -20,6 +20,7 @@ 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; @@ -33,6 +34,9 @@ import java.util.Objects; 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 final class NetworkEvent extends Event implements Parcelable { 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 @@ public final class NetworkEvent extends Event implements Parcelable { /** @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 @@ public final class NetworkEvent extends Event implements Parcelable { 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 @@ public final class NetworkEvent extends Event implements Parcelable { 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 @@ public final class NetworkEvent extends Event implements Parcelable { * * @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 @@ public final class NetworkEvent extends Event implements Parcelable { @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 @@ public final class NetworkEvent extends Event implements Parcelable { /** @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 final class NetworkEvent extends Event implements Parcelable { 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 @@ public final class NetworkEvent extends Event implements Parcelable { 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 5a0820d16cb9..b23b4d2728b4 100644 --- a/media/java/android/media/metrics/PlaybackErrorEvent.java +++ b/media/java/android/media/metrics/PlaybackErrorEvent.java @@ -21,6 +21,7 @@ import android.annotation.IntRange; 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 @@ public final class PlaybackErrorEvent extends Event implements Parcelable { @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 final class PlaybackErrorEvent extends Event implements Parcelable { 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 @@ public final class PlaybackErrorEvent extends Event implements Parcelable { 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 @@ public final class PlaybackErrorEvent extends Event implements Parcelable { private int mErrorCode; private int mSubErrorCode; private long mTimeSinceCreatedMillis = -1; + private Bundle mExtras; /** * Creates a new Builder. @@ -226,6 +234,16 @@ public final class PlaybackErrorEvent extends Event implements Parcelable { 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 @@ public final class PlaybackErrorEvent extends Event implements Parcelable { 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 4aa61662ba52..7e7f44a97b9c 100644 --- a/media/java/android/media/metrics/PlaybackMetrics.java +++ b/media/java/android/media/metrics/PlaybackMetrics.java @@ -20,6 +20,7 @@ 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; @@ -58,6 +59,10 @@ public final class PlaybackMetrics implements Parcelable { /** 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 @@ public final class PlaybackMetrics implements Parcelable { /** 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 @@ public final class PlaybackMetrics implements Parcelable { /** @hide */ @IntDef(prefix = "PLAYBACK_TYPE_", value = { + PLAYBACK_TYPE_UNKNOWN, PLAYBACK_TYPE_VOD, PLAYBACK_TYPE_LIVE, PLAYBACK_TYPE_OTHER @@ -134,6 +144,7 @@ public final class PlaybackMetrics implements Parcelable { /** @hide */ @IntDef(prefix = "CONTENT_TYPE_", value = { + CONTENT_TYPE_UNKNOWN, CONTENT_TYPE_MAIN, CONTENT_TYPE_AD, CONTENT_TYPE_OTHER @@ -158,6 +169,8 @@ public final class PlaybackMetrics implements Parcelable { 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 @@ public final class PlaybackMetrics implements Parcelable { 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 @@ public final class PlaybackMetrics implements Parcelable { this.mNetworkBytesRead = networkBytesRead; this.mLocalBytesRead = localBytesRead; this.mNetworkTransferDurationMillis = networkTransferDurationMillis; + this.mDrmSessionId = drmSessionId; + this.mExtras = extras.deepCopy(); } /** @@ -321,6 +338,12 @@ public final class PlaybackMetrics implements Parcelable { return mNetworkTransferDurationMillis; } + /** @hide */ + @NonNull + public byte[] getDrmSessionId() { + return mDrmSessionId; + } + @Override public String toString() { return "PlaybackMetrics { " @@ -339,6 +362,7 @@ public final class PlaybackMetrics implements Parcelable { + "networkBytesRead = " + mNetworkBytesRead + ", " + "localBytesRead = " + mLocalBytesRead + ", " + "networkTransferDurationMillis = " + mNetworkTransferDurationMillis + + "drmSessionId = " + Arrays.toString(mDrmSessionId) + " }"; } @@ -361,7 +385,8 @@ public final class PlaybackMetrics implements Parcelable { && 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 @@ public final class PlaybackMetrics implements Parcelable { 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 @@ public final class PlaybackMetrics implements Parcelable { 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 @@ public final class PlaybackMetrics implements Parcelable { 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 @@ public final class PlaybackMetrics implements Parcelable { dest.writeLong(mNetworkBytesRead); dest.writeLong(mLocalBytesRead); dest.writeLong(mNetworkTransferDurationMillis); + dest.writeInt(mDrmSessionId.length); + dest.writeByteArray(mDrmSessionId); } @Override @@ -411,6 +440,7 @@ public final class PlaybackMetrics implements Parcelable { 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 @@ public final class PlaybackMetrics implements Parcelable { 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 @@ public final class PlaybackMetrics implements Parcelable { 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 @@ public final class PlaybackMetrics implements Parcelable { 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 @@ public final class PlaybackMetrics implements Parcelable { 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 @@ public final class PlaybackMetrics implements Parcelable { 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 4ee8a45fe196..272fd9bd5576 100644 --- a/media/java/android/media/metrics/PlaybackSession.java +++ b/media/java/android/media/metrics/PlaybackSession.java @@ -29,6 +29,7 @@ import java.util.Objects; 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 @@ public final class PlaybackSession implements AutoCloseable { mManager = manager; AnnotationValidations.validate(NonNull.class, null, mId); AnnotationValidations.validate(NonNull.class, null, mManager); + mLogSessionId = new LogSessionId(mId); } /** @@ -79,9 +81,16 @@ public final class PlaybackSession implements AutoCloseable { } 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 8ca5b75dec98..dea8c1db71de 100644 --- a/media/java/android/media/metrics/PlaybackStateEvent.java +++ b/media/java/android/media/metrics/PlaybackStateEvent.java @@ -20,6 +20,7 @@ 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; @@ -136,9 +137,11 @@ public final class PlaybackStateEvent extends Event implements Parcelable { */ public PlaybackStateEvent( int state, - long timeSinceCreatedMillis) { + long timeSinceCreatedMillis, + Bundle extras) { this.mTimeSinceCreatedMillis = timeSinceCreatedMillis; this.mState = state; + this.mExtras = extras.deepCopy(); } /** @@ -174,8 +177,12 @@ public final class PlaybackStateEvent extends Event implements Parcelable { @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 @@ public final class PlaybackStateEvent extends Event implements Parcelable { /** @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 final class PlaybackStateEvent extends Event implements Parcelable { 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 @@ public final class PlaybackStateEvent extends Event implements Parcelable { 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 000000000000..541d129604ad --- /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 ef25357457c5..aa519782ec80 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 @@ public final class TrackChangeEvent extends Event implements Parcelable { 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 @@ public final class TrackChangeEvent extends Event implements Parcelable { @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 @@ public final class TrackChangeEvent extends Event implements Parcelable { 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 @@ public final class TrackChangeEvent extends Event implements Parcelable { */ @IntRange(from = -1, to = Integer.MAX_VALUE) public int getSampleRate() { - return mSampleRate; + return mAudioSampleRate; } /** @@ -244,6 +284,16 @@ public final class TrackChangeEvent extends Event implements Parcelable { 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 @@ public final class TrackChangeEvent extends Event implements Parcelable { 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 @@ public final class TrackChangeEvent extends Event implements Parcelable { 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 @@ public final class TrackChangeEvent extends Event implements Parcelable { 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 @@ public final class TrackChangeEvent extends Event implements Parcelable { 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 @@ public final class TrackChangeEvent extends Event implements Parcelable { + "language = " + mLanguage + ", " + "languageRegion = " + mLanguageRegion + ", " + "channelCount = " + mChannelCount + ", " - + "sampleRate = " + mSampleRate + ", " + + "sampleRate = " + mAudioSampleRate + ", " + "width = " + mWidth + ", " - + "height = " + mHeight + + "height = " + mHeight + ", " + + "videoFrameRate = " + mVideoFrameRate + " }"; } @@ -357,16 +415,17 @@ public final class TrackChangeEvent extends Event implements Parcelable { && 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 @@ public final class TrackChangeEvent extends Event implements Parcelable { 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 final class TrackChangeEvent extends Event implements Parcelable { */ 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 @@ public final class TrackChangeEvent extends Event implements Parcelable { 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 @@ public final class TrackChangeEvent extends Event implements Parcelable { 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 98a13cfa6f3f..78db750d4a64 100644 --- a/media/java/android/media/session/MediaSessionManager.java +++ b/media/java/android/media/session/MediaSessionManager.java @@ -541,17 +541,6 @@ public final class MediaSessionManager { * 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 307d80dc15c0..07866ac34e4c 100644 --- a/media/jni/android_media_MediaCodecList.cpp +++ b/media/jni/android_media_MediaCodecList.cpp @@ -105,6 +105,7 @@ static const JavaMediaCodecListWrapper *getCodecList(JNIEnv *env) { // 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 53f6fe24556b..4ccbfaf24c65 100644 --- a/media/jni/android_media_MediaDrm.cpp +++ b/media/jni/android_media_MediaDrm.cpp @@ -376,6 +376,7 @@ jint MediaErrorToJavaError(status_t err) { 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 dc0793af2d17..a64e3f2a7cf0 100644 --- a/media/jni/android_media_MediaDrm.h +++ b/media/jni/android_media_MediaDrm.h @@ -58,12 +58,13 @@ enum { 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/core/java/android/net/OemNetworkPreferences.aidl b/packages/Connectivity/framework/aidl-export/android/net/OemNetworkPreferences.aidl index 2b6a4ceef592..2b6a4ceef592 100644 --- a/core/java/android/net/OemNetworkPreferences.aidl +++ b/packages/Connectivity/framework/aidl-export/android/net/OemNetworkPreferences.aidl diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt index a9fd6f248560..d2ed73ef8298 100644 --- a/packages/Connectivity/framework/api/module-lib-current.txt +++ b/packages/Connectivity/framework/api/module-lib-current.txt @@ -6,6 +6,7 @@ package android.net { } 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 f5972fa34042..a732430e6a9c 100644 --- a/packages/Connectivity/framework/api/system-current.txt +++ b/packages/Connectivity/framework/api/system-current.txt @@ -320,6 +320,26 @@ package android.net { method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int); } + public final class OemNetworkPreferences implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getNetworkPreferences(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.OemNetworkPreferences> CREATOR; + field public static final int OEM_NETWORK_PREFERENCE_OEM_PAID = 1; // 0x1 + field public static final int OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK = 2; // 0x2 + field public static final int OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY = 3; // 0x3 + field public static final int OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY = 4; // 0x4 + field public static final int OEM_NETWORK_PREFERENCE_UNINITIALIZED = 0; // 0x0 + } + + public static final class OemNetworkPreferences.Builder { + ctor public OemNetworkPreferences.Builder(); + ctor public OemNetworkPreferences.Builder(@NonNull android.net.OemNetworkPreferences); + method @NonNull public android.net.OemNetworkPreferences.Builder addNetworkPreference(@NonNull String, int); + method @NonNull public android.net.OemNetworkPreferences build(); + method @NonNull public android.net.OemNetworkPreferences.Builder clearNetworkPreference(@NonNull String); + } + public abstract class QosCallback { ctor public QosCallback(); method public void onError(@NonNull android.net.QosCallbackException); diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java index 39ec2edcea3f..bbf45596e789 100644 --- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java +++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java @@ -1259,6 +1259,25 @@ public class ConnectivityManager { } /** + * 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. * @@ -2886,10 +2905,14 @@ public class ConnectivityManager { ResultReceiver wrappedListener = new ResultReceiver(null) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { - Binder.withCleanCallingIdentity(() -> - executor.execute(() -> { - listener.onTetheringEntitlementResult(resultCode); - })); + final long token = Binder.clearCallingIdentity(); + try { + executor.execute(() -> { + listener.onTetheringEntitlementResult(resultCode); + }); + } finally { + Binder.restoreCallingIdentity(token); + } } }; diff --git a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl index 160338d396af..cd49258d1c47 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.NetworkCapabilities; 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 @@ interface IConnectivityManager @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 cd76f409b093..c82cd3b4f357 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.ArraySet; 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 @@ public final class NetworkCapabilities implements Parcelable { */ @UnsupportedAppUsage public @NetCapability int[] getCapabilities() { - return BitUtils.unpackBits(mNetworkCapabilities); + return NetworkCapabilitiesUtils.unpackBits(mNetworkCapabilities); } /** @@ -620,7 +620,7 @@ public final class NetworkCapabilities implements Parcelable { * @hide */ public @NetCapability int[] getUnwantedCapabilities() { - return BitUtils.unpackBits(mUnwantedNetworkCapabilities); + return NetworkCapabilitiesUtils.unpackBits(mUnwantedNetworkCapabilities); } @@ -632,8 +632,8 @@ public final class NetworkCapabilities implements Parcelable { */ 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 @@ public final class NetworkCapabilities implements Parcelable { & 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 @@ public final class NetworkCapabilities implements Parcelable { */ @SystemApi @NonNull public @Transport int[] getTransportTypes() { - return BitUtils.unpackBits(mTransportTypes); + return NetworkCapabilitiesUtils.unpackBits(mTransportTypes); } /** @@ -956,7 +956,7 @@ public final class NetworkCapabilities implements Parcelable { * @hide */ public void setTransportTypes(@Transport int[] transportTypes) { - mTransportTypes = BitUtils.packBits(transportTypes); + mTransportTypes = NetworkCapabilitiesUtils.packBits(transportTypes); } /** @@ -1721,8 +1721,10 @@ public final class NetworkCapabilities implements Parcelable { 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)); } @@ -1864,7 +1866,7 @@ public final class NetworkCapabilities implements Parcelable { final ArraySet<T> result = new ArraySet<>(size); for (int i = 0; i < size; i++) { final T value = in.readParcelable(loader); - result.append(value); + result.add(value); } return result; } diff --git a/core/java/android/net/NetworkState.java b/packages/Connectivity/framework/src/android/net/NetworkState.java index 813fde1c15f2..d01026566ca0 100644 --- a/core/java/android/net/NetworkState.java +++ b/packages/Connectivity/framework/src/android/net/NetworkState.java @@ -115,7 +115,8 @@ public class NetworkState implements Parcelable { } @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/core/java/android/net/OemNetworkPreferences.java b/packages/Connectivity/framework/src/android/net/OemNetworkPreferences.java index 48bd29769f83..48bd29769f83 100644 --- a/core/java/android/net/OemNetworkPreferences.java +++ b/packages/Connectivity/framework/src/android/net/OemNetworkPreferences.java diff --git a/packages/Connectivity/framework/src/android/net/RouteInfo.java b/packages/Connectivity/framework/src/android/net/RouteInfo.java index 5b6684ace052..fad3144a4b80 100644 --- a/packages/Connectivity/framework/src/android/net/RouteInfo.java +++ b/packages/Connectivity/framework/src/android/net/RouteInfo.java @@ -26,6 +26,7 @@ import android.os.Parcel; import android.os.Parcelable; import com.android.net.module.util.NetUtils; +import com.android.net.module.util.NetworkStackConstants; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -181,9 +182,9 @@ public final class RouteInfo implements Parcelable { if (destination == null) { if (gateway != null) { if (gateway instanceof Inet4Address) { - destination = new IpPrefix(Inet4Address.ANY, 0); + destination = new IpPrefix(NetworkStackConstants.IPV4_ADDR_ANY, 0); } else { - destination = new IpPrefix(Inet6Address.ANY, 0); + destination = new IpPrefix(NetworkStackConstants.IPV6_ADDR_ANY, 0); } } else { // no destination, no gateway. invalid. @@ -196,9 +197,9 @@ public final class RouteInfo implements Parcelable { // ConnectivityService) to stop doing things like r.getGateway().equals(), ... . if (gateway == null) { if (destination.getAddress() instanceof Inet4Address) { - gateway = Inet4Address.ANY; + gateway = NetworkStackConstants.IPV4_ADDR_ANY; } else { - gateway = Inet6Address.ANY; + gateway = NetworkStackConstants.IPV6_ADDR_ANY; } } mHasGateway = (!gateway.isAnyLocalAddress()); diff --git a/packages/Connectivity/framework/src/android/net/util/DnsUtils.java b/packages/Connectivity/framework/src/android/net/util/DnsUtils.java index 7908353eeda2..3fe245edb9e2 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.ErrnoException; 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 @@ public class DnsUtils { 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 43fffd733e91..739ddada50b4 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.database.ContentObserver; 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 @@ public class MultinetworkPolicyTracker { } @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 @@ public class MultinetworkPolicyTracker { } }; - 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 513eba2ddc6d..64628a82fe35 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/SettingsLib/MainSwitchPreference/Android.bp b/packages/SettingsLib/MainSwitchPreference/Android.bp index 1feec21e24e4..7b7496ca650a 100644 --- a/packages/SettingsLib/MainSwitchPreference/Android.bp +++ b/packages/SettingsLib/MainSwitchPreference/Android.bp @@ -15,7 +15,6 @@ android_library { static_libs: [ "androidx.preference_preference", - "SettingsLibRestrictedLockUtils", ], sdk_version: "system_current", diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java index 1c9298ed6085..8d9a562fede7 100644 --- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java +++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java @@ -24,16 +24,12 @@ import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.widget.CompoundButton; -import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.Switch; import android.widget.TextView; -import androidx.annotation.VisibleForTesting; import androidx.core.content.res.TypedArrayUtils; -import com.android.settingslib.RestrictedLockUtils; - import java.util.ArrayList; import java.util.List; @@ -48,12 +44,8 @@ public class MainSwitchBar extends LinearLayout implements CompoundButton.OnChec private View mAboveDivider; private View mBelowDivider; - private TextView mTextView; - private ImageView mRestrictedIcon; - private Switch mSwitch; - - private RestrictedLockUtils.EnforcedAdmin mEnforcedAdmin; - private boolean mDisabledByAdmin; + protected TextView mTextView; + protected Switch mSwitch; public MainSwitchBar(Context context) { this(context, null); @@ -81,14 +73,6 @@ public class MainSwitchBar extends LinearLayout implements CompoundButton.OnChec addOnSwitchChangeListener((switchView, isChecked) -> setChecked(isChecked)); - mRestrictedIcon = findViewById(R.id.restricted_icon); - mRestrictedIcon.setOnClickListener((View v) -> { - if (mDisabledByAdmin) { - RestrictedLockUtils.sendShowAdminSupportDetailsIntent(context, mEnforcedAdmin); - onRestrictedIconClick(); - } - }); - setChecked(mSwitch.isChecked()); if (attrs != null) { @@ -110,7 +94,7 @@ public class MainSwitchBar extends LinearLayout implements CompoundButton.OnChec @Override public boolean performClick() { - return getDelegatingView().performClick(); + return mSwitch.performClick(); } /** @@ -189,51 +173,14 @@ public class MainSwitchBar extends LinearLayout implements CompoundButton.OnChec } /** - * If admin is not null, disables the text and switch but keeps the view clickable. - * Otherwise, calls setEnabled which will enables the entire view including - * the text and switch. - */ - public void setDisabledByAdmin(RestrictedLockUtils.EnforcedAdmin admin) { - mEnforcedAdmin = admin; - if (admin != null) { - super.setEnabled(true); - mDisabledByAdmin = true; - mTextView.setEnabled(false); - mSwitch.setEnabled(false); - mSwitch.setVisibility(View.GONE); - mRestrictedIcon.setVisibility(View.VISIBLE); - } else { - mDisabledByAdmin = false; - mSwitch.setVisibility(View.VISIBLE); - mRestrictedIcon.setVisibility(View.GONE); - setEnabled(true); - } - } - - /** * Enable or disable the text and switch. */ public void setEnabled(boolean enabled) { - if (enabled && mDisabledByAdmin) { - setDisabledByAdmin(null); - return; - } super.setEnabled(enabled); mTextView.setEnabled(enabled); mSwitch.setEnabled(enabled); } - /** - * Called by the restricted icon clicked. - */ - protected void onRestrictedIconClick() { - } - - @VisibleForTesting - View getDelegatingView() { - return mDisabledByAdmin ? mRestrictedIcon : mSwitch; - } - private void propagateChecked(boolean isChecked) { final int count = mSwitchChangeListeners.size(); for (int n = 0; n < count; n++) { diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java index 35afec38dd3d..ebeffcc3c361 100644 --- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java +++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java @@ -24,8 +24,6 @@ import androidx.core.content.res.TypedArrayUtils; import androidx.preference.PreferenceViewHolder; import androidx.preference.TwoStatePreference; -import com.android.settingslib.RestrictedLockUtils; - import java.util.ArrayList; import java.util.List; @@ -41,8 +39,6 @@ public class MainSwitchPreference extends TwoStatePreference { private MainSwitchBar mMainSwitchBar; private CharSequence mTitle; - private RestrictedLockUtils.EnforcedAdmin mEnforcedAdmin; - public MainSwitchPreference(Context context) { super(context); init(context, null); @@ -115,7 +111,6 @@ public class MainSwitchPreference extends TwoStatePreference { if (mMainSwitchBar != null) { mMainSwitchBar.setChecked(checked); mMainSwitchBar.setTitle(mTitle); - mMainSwitchBar.setDisabledByAdmin(mEnforcedAdmin); mMainSwitchBar.show(); } } @@ -142,18 +137,6 @@ public class MainSwitchPreference extends TwoStatePreference { } } - /** - * If admin is not null, disables the text and switch but keeps the view clickable. - * Otherwise, calls setEnabled which will enables the entire view including - * the text and switch. - */ - public void setDisabledByAdmin(RestrictedLockUtils.EnforcedAdmin admin) { - mEnforcedAdmin = admin; - if (mMainSwitchBar != null) { - mMainSwitchBar.setDisabledByAdmin(mEnforcedAdmin); - } - } - private void registerListenerToSwitchBar() { for (OnMainSwitchChangeListener listener : mSwitchChangeListeners) { mMainSwitchBar.addOnSwitchChangeListener(listener); diff --git a/packages/SettingsLib/UsageProgressBarPreference/src/com/android/settingslib/widget/UsageProgressBarPreference.java b/packages/SettingsLib/UsageProgressBarPreference/src/com/android/settingslib/widget/UsageProgressBarPreference.java index af64a1dc2282..21859501c057 100644 --- a/packages/SettingsLib/UsageProgressBarPreference/src/com/android/settingslib/widget/UsageProgressBarPreference.java +++ b/packages/SettingsLib/UsageProgressBarPreference/src/com/android/settingslib/widget/UsageProgressBarPreference.java @@ -160,6 +160,7 @@ public class UsageProgressBarPreference extends Preference { customLayout.removeAllViews(); customLayout.setVisibility(View.GONE); } else { + customLayout.removeAllViews(); customLayout.addView(mCustomImageView); customLayout.setVisibility(View.VISIBLE); } diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml index eafc6147fae8..1a67b5e7dea7 100644 --- a/packages/SettingsLib/res/values-af/strings.xml +++ b/packages/SettingsLib/res/values-af/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (rooi-groen)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (blou-geel)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Kleurregstelling"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Kleurregstelling stel jou in staat om te verstel hoe kleure op jou toestel vertoon word"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Geneutraliseer deur <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g> oor"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Totdat jy dit afskakel"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Sopas"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Foonluidspreker"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Kan nie koppel nie. Skakel toestel af en weer aan"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Bedrade oudiotoestel"</string> <string name="help_label" msgid="3528360748637781274">"Hulp en terugvoer"</string> diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml index 547d0af6200d..97abce186d96 100644 --- a/packages/SettingsLib/res/values-am/strings.xml +++ b/packages/SettingsLib/res/values-am/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"ፕሮታኖማሊ (ቀይ-አረንጓዴ)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ትራይታኖማሊ (ሰማያዊ-ቢጫ)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"የቀለም ማስተካከያ"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"ቀለም ማስተካከያ ቀለሞች በመሣሪያዎ ላይ እንዴት እንደሚታዩ እንዲያስተካክሉ ያስችሉዎታል"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"በ<xliff:g id="TITLE">%1$s</xliff:g> ተሽሯል"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ገደማ ቀርቷል"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"እስኪያጠፉት ድረስ"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"ልክ አሁን"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"የስልክ ድምጽ ማጉያ"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"መገናኘት ላይ ችግር። መሳሪያውን ያጥፉት እና እንደገና ያብሩት"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ባለገመድ የኦዲዮ መሣሪያ"</string> <string name="help_label" msgid="3528360748637781274">"እገዛ እና ግብረመልስ"</string> diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml index c6a1d18f9c1e..f9e12c7149c0 100644 --- a/packages/SettingsLib/res/values-ar/strings.xml +++ b/packages/SettingsLib/res/values-ar/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"غطش الأحمر (الأحمر والأخضر)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"غمش الأزرق (الأزرق والأصفر)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"تصحيح الألوان"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"تسمح لك ميزة تصحيح الألوان بتعديل كيفية عرض الألوان على جهازك."</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"تم الاستبدال بـ <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"يتبقى <xliff:g id="TIME_REMAINING">%1$s</xliff:g> تقريبًا"</string> @@ -519,6 +520,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"إلى أن يتم إيقاف الوضع"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"للتو"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"مكبر صوت الهاتف"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"حدثت مشكلة أثناء الاتصال. يُرجى إيقاف الجهاز ثم إعادة تشغيله."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"جهاز سماعي سلكي"</string> <string name="help_label" msgid="3528360748637781274">"المساعدة والملاحظات والآراء"</string> diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml index e9deb4641e46..efd813a010e0 100644 --- a/packages/SettingsLib/res/values-as/strings.xml +++ b/packages/SettingsLib/res/values-as/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"প্ৰ’টানোমালি (ৰঙা-সেউজীয়া)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ট্ৰাইটান\'মেলী (নীলা-হালধীয়া)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ৰং শুধৰণী"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"ৰং শুধৰণি সুবিধাটোৰে আপোনাক আপোনাৰ ডিভাইচত ৰংবোৰ কেনেকৈ প্ৰদর্শন কৰা হয় সেয়া মিলাবলৈ দিয়ে"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g>ৰ দ্বাৰা অগ্ৰাহ্য কৰা হৈছে"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"প্রায় <xliff:g id="TIME_REMAINING">%1$s</xliff:g> বাকী আছে"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"আপুনি অফ নকৰা পর্যন্ত"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"এই মাত্ৰ"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"ফ’নৰ স্পীকাৰ"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"সংযোগ হোৱাত সমস্যা হৈছে। ডিভাইচটো অফ কৰি পুনৰ অন কৰক"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"তাঁৰযুক্ত অডিঅ’ ডিভাইচ"</string> <string name="help_label" msgid="3528360748637781274">"সহায় আৰু মতামত"</string> diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml index d04409cd5e56..2b0fa86499bc 100644 --- a/packages/SettingsLib/res/values-az/strings.xml +++ b/packages/SettingsLib/res/values-az/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaliya (qırmızı-yaşıl)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaliya (göy-sarı)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Rəng düzəlişi"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Rəng korreksiyası sizə rənglərin cihazınızda necə göstərilməsini tənzimləmək imkanı verir"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Cihazınızda rənglərin necə göstərilməsini tənzimləyin. Bu, aşağıdakıları etmək istədikdə faydalı ola bilər:<br/><br/> <ol> <li> Rəngləri daha dəqiq görmək</li> <li> Fokuslanmaq üçün rəngləri ləğv etmək</li> </ol>"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> tərəfindən qəbul edilmir"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Təxminən <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qalıb"</string> @@ -515,6 +515,7 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Deaktiv edənə qədər"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"İndicə"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Telefon dinamiki"</string> + <string name="media_transfer_this_phone" msgid="7194341457812151531">"Bu telefon"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Qoşulmaqla bağlı problem. Cihazı deaktiv edin, sonra yenidən aktiv edin"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Simli audio cihaz"</string> <string name="help_label" msgid="3528360748637781274">"Yardım və rəy"</string> diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml index ecd70a285bd0..b3186376ad59 100644 --- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml +++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalija (crveno-zeleno)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalija (plavo-žuto)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korekcija boja"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Korekcija boja vam omogućava da prilagodite način na koji se boje prikazuju na uređaju"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Prilagodite način na koji se boje prikazuju na uređaju. To može da bude korisno kada želite:<br/><br/> <ol> <li> da vam se boje tačnije prikazuju</li> <li> da uklonite boje kako biste se fokusirali</li> </ol>"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Zamenjuje ga <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>–<xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Preostalo je oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -516,6 +516,7 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Dok ne isključite"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Upravo"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Zvučnik telefona"</string> + <string name="media_transfer_this_phone" msgid="7194341457812151531">"Ovaj telefon"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem pri povezivanju. Isključite uređaj, pa ga ponovo uključite"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žičani audio uređaj"</string> <string name="help_label" msgid="3528360748637781274">"Pomoć i povratne informacije"</string> diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml index 6a3b961d1c5c..7a5aec4d3b9b 100644 --- a/packages/SettingsLib/res/values-be/strings.xml +++ b/packages/SettingsLib/res/values-be/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Пратанамалія (чырвоны-зялёны)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Трытанамалія (сіні-жоўты)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Карэкцыя колеру"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Карэкцыя колеру дазволіць вам наладзіць адлюстраванне колераў на экране прылады"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Перавызначаны <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Зараду хопіць прыблізна на <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -517,6 +518,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Пакуль не выключыце"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Толькі што"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Дынамік тэлефона"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Праблема з падключэннем. Выключыце і зноў уключыце прыладу"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Правадная аўдыяпрылада"</string> <string name="help_label" msgid="3528360748637781274">"Даведка і водгукі"</string> diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml index d2bf70565be9..9ff2531c0e7c 100644 --- a/packages/SettingsLib/res/values-bg/strings.xml +++ b/packages/SettingsLib/res/values-bg/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалия (червено – зелено)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалия (синьо – жълто)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Корекция на цветове"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Функцията „Корекция на цветове“ ви позволява да коригирате това, как цветовете се показват на устройството ви"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Коригирайте как цветовете се показват на устройството ви. Това може да бъде полезно, когато искате да:<br/><br/> <ol> <li> видите цветовете по-ясно;</li> <li> премахнете цветовете, за да се фокусирате.</li> </ol>"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Заменено от „<xliff:g id="TITLE">%1$s</xliff:g>“"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Още около <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,6 +515,7 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"До изключване"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Току-що"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Високоговорител"</string> + <string name="media_transfer_this_phone" msgid="7194341457812151531">"Този телефон"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"При свързването възникна проблем. Изключете устройството и го включете отново"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Аудиоустройство с кабел"</string> <string name="help_label" msgid="3528360748637781274">"Помощ и отзиви"</string> diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml index 3ccf0e426b77..675d1794ae1a 100644 --- a/packages/SettingsLib/res/values-bn/strings.xml +++ b/packages/SettingsLib/res/values-bn/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"প্রোটানোম্যালি (লাল-সবুজ)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ট্রিট্যানোম্যালি (নীল-হলুদ)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"রঙ সংশোধন"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"ডিভাইসে রঙগুলি কেমনভাবে দেখানো হবে তা অ্যাডজাস্ট করতে \'রঙ সংশোধন করুন\' বিকল্প ব্যবহার করা যেতে পারে"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> এর দ্বারা ওভাররাইড করা হয়েছে"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"আর আনুমানিক <xliff:g id="TIME_REMAINING">%1$s</xliff:g> চলবে"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"যতক্ষণ না আপনি বন্ধ করছেন"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"এখনই"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"ফোনের স্পিকার"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"কানেক্ট করতে সমস্যা হচ্ছে। ডিভাইস বন্ধ করে আবার চালু করুন"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ওয়্যার অডিও ডিভাইস"</string> <string name="help_label" msgid="3528360748637781274">"সহায়তা ও মতামত"</string> diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml index f01eef340abc..97083ad15519 100644 --- a/packages/SettingsLib/res/values-bs/strings.xml +++ b/packages/SettingsLib/res/values-bs/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalija (crveno-zeleno)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalija (plavo-žuto)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Ispravka boje"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Ispravka boje vam dozvoljava da prilagodite način prikazivanja boja na uređaju"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Zamjenjuje <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Preostalo je još oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -516,6 +517,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Dok ne isključite"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Upravo"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Zvučnik telefona"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Došlo je do problema prilikom povezivanja. Isključite, pa ponovo uključite uređaj"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žičani audio uređaj"</string> <string name="help_label" msgid="3528360748637781274">"Pomoć i povratne informacije"</string> diff --git a/packages/SettingsLib/res/values-ca/arrays.xml b/packages/SettingsLib/res/values-ca/arrays.xml index 3fd968ba4763..9202013641ea 100644 --- a/packages/SettingsLib/res/values-ca/arrays.xml +++ b/packages/SettingsLib/res/values-ca/arrays.xml @@ -234,7 +234,7 @@ <item msgid="4433736508877934305">"Cap"</item> <item msgid="9140053004929079158">"Logcat"</item> <item msgid="3866871644917859262">"Systrace (gràfics)"</item> - <item msgid="7345673972166571060">"Pila de trucades a glGetError"</item> + <item msgid="7345673972166571060">"Pila de crides a glGetError"</item> </string-array> <string-array name="show_non_rect_clip_entries"> <item msgid="2482978351289846212">"Desactivat"</item> diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml index 7069999fc8e7..4889220a8894 100644 --- a/packages/SettingsLib/res/values-ca/strings.xml +++ b/packages/SettingsLib/res/values-ca/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (vermell-verd)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (blau-groc)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correcció de color"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"La correcció de color permet ajustar com es mostren els colors al teu dispositiu"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"S\'ha substituït per <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>: <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Temps restant aproximat: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Fins que no el desactivis"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Ara mateix"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Altaveu del telèfon"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Hi ha hagut un problema amb la connexió. Desactiva el dispositiu i torna\'l a activar."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositiu d\'àudio amb cable"</string> <string name="help_label" msgid="3528360748637781274">"Ajuda i suggeriments"</string> diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml index c677feffc384..e857e60ed224 100644 --- a/packages/SettingsLib/res/values-cs/strings.xml +++ b/packages/SettingsLib/res/values-cs/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomálie (červená a zelená)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomálie (modrá a žlutá)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korekce barev"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Korekce barev umožňuje upravit zobrazování barev na zařízení"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Přepsáno nastavením <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Zbývá asi <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -517,6 +518,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Dokud tuto funkci nevypnete"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Právě teď"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Reproduktor telefonu"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problém s připojením. Vypněte zařízení a znovu jej zapněte"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Kabelové audiozařízení"</string> <string name="help_label" msgid="3528360748637781274">"Nápověda a zpětná vazba"</string> diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml index 84247a622740..53e21ba3abc2 100644 --- a/packages/SettingsLib/res/values-da/strings.xml +++ b/packages/SettingsLib/res/values-da/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanopi (rød-grøn)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanopi (blå-gul)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korriger farver"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Ved hjælp af farvekorrigering kan du justere, hvordan farver ser ud på din enhed"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Tilsidesat af <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Ca. <xliff:g id="TIME_REMAINING">%1$s</xliff:g> tilbage"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Indtil du deaktiverer"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Lige nu"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Telefonens højttaler"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Der kunne ikke oprettes forbindelse. Sluk og tænd enheden"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Lydenhed med ledning"</string> <string name="help_label" msgid="3528360748637781274">"Hjælp og feedback"</string> diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml index 4cc79d32b797..a4a976fcf34d 100644 --- a/packages/SettingsLib/res/values-de/strings.xml +++ b/packages/SettingsLib/res/values-de/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (Rot-Grün-Sehschwäche)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (Blau-Gelb-Sehschwäche)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Farbkorrektur"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Mit der Farbkorrektur kannst du anpassen, wie Farben auf deinem Display angezeigt werden"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Außer Kraft gesetzt von \"<xliff:g id="TITLE">%1$s</xliff:g>\""</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Noch etwa <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Bis zur Deaktivierung"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Gerade eben"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Smartphone-Lautsprecher"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Verbindung kann nicht hergestellt werden. Schalte das Gerät aus & und wieder ein."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Netzbetriebenes Audiogerät"</string> <string name="help_label" msgid="3528360748637781274">"Hilfe und Feedback"</string> diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml index 30705a1f6f62..76faa4c13617 100644 --- a/packages/SettingsLib/res/values-el/strings.xml +++ b/packages/SettingsLib/res/values-el/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Πρωτανοπία (κόκκινο-πράσινο)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Τριτανοπία (μπλε-κίτρινο)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Διόρθωση χρωμάτων"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Η διόρθωση χρωμάτων σάς επιτρέπει να ρυθμίσετε τον τρόπο εμφάνισης των χρωμάτων στη συσκευή σας"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Προσαρμόστε πώς θα εμφανίζονται τα χρώματα στη συσκευή σας. Αυτό μπορεί να είναι χρήσιμο όταν θέλετε:<br/><br/> <ol> <li> Να βλέπετε τα χρώματα με μεγαλύτερη ακρίβεια</li> <li> Να καταργήσετε τα χρώματα για να συγκεντρωθείτε</li> </ol>"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Αντικαταστάθηκε από <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Απομένει/ουν περίπου <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,6 +515,7 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Μέχρι την απενεργοποίηση"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Μόλις τώρα"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Ηχείο τηλεφώνου"</string> + <string name="media_transfer_this_phone" msgid="7194341457812151531">"Αυτό το τηλέφωνο"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Πρόβλημα κατά τη σύνδεση. Απενεργοποιήστε τη συσκευή και ενεργοποιήστε την ξανά"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Ενσύρματη συσκευή ήχου"</string> <string name="help_label" msgid="3528360748637781274">"Βοήθεια και σχόλια"</string> diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml index b3d80abfc0a2..9a63404229a5 100644 --- a/packages/SettingsLib/res/values-en-rAU/strings.xml +++ b/packages/SettingsLib/res/values-en-rAU/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (red-green)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (blue-yellow)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Colour correction"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Colour correction allows you to adjust how colours are displayed on your device"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Adjust how colours display on your device. This can be helpful when you want to:<br/><br/> <ol> <li> See colours more accurately</li> <li> Remove colours to help you focus</li> </ol>"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string> @@ -515,6 +515,7 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Until you turn off"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Phone speaker"</string> + <string name="media_transfer_this_phone" msgid="7194341457812151531">"This phone"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off and back on"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string> <string name="help_label" msgid="3528360748637781274">"Help and feedback"</string> diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml index ecf97ad07c85..49271dbed6f5 100644 --- a/packages/SettingsLib/res/values-en-rCA/strings.xml +++ b/packages/SettingsLib/res/values-en-rCA/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (red-green)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (blue-yellow)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Colour correction"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Colour correction allows you to adjust how colours are displayed on your device"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Adjust how colours display on your device. This can be helpful when you want to:<br/><br/> <ol> <li> See colours more accurately</li> <li> Remove colours to help you focus</li> </ol>"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string> @@ -515,6 +515,7 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Until you turn off"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Phone speaker"</string> + <string name="media_transfer_this_phone" msgid="7194341457812151531">"This phone"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off and back on"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string> <string name="help_label" msgid="3528360748637781274">"Help and feedback"</string> diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml index b3d80abfc0a2..9a63404229a5 100644 --- a/packages/SettingsLib/res/values-en-rGB/strings.xml +++ b/packages/SettingsLib/res/values-en-rGB/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (red-green)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (blue-yellow)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Colour correction"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Colour correction allows you to adjust how colours are displayed on your device"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Adjust how colours display on your device. This can be helpful when you want to:<br/><br/> <ol> <li> See colours more accurately</li> <li> Remove colours to help you focus</li> </ol>"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string> @@ -515,6 +515,7 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Until you turn off"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Phone speaker"</string> + <string name="media_transfer_this_phone" msgid="7194341457812151531">"This phone"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off and back on"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string> <string name="help_label" msgid="3528360748637781274">"Help and feedback"</string> diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml index b3d80abfc0a2..9a63404229a5 100644 --- a/packages/SettingsLib/res/values-en-rIN/strings.xml +++ b/packages/SettingsLib/res/values-en-rIN/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (red-green)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (blue-yellow)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Colour correction"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Colour correction allows you to adjust how colours are displayed on your device"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Adjust how colours display on your device. This can be helpful when you want to:<br/><br/> <ol> <li> See colours more accurately</li> <li> Remove colours to help you focus</li> </ol>"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string> @@ -515,6 +515,7 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Until you turn off"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Phone speaker"</string> + <string name="media_transfer_this_phone" msgid="7194341457812151531">"This phone"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off and back on"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string> <string name="help_label" msgid="3528360748637781274">"Help and feedback"</string> diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml index c3a3f3f484fb..3476b975253f 100644 --- a/packages/SettingsLib/res/values-en-rXC/strings.xml +++ b/packages/SettingsLib/res/values-en-rXC/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (red-green)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (blue-yellow)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Color correction"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Color correction allows you to adjust how colors are displayed on your device"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Adjust how colors display on your device. This can be helpful when you want to:<br/><br/> <ol> <li> See colors more accurately</li> <li> Remove colors to help you focus</li> </ol>"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string> @@ -515,6 +515,7 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Until you turn off"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Phone speaker"</string> + <string name="media_transfer_this_phone" msgid="7194341457812151531">"This phone"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off & back on"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string> <string name="help_label" msgid="3528360748637781274">"Help & feedback"</string> diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml index eb2a23b45e70..71cf5cbea0f2 100644 --- a/packages/SettingsLib/res/values-es-rUS/strings.xml +++ b/packages/SettingsLib/res/values-es-rUS/strings.xml @@ -220,7 +220,7 @@ <string name="adb_wireless_device_connected_summary" msgid="3039660790249148713">"Conectado actualmente"</string> <string name="adb_wireless_device_details_title" msgid="7129369670526565786">"Detalles del dispositivo"</string> <string name="adb_device_forget" msgid="193072400783068417">"Olvidar"</string> - <string name="adb_device_fingerprint_title_format" msgid="291504822917843701">"Huellas digitales del dispositivo: <xliff:g id="FINGERPRINT_PARAM">%1$s</xliff:g>"</string> + <string name="adb_device_fingerprint_title_format" msgid="291504822917843701">"Huellas dactilares del dispositivo: <xliff:g id="FINGERPRINT_PARAM">%1$s</xliff:g>"</string> <string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"Error de conexión"</string> <string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"Asegúrate de que <xliff:g id="DEVICE_NAME">%1$s</xliff:g> esté conectado a la red correcta."</string> <string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"Vincular con dispositivo"</string> @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalía (rojo-verde)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalía (azul-amarillo)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Corrección de color"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"La corrección de color te permite ajustar la manera en que se muestran los colores en el dispositivo"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Reemplazado por <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tiempo restante: aproximadamente <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Hasta que lo desactives"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Recién"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Altavoz del teléfono"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Error al establecer la conexión. Apaga el dispositivo y vuelve a encenderlo."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string> <string name="help_label" msgid="3528360748637781274">"Ayuda y comentarios"</string> diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml index fe9984b701db..a7d7b215e3a8 100644 --- a/packages/SettingsLib/res/values-es/strings.xml +++ b/packages/SettingsLib/res/values-es/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalía (rojo-verde)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalía (azul-amarillo)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Corrección de color"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"La corrección de color te permite ajustar cómo se muestran los colores en tu dispositivo"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Anulado por <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>: <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tiempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Hasta que lo desactives"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"justo ahora"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Altavoz del teléfono"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"No se ha podido conectar; reinicia el dispositivo"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string> <string name="help_label" msgid="3528360748637781274">"Ayuda y comentarios"</string> diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml index c70700ddc24c..add25f839d21 100644 --- a/packages/SettingsLib/res/values-et/strings.xml +++ b/packages/SettingsLib/res/values-et/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaalia (punane-roheline)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaalia (sinine-kollane)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Värvide korrigeerimine"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Värvide korrigeerimine võimaldab kohandada seadmes kuvatavaid värve"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Alistas <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Ligikaudu <xliff:g id="TIME_REMAINING">%1$s</xliff:g> jäänud"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Kuni välja lülitate"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Äsja"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Telefoni kõlar"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Probleem ühendamisel. Lülitage seade välja ja uuesti sisse"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Juhtmega heliseade"</string> <string name="help_label" msgid="3528360748637781274">"Abi ja tagasiside"</string> diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml index 09c964aa9dd1..c95d15761561 100644 --- a/packages/SettingsLib/res/values-eu/strings.xml +++ b/packages/SettingsLib/res/values-eu/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanopia (gorri-berdeak)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanopia (urdin-horia)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Koloreen zuzenketa"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Koloreen zuzenketaren bidez, gailuan koloreak bistaratzen diren modua doi dezakezu"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> hobespena gainjarri zaio"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> inguru gelditzen dira"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Zuk desaktibatu arte"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Oraintxe"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Telefonoaren bozgorailua"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Arazoren bat izan da konektatzean. Itzali gailua eta pitz ezazu berriro."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Audio-gailu kableduna"</string> <string name="help_label" msgid="3528360748637781274">"Laguntza eta iritziak"</string> diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml index 22cd6ae68de2..631ff5e3cbc4 100644 --- a/packages/SettingsLib/res/values-fa/strings.xml +++ b/packages/SettingsLib/res/values-fa/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"قرمزدشواربینی (قرمز-سبز)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"آبیدشواربینی (آبی-زرد)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"تصحیح رنگ"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"تصحیح رنگ به شما امکان میدهد نحوه نمایش رنگها را در دستگاهتان تنظیم کنید"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"توسط <xliff:g id="TITLE">%1$s</xliff:g> لغو شد"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"تقریباً <xliff:g id="TIME_REMAINING">%1$s</xliff:g> شارژ باقی مانده است"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"تا زمانیکه آن را خاموش کنید"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"هماکنون"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"بلندگوی تلفن"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"مشکل در اتصال. دستگاه را خاموش و دوباره روشن کنید"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"دستگاه صوتی سیمی"</string> <string name="help_label" msgid="3528360748637781274">"راهنما و بازخورد"</string> diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml index 22dde690c3cf..7591c911b96e 100644 --- a/packages/SettingsLib/res/values-fi/strings.xml +++ b/packages/SettingsLib/res/values-fi/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (puna-vihersokeus)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (sini-keltasokeus)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Värinkorjaus"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Värinkorjauksella voit muuttaa värien näkymistä laitteellasi"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Tämän ohittaa <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Noin <xliff:g id="TIME_REMAINING">%1$s</xliff:g> jäljellä"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Kunnes laitat pois päältä"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Äsken"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Puhelimen kaiutin"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Yhteysvirhe. Sammuta laite ja käynnistä se uudelleen."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Langallinen äänilaite"</string> <string name="help_label" msgid="3528360748637781274">"Ohje ja palaute"</string> diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml index d189f72aad65..a390257c8ce4 100644 --- a/packages/SettingsLib/res/values-fr-rCA/strings.xml +++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (rouge/vert)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (bleu/jaune)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correction des couleurs"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"La correction des couleurs vous permet d\'ajuster la manière dont les couleurs s\'affichent sur votre appareil"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Remplacé par <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> : <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Il reste environ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Jusqu\'à la désactivation"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"À l\'instant"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Haut-parleur du téléphone"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problème de connexion. Éteingez et rallumez l\'appareil"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Appareil audio à câble"</string> <string name="help_label" msgid="3528360748637781274">"Aide et commentaires"</string> diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml index 49d7faa63a3b..8cf8c6ee5ee6 100644 --- a/packages/SettingsLib/res/values-fr/strings.xml +++ b/packages/SettingsLib/res/values-fr/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (rouge/vert)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (bleu-jaune)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correction des couleurs"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"La correction des couleurs vous permet d\'ajuster l\'affichage des couleurs sur votre appareil"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Remplacé par <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Temps restant : environ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Jusqu\'à la désactivation"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"À l\'instant"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Haut-parleur du téléphone"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problème de connexion. Éteignez l\'appareil, puis rallumez-le"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Appareil audio filaire"</string> <string name="help_label" msgid="3528360748637781274">"Aide et commentaires"</string> diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml index 0922c3dca3af..c1ba51d798f1 100644 --- a/packages/SettingsLib/res/values-gl/strings.xml +++ b/packages/SettingsLib/res/values-gl/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalía (vermello-verde)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalía (azul-amarelo)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Corrección da cor"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"A corrección da cor permíteche axustar como se mostran as cores no dispositivo"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Anulado por <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Ata a desactivación"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Agora mesmo"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Altofalante do teléfono"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Produciuse un problema coa conexión. Apaga e acende o dispositivo."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string> <string name="help_label" msgid="3528360748637781274">"Axuda e comentarios"</string> diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml index 10c5cc87c6da..94d83e0577bf 100644 --- a/packages/SettingsLib/res/values-gu/strings.xml +++ b/packages/SettingsLib/res/values-gu/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"પ્રોટેનોમલી (લાલ-લીલો)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ટ્રાઇટેનોમલી(વાદળી-પીળો)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"રંગ સુધારણા"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"રંગ સુધારણા તમને તમારા ડિવાઇસ પર રંગો કેવી રીતે બતાવવામાં આવે તેની ગોઠવણી કરવાની મંજૂરી આપે છે"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> દ્વારા ઓવરરાઇડ થયું"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"લગભગ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> બાકી છે"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"તમે બંધ ન કરો ત્યાં સુધી"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"હમણાં જ"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"ફોન સ્પીકર"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"કનેક્ટ કરવામાં સમસ્યા આવી રહી છે. ડિવાઇસને બંધ કરીને ફરી ચાલુ કરો"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"વાયરવાળો ઑડિયો ડિવાઇસ"</string> <string name="help_label" msgid="3528360748637781274">"સહાય અને પ્રતિસાદ"</string> diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml index ea25406b1541..835e760df1b3 100644 --- a/packages/SettingsLib/res/values-hi/strings.xml +++ b/packages/SettingsLib/res/values-hi/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"लाल रंग पहचान न पाना (लाल-हरा)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"नीला रंग पहचान न पाना (नीला-पीला)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"रंग में सुधार करने की सुविधा"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"रंग में सुधार करने की सुविधा, आपके डिवाइस पर दिखने वाले रंगों में बदलाव करने में मदद करती है"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"आपके डिवाइस पर रंगों के दिखने के तरीके में बदलाव करें. इससे, आपको इनमें मदद मिलेगी:<br/><br/> <ol> <li> रंगों को बेहतर तरीके से देखने में</li> <li> आसानी से फ़ोकस करने के लिए, रंग हटाने में</li> </ol>"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> के द्वारा ओवरराइड किया गया"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"बैटरी करीब <xliff:g id="TIME_REMAINING">%1$s</xliff:g> में खत्म हो जाएगी"</string> @@ -515,6 +515,7 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"जब तक आप इसे बंद नहीं करते"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"अभी-अभी"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"फ़ोन का स्पीकर"</string> + <string name="media_transfer_this_phone" msgid="7194341457812151531">"यह फ़ोन"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"कनेक्ट करने में समस्या हो रही है. डिवाइस को बंद करके चालू करें"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"वायर वाला ऑडियो डिवाइस"</string> <string name="help_label" msgid="3528360748637781274">"सहायता और सुझाव"</string> diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml index 27a7a6e7891a..e99d4cb94e8b 100644 --- a/packages/SettingsLib/res/values-hr/strings.xml +++ b/packages/SettingsLib/res/values-hr/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalija (crveno – zeleno)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalija (plavo – žuto)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korekcija boje"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Korekcija boje omogućuje vam prilagodbu načina prikazivanja boja na vašem uređaju"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Premošćeno postavkom <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Još otprilike <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -516,6 +517,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Dok ne isključite"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Upravo sad"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Zvučnik telefona"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem s povezivanjem. Isključite i ponovo uključite uređaj"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žičani audiouređaj"</string> <string name="help_label" msgid="3528360748637781274">"Pomoć i povratne informacije"</string> diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml index 70a48b638506..503ee6020361 100644 --- a/packages/SettingsLib/res/values-hu/strings.xml +++ b/packages/SettingsLib/res/values-hu/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomália (piros– zöld)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomália (kék–sárga)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Színkorrekció"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"A színkorrekcióval módosíthatja a színek megjelenítésének módját az eszközön"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Felülírva erre: <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Körülbelül <xliff:g id="TIME_REMAINING">%1$s</xliff:g> maradt hátra"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Kikapcsolásig"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Az imént"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Telefon hangszórója"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Sikertelen csatlakozás. Kapcsolja ki az eszközt, majd kapcsolja be újra."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Vezetékes audioeszköz"</string> <string name="help_label" msgid="3528360748637781274">"Súgó és visszajelzés"</string> diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml index c39e966d880a..3686dd171964 100644 --- a/packages/SettingsLib/res/values-hy/strings.xml +++ b/packages/SettingsLib/res/values-hy/strings.xml @@ -404,7 +404,7 @@ <string name="transcode_user_control" msgid="6176368544817731314">"Չեղարկել վերակոդավորման կանխադրված կարգավորումները"</string> <string name="transcode_enable_all" msgid="2411165920039166710">"Միացնել վերակոդավորումը"</string> <string name="transcode_default" msgid="3784803084573509491">"Ենթադրել, որ հավելվածներն աջակցում են ժամանակակից ձևաչափեր"</string> - <string name="transcode_notification" msgid="5560515979793436168">"Ցուցադրել անդրկոդավորման ծանուցումներ"</string> + <string name="transcode_notification" msgid="5560515979793436168">"Ցույց տալ տրանսկոդավորման մասին ծանուցումները"</string> <string name="runningservices_settings_title" msgid="6460099290493086515">"Աշխատող ծառայություններ"</string> <string name="runningservices_settings_summary" msgid="1046080643262665743">"Դիտել և վերահսկել ընթացիկ աշխատող ծառայությունները"</string> <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ծառայություն"</string> @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Պրոտանոմալիա (կարմիր-կանաչ)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Տրիտանոմալիա (կապույտ-դեղին)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Գունաշտկում"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Գունաշտկումը թույլ է տալիս կարգավորել գույների ցուցադրումն այս սարքում"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Գերազանցված է <xliff:g id="TITLE">%1$s</xliff:g>-ից"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Լիցքը կբավարարի մոտ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Մինչև չանջատեք"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Հենց նոր"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Հեռախոսի բարձրախոս"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Կապի խնդիր կա: Սարքն անջատեք և նորից միացրեք:"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Լարով աուդիո սարք"</string> <string name="help_label" msgid="3528360748637781274">"Օգնություն և հետադարձ կապ"</string> diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml index 037c1b3b3e76..035be7d90e05 100644 --- a/packages/SettingsLib/res/values-in/strings.xml +++ b/packages/SettingsLib/res/values-in/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomali (merah-hijau)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomali (biru-kuning)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Koreksi warna"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Koreksi warna memungkinkan Anda untuk menyesuaikan cara warna ditampilkan pada perangkat Anda"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Digantikan oleh <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Sekitar <xliff:g id="TIME_REMAINING">%1$s</xliff:g> lagi"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Sampai Anda menonaktifkannya"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Baru saja"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Speaker ponsel"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ada masalah saat menghubungkan. Nonaktifkan perangkat & aktifkan kembali"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Perangkat audio berkabel"</string> <string name="help_label" msgid="3528360748637781274">"Bantuan & masukan"</string> diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml index 3f8783053ba3..718b5be270a7 100644 --- a/packages/SettingsLib/res/values-is/strings.xml +++ b/packages/SettingsLib/res/values-is/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Litblinda (rauðgræn)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Litblinda (blágul)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Litaleiðrétting"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Litaleiðrétting gerir þér kleift að stilla hvernig litir birtast í tækinu þínu"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Hnekkt af <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Um það bil <xliff:g id="TIME_REMAINING">%1$s</xliff:g> eftir"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Þar til þú slekkur"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Rétt í þessu"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Símahátalari"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Vandamál í tengingu. Slökktu og kveiktu á tækinu"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Snúrutengt hljómtæki"</string> <string name="help_label" msgid="3528360748637781274">"Hjálp og ábendingar"</string> diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml index 80ab57b66548..d2176d905b34 100644 --- a/packages/SettingsLib/res/values-it/strings.xml +++ b/packages/SettingsLib/res/values-it/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalìa (rosso-verde)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalìa (blu-giallo)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correzione del colore"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"La correzione del colore ti consente di regolare la visualizzazione dei colori sul tuo dispositivo"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Valore sostituito da <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tempo rimanente: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> circa"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Fino alla disattivazione"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Adesso"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Altoparlante telefono"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problema di connessione. Spegni e riaccendi il dispositivo"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo audio cablato"</string> <string name="help_label" msgid="3528360748637781274">"Guida e feedback"</string> diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml index 4355f31e3ed1..1357cae170f7 100644 --- a/packages/SettingsLib/res/values-iw/strings.xml +++ b/packages/SettingsLib/res/values-iw/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"פרוטנומליה (אדום-ירוק)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"טריטנומליה (כחול-צהוב)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"תיקון צבע"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"תיקון צבע מאפשר לשנות את האופן שבו צבעים מוצגים במכשיר שלך"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"נעקף על ידי <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"הזמן הנותר: בערך <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -517,6 +518,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"עד הכיבוי"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"הרגע"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"רמקול של טלפון"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"יש בעיה בחיבור. עליך לכבות את המכשיר ולהפעיל אותו מחדש"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"התקן אודיו חוטי"</string> <string name="help_label" msgid="3528360748637781274">"עזרה ומשוב"</string> diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml index ea4a683dd283..4a9126f066af 100644 --- a/packages/SettingsLib/res/values-ja/strings.xml +++ b/packages/SettingsLib/res/values-ja/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"第一色弱(赤緑)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"第三色弱(青黄)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"色補正"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"色補正機能では、デバイスで色をどのように表示するかを調整できます"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"デバイスで色をどのように表示するかを調整できます。この設定は以下の場合に役立ちます。<br/><br/> <ol> <li> 色をより正確に表示したい場合</li> <li> はっきり読み取れるよう色を取り除きたい場合</li> </ol>"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g>によって上書き済み"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"残り時間: 約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,6 +515,7 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"OFF にするまで"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"たった今"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"スマートフォンのスピーカー"</string> + <string name="media_transfer_this_phone" msgid="7194341457812151531">"このスマートフォン"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"接続エラーです。デバイスを OFF にしてから ON に戻してください"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有線オーディオ デバイス"</string> <string name="help_label" msgid="3528360748637781274">"ヘルプとフィードバック"</string> diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml index 5798a46e7c99..8bb6ba892e6d 100644 --- a/packages/SettingsLib/res/values-ka/strings.xml +++ b/packages/SettingsLib/res/values-ka/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"პროტოანომალია (წითელი-მწვანე)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ტრიტანომალია (ლურჯი-ყვითელი)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ფერის კორექცია"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"ფერთა კორექცია საშუალებას გაძლევთ დაარეგულიროთ, თუ როგორ გამოჩნდება ფერები თქვენს მოწყობილობაზე"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"უკუგებულია <xliff:g id="TITLE">%1$s</xliff:g>-ის მიერ"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"დარჩა დაახლოებით <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"გამორთვამდე"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"ახლახან"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"ტელეფონის დინამიკი"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"დაკავშირებისას წარმოიქმნა პრობლემა. გამორთეთ და კვლავ ჩართეთ მოწყობილობა"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"სადენიანი აუდიო მოწყობილობა"</string> <string name="help_label" msgid="3528360748637781274">"დახმარება და გამოხმაურება"</string> diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml index 5ce4e3a8f1c8..6a2c21eee17f 100644 --- a/packages/SettingsLib/res/values-kk/strings.xml +++ b/packages/SettingsLib/res/values-kk/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалия (қызыл-жасыл)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалия (көк-сары)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Түсті түзету"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Түсті түзету функциясының көмегімен құрылғыңызда көрсетілетін түстерді реттеуге болады."</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> үстінен басқан"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Шамамен <xliff:g id="TIME_REMAINING">%1$s</xliff:g> қалды"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Өшірілгенге дейін"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Дәл қазір"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Телефон динамигі"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Байланыс орнату қатесі шығуып жатыр. Құрылғыны өшіріп, қайта қосыңыз."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Сымды аудио құрылғысы"</string> <string name="help_label" msgid="3528360748637781274">"Анықтама және пікір"</string> diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml index e6f2cb03439e..f4cece4aa038 100644 --- a/packages/SettingsLib/res/values-km/strings.xml +++ b/packages/SettingsLib/res/values-km/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (ក្រហមពណ៌បៃតង)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (ពណ៌ខៀវ-លឿង)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ការកែពណ៌"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"ការកែតម្រូវពណ៌អនុញ្ញាតឱ្យអ្នកកែតម្រូវរបៀបបង្ហាញពណ៌នៅលើឧបករណ៍របស់អ្នក"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"កែតម្រូវរបៀបដែលពណ៌បង្ហាញនៅលើឧបករណ៍របស់អ្នក។ ចំណុចនេះអាចមានប្រយោជន៍ នៅពេលដែលអ្នកចង់៖<br/><br/> <ol> <li> មើលឃើញពណ៌កាន់តែត្រឹមត្រូវ</li> <li> លុបពណ៌ ដើម្បីជួយអ្នកក្នុងការផ្ដោត</li> </ol>"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"បដិសេធដោយ <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"នៅសល់ប្រហែល <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ទៀត"</string> @@ -515,6 +515,7 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"រហូតទាល់តែអ្នកបិទ"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"អម្បាញ់មិញ"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"ឧបករណ៍បំពងសំឡេងទូរសព្ទ"</string> + <string name="media_transfer_this_phone" msgid="7194341457812151531">"ទូរសព្ទនេះ"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"មានបញ្ហាក្នុងការភ្ជាប់។ បិទ រួចបើកឧបករណ៍វិញ"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ឧបករណ៍សំឡេងប្រើខ្សែ"</string> <string name="help_label" msgid="3528360748637781274">"ជំនួយ និងមតិកែលម្អ"</string> diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml index 561e6bed887d..a844ee6d0ad5 100644 --- a/packages/SettingsLib/res/values-kn/strings.xml +++ b/packages/SettingsLib/res/values-kn/strings.xml @@ -404,8 +404,7 @@ <string name="transcode_user_control" msgid="6176368544817731314">"ಟ್ರಾನ್ಸ್ಕೋಡಿಂಗ್ ಡೀಫಾಲ್ಟ್ಗಳನ್ನು ಅತಿಕ್ರಮಿಸಿ"</string> <string name="transcode_enable_all" msgid="2411165920039166710">"ಟ್ರಾನ್ಸ್ಕೋಡಿಂಗ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string> <string name="transcode_default" msgid="3784803084573509491">"ಆ್ಯಪ್ಗಳು ಆಧುನಿಕ ಫಾರ್ಮ್ಯಾಟ್ಗಳನ್ನು ಬೆಂಬಲಿಸುತ್ತದೆ ಎಂದು ಊಹಿಸಿ"</string> - <!-- no translation found for transcode_notification (5560515979793436168) --> - <skip /> + <string name="transcode_notification" msgid="5560515979793436168">"ಟ್ರಾನ್ಸ್ಕೋಡಿಂಗ್ ಅಧಿಸೂಚನೆಗಳನ್ನು ತೋರಿಸಿ"</string> <string name="runningservices_settings_title" msgid="6460099290493086515">"ರನ್ ಆಗುತ್ತಿರುವ ಸೇವೆಗಳು"</string> <string name="runningservices_settings_summary" msgid="1046080643262665743">"ಈಗ ರನ್ ಆಗುತ್ತಿರುವ ಸೇವೆಗಳನ್ನು ವೀಕ್ಷಿಸಿ ಮತ್ತು ನಿಯಂತ್ರಿಸಿ"</string> <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ಹೊಂದಿಸಿ"</string> @@ -425,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"ಪ್ರೊಟನೋಮಲಿ (ಕೆಂಪು-ಹಸಿರು)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ಟ್ರಿಟನೋಮಲಿ (ನೀಲಿ-ಹಳದಿ)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ಬಣ್ಣದ ತಿದ್ದುಪಡಿ"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಬಣ್ಣಗಳನ್ನು ಹೇಗೆ ಪ್ರದರ್ಶಿಸಲಾಗುತ್ತದೆ ಎಂಬುದನ್ನು ಹೊಂದಾಣಿಕೆ ಮಾಡಲು ಬಣ್ಣ ತಿದ್ದುಪಡಿಯು ಅವಕಾಶ ನೀಡುತ್ತದೆ"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ಮೂಲಕ ಅತಿಕ್ರಮಿಸುತ್ತದೆ"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ಸಮಯ ಬಾಕಿ ಉಳಿದಿದೆ"</string> @@ -516,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"ನೀವು ಆಫ್ ಮಾಡುವವರೆಗೆ"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"ಇದೀಗ"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"ಫೋನ್ ಸ್ಪೀಕರ್"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ಕನೆಕ್ಟ್ ಮಾಡುವಾಗ ಸಮಸ್ಯೆ ಎದುರಾಗಿದೆ ಸಾಧನವನ್ನು ಆಫ್ ಮಾಡಿ ಹಾಗೂ ನಂತರ ಪುನಃ ಆನ್ ಮಾಡಿ"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ವೈರ್ ಹೊಂದಿರುವ ಆಡಿಯೋ ಸಾಧನ"</string> <string name="help_label" msgid="3528360748637781274">"ಸಹಾಯ ಮತ್ತು ಪ್ರತಿಕ್ರಿಯೆ"</string> diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml index cd3b8b842c66..c9960c4086be 100644 --- a/packages/SettingsLib/res/values-ko/strings.xml +++ b/packages/SettingsLib/res/values-ko/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"적색약(적녹)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"청색약(청황)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"색상 보정"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"색상 보정을 사용하면 기기에 표시되는 색상을 조절할 수 있습니다."</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"기기에 색상이 표시되는 방식을 조정합니다. 색상을 더 정확하게 보고 싶거나 집중을 위해 일부 색상을 제거할 때 유용합니다."</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> 우선 적용됨"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>, <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"남은 시간 약 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,6 +515,7 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"사용 중지할 때까지"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"조금 전"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"휴대전화 스피커"</string> + <string name="media_transfer_this_phone" msgid="7194341457812151531">"이 휴대전화"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"연결 중에 문제가 발생했습니다. 기기를 껐다가 다시 켜 보세요."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"유선 오디오 기기"</string> <string name="help_label" msgid="3528360748637781274">"고객센터"</string> diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml index 1990353f80b8..4ca656798df8 100644 --- a/packages/SettingsLib/res/values-ky/strings.xml +++ b/packages/SettingsLib/res/values-ky/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалия (кызыл-жашыл)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалия (көк-сары)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Түсүн тууралоо"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Түстөрдү тууралоо менен, түзмөгүңүздүн экранынын түстөрүн өзгөртө аласыз"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> менен алмаштырылган"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Болжол менен <xliff:g id="TIME_REMAINING">%1$s</xliff:g> калды"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Бул функция өчүрүлгөнгө чейин"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Жаңы эле"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Телефондун динамиги"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Туташууда маселе келип чыкты. Түзмөктү өчүрүп, кайра күйгүзүп көрүңүз"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Зымдуу аудио түзмөк"</string> <string name="help_label" msgid="3528360748637781274">"Жардам/Пикир билдирүү"</string> diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml index 4997ea1a82c6..176c80fbc1d6 100644 --- a/packages/SettingsLib/res/values-lo/strings.xml +++ b/packages/SettingsLib/res/values-lo/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (ສີແດງ-ສີຂຽວ)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (ສີຟ້າ-ສີເຫຼືອງ)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ການປັບແຕ່ງສີ"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"ການແກ້ໄຂສີຈະເຮັດໃຫ້ທ່ານສາມາດປັບແຕ່ງການສະແດງຜົນຂອງສີຢູ່ອຸປະກອນຂອງທ່ານໄດ້"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"ຖືກແທນໂດຍ <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"ເຫຼືອອີກປະມານ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"ຈົນກວ່າທ່ານຈະປິດ"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"ຕອນນີ້"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"ລຳໂພງໂທລະສັບ"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ເກີດບັນຫາໃນການເຊື່ອມຕໍ່. ປິດອຸປະກອນແລ້ວເປີດກັບຄືນມາໃໝ່"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ອຸປະກອນສຽງແບບມີສາຍ"</string> <string name="help_label" msgid="3528360748637781274">"ຊ່ວຍເຫຼືອ ແລະ ຕິຊົມ"</string> diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml index ec3cb0d94a51..b0ab8f449c67 100644 --- a/packages/SettingsLib/res/values-lt/strings.xml +++ b/packages/SettingsLib/res/values-lt/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalija (raudona, žalia)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalija (mėlyna, geltona)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Spalvų taisymas"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Spalvų taisymo funkcija padės koreguoti, kaip spalvos rodomos jūsų įrenginyje"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Nepaisyta naudojant nuostatą „<xliff:g id="TITLE">%1$s</xliff:g>“"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Liko maždaug <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -517,6 +518,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Kol išjungsite"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Ką tik"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Telefono garsiakalbis"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Prisijungiant kilo problema. Išjunkite įrenginį ir vėl jį įjunkite"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Laidinis garso įrenginys"</string> <string name="help_label" msgid="3528360748637781274">"Pagalba ir atsiliepimai"</string> diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml index ff9f0a1649f9..2633f13e4e34 100644 --- a/packages/SettingsLib/res/values-lv/strings.xml +++ b/packages/SettingsLib/res/values-lv/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomālija (sarkans/zaļš)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomālija (zils/dzeltens)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Krāsu korekcija"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Izmantojot krāsu korekciju, varat koriģēt krāsu attēlojumu savā ierīcē"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Jaunā preference: <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> — <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Aptuvenais atlikušais laiks: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -516,6 +517,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Līdz brīdim, kad izslēgsiet"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Tikko"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Tālruņa skaļrunis"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Radās problēma ar savienojuma izveidi. Izslēdziet un atkal ieslēdziet ierīci."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Vadu audioierīce"</string> <string name="help_label" msgid="3528360748637781274">"Palīdzība un atsauksmes"</string> diff --git a/packages/SettingsLib/res/values-mk/arrays.xml b/packages/SettingsLib/res/values-mk/arrays.xml index d1c74e64827f..03128c17c784 100644 --- a/packages/SettingsLib/res/values-mk/arrays.xml +++ b/packages/SettingsLib/res/values-mk/arrays.xml @@ -138,9 +138,9 @@ <item msgid="1333279807604675720">"Стерео"</item> </string-array> <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles"> - <item msgid="1241278021345116816">"Оптимизирано за квалитет на аудиото (990 кб/с - 909 кб/с)"</item> + <item msgid="1241278021345116816">"Оптимизирано за квалитет на аудиото (990 kbps - 909 kbps)"</item> <item msgid="3523665555859696539">"Балансиран квалитет на звукот и врската (660 kb/s/606 kb/s)"</item> - <item msgid="886408010459747589">"Оптимизирано за квалитет на врската (330 кб/с - 303 кб/с)"</item> + <item msgid="886408010459747589">"Оптимизирано за квалитет на врската (330 kbps - 303 kbps)"</item> <item msgid="3808414041654351577">"Најдобар напор (приспособлива стапка на битови)"</item> </string-array> <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries"> diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml index 507f65c641b2..e4173d0dcac9 100644 --- a/packages/SettingsLib/res/values-mk/strings.xml +++ b/packages/SettingsLib/res/values-mk/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалија (слепило за црвена и зелена)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалија (слепило за сина и жолта)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Корекција на бои"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Корекцијата на боите ви овозможува да го приспособите начинот на прикажување на боите на вашиот уред"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Прескокнато според <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Уште околу <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Додека не го исклучите"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Неодамнешни"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Телефонски звучник"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Проблем со поврзување. Исклучете го уредот и повторно вклучете го"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Жичен аудиоуред"</string> <string name="help_label" msgid="3528360748637781274">"Помош и повратни информации"</string> diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml index 8a09801502e1..3cfe47954a33 100644 --- a/packages/SettingsLib/res/values-ml/strings.xml +++ b/packages/SettingsLib/res/values-ml/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"പ്രോട്ടാനോമലി (ചുവപ്പ്-പച്ച)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ട്രിട്ടാനോമലി (നീല-മഞ്ഞ)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"നിറം ക്രമീകരിക്കൽ"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"നിങ്ങളുടെ ഉപകരണത്തിൽ നിറങ്ങൾ എങ്ങനെ പ്രദർശിപ്പിക്കുന്നു എന്നത് ക്രമീകരിക്കാൻ \'നിറം ക്രമീകരിക്കൽ\' അനുവദിക്കുന്നു"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ഉപയോഗിച്ച് അസാധുവാക്കി"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"ഏതാണ്ട് <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ശേഷിക്കുന്നു"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"നിങ്ങൾ ഓഫാക്കുന്നത് വരെ"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"ഇപ്പോൾ"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"ഫോൺ സ്പീക്കർ"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"കണക്റ്റ് ചെയ്യുന്നതിൽ പ്രശ്നമുണ്ടായി. ഉപകരണം ഓഫാക്കി വീണ്ടും ഓണാക്കുക"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"വയർ മുഖേന ബന്ധിപ്പിച്ച ഓഡിയോ ഉപകരണം"</string> <string name="help_label" msgid="3528360748637781274">"സഹായവും ഫീഡ്ബാക്കും"</string> diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml index 27ca8f59739d..7c833f7a3a52 100644 --- a/packages/SettingsLib/res/values-mn/strings.xml +++ b/packages/SettingsLib/res/values-mn/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномаль (улаан-ногоон)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомаль (цэнхэр-шар)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Өнгө тохируулах"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Өнгө тохируулга нь танд төхөөрөмж дээрээ өнгө хэрхэн харагдахыг тохируулах боломжийг олгодог"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Таны төхөөрөмж дээр өнгийг хэрхэн үзүүлэхийг тохируулна уу. Энэ нь таныг дараахыг хийхийг хүссэн үед хэрэгтэй байж болно:<br/><br/> <ol> <li> Өнгийг илүү оновчтой харах</li> <li> Төвлөрөхийн тулд өнгийг хасах</li> </ol>"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Давхарласан <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Ойролцоогоор <xliff:g id="TIME_REMAINING">%1$s</xliff:g> үлдсэн"</string> @@ -515,6 +515,7 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Таныг унтраах хүртэл"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Дөнгөж сая"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Утасны чанга яригч"</string> + <string name="media_transfer_this_phone" msgid="7194341457812151531">"Энэ утас"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Холбогдоход асуудал гарлаа. Төхөөрөмжийг унтраагаад дахин асаана уу"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Утастай аудио төхөөрөмж"</string> <string name="help_label" msgid="3528360748637781274">"Тусламж, санал хүсэлт"</string> diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml index b6c546072473..f8d9089d88e3 100644 --- a/packages/SettingsLib/res/values-mr/strings.xml +++ b/packages/SettingsLib/res/values-mr/strings.xml @@ -404,8 +404,7 @@ <string name="transcode_user_control" msgid="6176368544817731314">"ट्रान्सकोडिंग डीफॉल्ट ओव्हरराइड करा"</string> <string name="transcode_enable_all" msgid="2411165920039166710">"ट्रान्सकोडिंग सुरू करा"</string> <string name="transcode_default" msgid="3784803084573509491">"असे गृहीत धरा की, ॲप्स आधुनिक फॉरमॅटना सपोर्ट करतात"</string> - <!-- no translation found for transcode_notification (5560515979793436168) --> - <skip /> + <string name="transcode_notification" msgid="5560515979793436168">"ट्रान्सकोडिंग सूचना दाखवा"</string> <string name="runningservices_settings_title" msgid="6460099290493086515">"सुरू सेवा"</string> <string name="runningservices_settings_summary" msgid="1046080643262665743">"सध्या सुरू असलेल्या सेवा पहा आणि नियंत्रित करा"</string> <string name="select_webview_provider_title" msgid="3917815648099445503">"वेबदृश्य अंमलबजावणी"</string> @@ -425,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"क्षीण रक्तवर्णांधता (लाल-हिरवा)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"रंग दृष्टी कमतरता (निळा-पिवळा)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"रंग सुधारणा"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"कलर इन्व्हर्जन तुमच्या डिव्हाइसवर रंग कसे प्रदर्शित केले जातात ते अॅडजस्ट करू देते"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> द्वारे अधिलिखित"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"अंदाजे <xliff:g id="TIME_REMAINING">%1$s</xliff:g> बाकी आहे"</string> @@ -516,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"तुम्ही बंद करेपर्यंत"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"आत्ताच"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"फोनचा स्पीकर"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"कनेक्ट करण्यात समस्या आली. डिव्हाइस बंद करा आणि नंतर सुरू करा"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"वायर असलेले ऑडिओ डिव्हाइस"</string> <string name="help_label" msgid="3528360748637781274">"मदत आणि फीडबॅक"</string> diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml index 53a4398d1b90..4df385597068 100644 --- a/packages/SettingsLib/res/values-ms/strings.xml +++ b/packages/SettingsLib/res/values-ms/strings.xml @@ -68,7 +68,7 @@ <string name="bluetooth_disconnecting" msgid="7638892134401574338">"Memutuskan sambungan..."</string> <string name="bluetooth_connecting" msgid="5871702668260192755">"Menyambung..."</string> <string name="bluetooth_connected" msgid="8065345572198502293">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> disambungkan"</string> - <string name="bluetooth_pairing" msgid="4269046942588193600">"Memasangkan..."</string> + <string name="bluetooth_pairing" msgid="4269046942588193600">"Menggandingkan..."</string> <string name="bluetooth_connected_no_headset" msgid="2224101138659967604">"Disambungkan (tiada telefon)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string> <string name="bluetooth_connected_no_a2dp" msgid="8566874395813947092">"Disambungkan (tiada media)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string> <string name="bluetooth_connected_no_map" msgid="3381860077002724689">"Disambungkan (tiada akses mesej)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string> @@ -113,7 +113,7 @@ <string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Gunakan untuk pemindahan fail"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Gunakan untuk input"</string> <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Gunakan untuk Alat Bantu Dengar"</string> - <string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Jadikan pasangan"</string> + <string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Gandingkan"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"JADIKAN PASANGAN"</string> <string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Batal"</string> <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"Berpasangan memberi anda akses kepada kenalan dan sejarah panggilan apabila disambungkan."</string> @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomali (merah-hijau)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomali (biru-kuning)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Pembetulan warna"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Pembetulan warna membolehkan anda melaraskan cara warna dipaparkan pada peranti anda"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Laraskan cara warna dipaparkan pada peranti anda. Ini boleh membantu apabila anda ingin:<br/><br/> <ol> <li> Lihat warna dengan lebih tepat</li> <li> Alih keluar warna untuk membantu anda fokus</li> </ol>"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Diatasi oleh <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Kira-kira <xliff:g id="TIME_REMAINING">%1$s</xliff:g> lagi"</string> @@ -515,6 +515,7 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Sehingga anda matikan"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Sebentar tadi"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Pembesar suara telefon"</string> + <string name="media_transfer_this_phone" msgid="7194341457812151531">"Telefon ini"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Masalah penyambungan. Matikan & hidupkan kembali peranti"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Peranti audio berwayar"</string> <string name="help_label" msgid="3528360748637781274">"Bantuan & maklum balas"</string> diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml index 0fef5abf782b..f10e5393877f 100644 --- a/packages/SettingsLib/res/values-my/strings.xml +++ b/packages/SettingsLib/res/values-my/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (အနီ-အစိမ်း)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (အပြာ-အဝါ)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"အရောင်ပြင်ဆင်မှု"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"အရောင်အမှန်ပြင်ခြင်းက သင့်စက်ပေါ်တွင် အရောင်များပြနေပုံကို ချိန်ညှိခွင့်ပြုသည်"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> မှ ကျော်၍ လုပ်ထားသည်။"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ခန့် ကျန်သည်"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"သင်ပိတ်လိုက်သည် အထိ"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"ယခုလေးတင်"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"ဖုန်းစပီကာ"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ချိတ်ဆက်ရာတွင် ပြဿနာရှိပါသည်။ စက်ကိုပိတ်ပြီး ပြန်ဖွင့်ပါ"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ကြိုးတပ် အသံစက်ပစ္စည်း"</string> <string name="help_label" msgid="3528360748637781274">"အကူအညီနှင့် အကြံပြုချက်"</string> diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml index 0ca8d51645e8..9fb68d0a30ef 100644 --- a/packages/SettingsLib/res/values-nb/strings.xml +++ b/packages/SettingsLib/res/values-nb/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomali (rød-grønn)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomali (blå-gul)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Fargekorrigering"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Med fargekorrigering kan du justere hvordan farger vises på enheten din"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overstyres av <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Omtrent <xliff:g id="TIME_REMAINING">%1$s</xliff:g> gjenstår"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Til du slår av"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Nå nettopp"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Telefonhøyttaler"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Tilkoblingsproblemer. Slå enheten av og på igjen"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Lydenhet med kabel"</string> <string name="help_label" msgid="3528360748637781274">"Hjelp og tilbakemelding"</string> diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml index 75b4537f6a8f..4c847cfaa2b4 100644 --- a/packages/SettingsLib/res/values-ne/strings.xml +++ b/packages/SettingsLib/res/values-ne/strings.xml @@ -404,8 +404,7 @@ <string name="transcode_user_control" msgid="6176368544817731314">"ट्रान्सकोडिङसम्बन्धी पूर्वनिर्धारित सेटिङ परिवर्तन गर्नुहोस्"</string> <string name="transcode_enable_all" msgid="2411165920039166710">"ट्रान्सकोडिङ अन गर्नुहोस्"</string> <string name="transcode_default" msgid="3784803084573509491">"एपहरूमा आधुनिक फर्म्याट प्रयोग गर्न मिल्छ भनी मान्नुहोस्"</string> - <!-- no translation found for transcode_notification (5560515979793436168) --> - <skip /> + <string name="transcode_notification" msgid="5560515979793436168">"ट्रान्सकोडिङसम्बन्धी सूचना देखाइयोस्"</string> <string name="runningservices_settings_title" msgid="6460099290493086515">"चलिरहेका सेवाहरू"</string> <string name="runningservices_settings_summary" msgid="1046080643262665743">"हाल चालु भइरहेका सेवाहरू हेर्नुहोस् र नियन्त्रण गर्नुहोस्"</string> <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView कार्यान्वयन"</string> @@ -425,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"प्रोटानेमली (रातो, हरियो)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ट्रिटानोमेली (निलो-पंहेलो)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"रङ्ग सुधार"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"रंङ सच्याउने सुविधाले तपाईंलाई आफ्नो यन्त्रमा रंङहरू कसरी देखाउने भन्ने कुरा निर्धारण गर्न दिन्छ"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> द्वारा अधिरोहित"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"लगभग <xliff:g id="TIME_REMAINING">%1$s</xliff:g> बाँकी छ"</string> @@ -516,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"तपाईंले निष्क्रिय नपार्दासम्म"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"अहिले भर्खरै"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"फोनको स्पिकर"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"जोड्ने क्रममा समस्या भयो। यन्त्रलाई निष्क्रिय पारेर फेरि सक्रिय गर्नुहोस्"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"तारयुक्त अडियो यन्त्र"</string> <string name="help_label" msgid="3528360748637781274">"मद्दत र प्रतिक्रिया"</string> diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml index 71d6acc6a22b..4cb755ba468c 100644 --- a/packages/SettingsLib/res/values-nl/strings.xml +++ b/packages/SettingsLib/res/values-nl/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (rood-groen)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (blauw-geel)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Kleurcorrectie"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Met kleurcorrectie kun je aanpassen hoe kleuren op je apparaat worden weergegeven"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Aanpassen hoe kleuren worden getoond op je apparaat. In de volgende gevallen kan dit handig zijn:<br/><br/> <ol> <li> Je wilt kleuren duidelijker zien.</li> <li> Je wilt kleuren verwijderen zodat je je beter kunt focussen.</li> </ol>"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overschreven door <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Nog ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,6 +515,7 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Totdat je uitschakelt"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Zojuist"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Telefoonspeaker"</string> + <string name="media_transfer_this_phone" msgid="7194341457812151531">"Deze telefoon"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Probleem bij verbinding maken. Schakel het apparaat uit en weer in."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Bedraad audioapparaat"</string> <string name="help_label" msgid="3528360748637781274">"Hulp en feedback"</string> diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml index 1d6e34f7af23..b7c93e55163c 100644 --- a/packages/SettingsLib/res/values-or/strings.xml +++ b/packages/SettingsLib/res/values-or/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"ପ୍ରୋଟାନୋମାଲି (ଲାଲ୍-ସବୁଜ)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (ନୀଳ-ହଳଦିଆ)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ରଙ୍ଗ ସଂଶୋଧନ"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"ଆପଣଙ୍କ ଡିଭାଇସରେ ରଙ୍ଗଗୁଡ଼ିକ କିପରି ଡିସପ୍ଲେ ହୁଏ, ତାହା ଆଡଜଷ୍ଟ କରିବାକୁ \'ରଙ୍ଗ ସଂଶୋଧନ’ ଆପଣଙ୍କୁ ଅନୁମତି ଦିଏ"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ଦ୍ୱାରା ଓଭର୍ରାଇଡ୍ କରାଯାଇଛି"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"ପାଖାପାଖି <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ବଳକା ଅଛି"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"ଆପଣ ବନ୍ଦ ନକରିବା ପର୍ଯ୍ୟନ୍ତ"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"ଏହିକ୍ଷଣି"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"ଫୋନ୍ ସ୍ପିକର୍"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ସଂଯୋଗ କରିବାରେ ସମସ୍ୟା ହେଉଛି। ଡିଭାଇସ୍ ବନ୍ଦ କରି ପୁଣି ଚାଲୁ କରନ୍ତୁ"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ତାରଯୁକ୍ତ ଅଡିଓ ଡିଭାଇସ୍"</string> <string name="help_label" msgid="3528360748637781274">"ସାହାଯ୍ୟ ଓ ମତାମତ"</string> diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml index 9d91aae0a982..896a10034383 100644 --- a/packages/SettingsLib/res/values-pa/strings.xml +++ b/packages/SettingsLib/res/values-pa/strings.xml @@ -404,8 +404,7 @@ <string name="transcode_user_control" msgid="6176368544817731314">"ਟ੍ਰਾਂਸਕੋਡਿੰਗ ਦੀਆਂ ਪੂਰਵ-ਨਿਰਧਾਰਤ ਸੈਟਿੰਗਾਂ ਨੂੰ ਓਵਰਰਾਈਡ ਕਰੋ"</string> <string name="transcode_enable_all" msgid="2411165920039166710">"ਟ੍ਰਾਂਸਕੋਡਿੰਗ ਚਾਲੂ ਕਰੋ"</string> <string name="transcode_default" msgid="3784803084573509491">"ਮੰਨ ਲਓ ਕਿ ਐਪਾਂ ਆਧੁਨਿਕ ਫਾਰਮੈਟਾਂ ਦਾ ਸਮਰਥਨ ਕਰਦੀਆਂ ਹਨ"</string> - <!-- no translation found for transcode_notification (5560515979793436168) --> - <skip /> + <string name="transcode_notification" msgid="5560515979793436168">"ਟ੍ਰਾਂਸਕੋਡਿੰਗ ਸੂਚਨਾਵਾਂ ਦਿਖਾਓ"</string> <string name="runningservices_settings_title" msgid="6460099290493086515">"ਚੱਲ ਰਹੀਆਂ ਸੇਵਾਵਾਂ"</string> <string name="runningservices_settings_summary" msgid="1046080643262665743">"ਇਸ ਵੇਲੇ ਚੱਲ ਰਹੀਆਂ ਸੇਵਾਵਾਂ ਦੇਖੋ ਅਤੇ ਇਹਨਾਂ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ"</string> <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ਅਮਲ"</string> @@ -425,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (ਲਾਲ-ਹਰਾ)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (ਨੀਲਾ-ਪੀਲਾ)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ਰੰਗ ਸੁਧਾਈ"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"ਰੰਗ ਸੁਧਾਈ ਨਾਲ ਤੁਹਾਨੂੰ ਆਪਣੇ ਡੀਵਾਈਸ \'ਤੇ ਰੰਗਾਂ ਦੇ ਪ੍ਰਦਰਸ਼ਿਤ ਹੋਣ ਨੂੰ ਵਿਵਸਥਿਤ ਕਰਨ ਦਿੱਤਾ ਜਾਂਦਾ ਹੈ"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ਦੁਆਰਾ ਓਵਰਰਾਈਡ ਕੀਤਾ"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"ਲਗਭਗ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ਬਾਕੀ"</string> @@ -516,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਬੰਦ ਨਹੀਂ ਕਰਦੇ"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"ਹੁਣੇ ਹੀ"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"ਫ਼ੋਨ ਦਾ ਸਪੀਕਰ"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ਕਨੈਕਟ ਕਰਨ ਵਿੱਚ ਸਮੱਸਿਆ ਆਈ। ਡੀਵਾਈਸ ਨੂੰ ਬੰਦ ਕਰਕੇ ਵਾਪਸ ਚਾਲੂ ਕਰੋ"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ਤਾਰ ਵਾਲਾ ਆਡੀਓ ਡੀਵਾਈਸ"</string> <string name="help_label" msgid="3528360748637781274">"ਮਦਦ ਅਤੇ ਵਿਚਾਰ"</string> diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml index f48b05f01ddc..663f3fc592da 100644 --- a/packages/SettingsLib/res/values-pl/strings.xml +++ b/packages/SettingsLib/res/values-pl/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (czerwony-zielony)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (niebieski-żółty)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korekcja kolorów"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Korekcja kolorów pozwala na dostosowanie sposobu wyświetlania kolorów na urządzeniu"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Nadpisana przez <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Jeszcze około <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -517,6 +518,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Dopóki nie wyłączysz"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Przed chwilą"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Głośnik telefonu"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem z połączeniem. Wyłącz i ponownie włącz urządzenie"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Przewodowe urządzenie audio"</string> <string name="help_label" msgid="3528360748637781274">"Pomoc i opinie"</string> diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml index b9c919129623..8eab928c7fb5 100644 --- a/packages/SettingsLib/res/values-pt-rBR/strings.xml +++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (vermelho-verde)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (azul-amarelo)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correção de cor"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"A correção de cor permite ajustar como as cores são exibidas no dispositivo"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Até você desativar"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Agora"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Alto-falante do smartphone"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ocorreu um problema na conexão. Desligue o dispositivo e ligue-o novamente"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de áudio com fio"</string> <string name="help_label" msgid="3528360748637781274">"Ajuda e feedback"</string> diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml index 57e38c078375..f28d70a71ce7 100644 --- a/packages/SettingsLib/res/values-pt-rPT/strings.xml +++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (vermelho-verde)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (azul-amarelo)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correção da cor"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"A correção da cor permite-lhe ajustar a forma como as cores são apresentadas no seu dispositivo."</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Resta(m) cerca de <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Até desativar"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Agora mesmo"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Altifalante do telemóvel"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problema ao ligar. Desligue e volte a ligar o dispositivo."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de áudio com fios"</string> <string name="help_label" msgid="3528360748637781274">"Ajuda e comentários"</string> diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml index b9c919129623..8eab928c7fb5 100644 --- a/packages/SettingsLib/res/values-pt/strings.xml +++ b/packages/SettingsLib/res/values-pt/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (vermelho-verde)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (azul-amarelo)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correção de cor"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"A correção de cor permite ajustar como as cores são exibidas no dispositivo"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Até você desativar"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Agora"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Alto-falante do smartphone"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ocorreu um problema na conexão. Desligue o dispositivo e ligue-o novamente"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de áudio com fio"</string> <string name="help_label" msgid="3528360748637781274">"Ajuda e feedback"</string> diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml index c2da73c5679c..0a4e46209939 100644 --- a/packages/SettingsLib/res/values-ro/strings.xml +++ b/packages/SettingsLib/res/values-ro/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (roșu-verde)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (albastru-galben)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Corecția culorii"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Folosind corecția culorii, puteți ajusta modul în care se afișează culorile pe dispozitiv"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Valoare înlocuită de <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Timp aproximativ rămas: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -516,6 +517,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Până când dezactivați"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Chiar acum"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Difuzorul telefonului"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problemă la conectare. Opriți și reporniți dispozitivul."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispozitiv audio cu fir"</string> <string name="help_label" msgid="3528360748637781274">"Ajutor și feedback"</string> diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml index efcce7556910..b030715da04f 100644 --- a/packages/SettingsLib/res/values-ru/strings.xml +++ b/packages/SettingsLib/res/values-ru/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалия (красный/зеленый)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалия (синий/желтый)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Коррекция цвета"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Коррекция цвета позволяет изменить настройки цветопередачи на экране устройства."</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Новая настройка: <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"Уровень заряда – <xliff:g id="PERCENTAGE">%1$s</xliff:g>. <xliff:g id="TIME_STRING">%2$s</xliff:g>."</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Заряда хватит примерно на <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -517,6 +518,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Пока вы не отключите"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Только что"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Встроенный динамик"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ошибка подключения. Выключите и снова включите устройство."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Проводное аудиоустройство"</string> <string name="help_label" msgid="3528360748637781274">"Справка/отзыв"</string> diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml index 590e0e4eded1..035a159d6e97 100644 --- a/packages/SettingsLib/res/values-si/strings.xml +++ b/packages/SettingsLib/res/values-si/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"වර්ණ දුර්වලතාවය (රතු-කොළ)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"වර්ණ අන්ධතාවය (නිල්-කහ)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"වර්ණ නිවැරදි කිරීම"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"වර්ණ නිවැරදි කිරීම ඔබට ඔබේ උපාංගයෙහි වර්ණ සංදර්ශනය වන ආකාරය සීරුමාරු කිරීමට ඉඩ දේ"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"ඔබගේ උපාංගයේ වර්ණ සංදර්ශනය වන ආකාරය සීරුමාරු කරන්න. මෙය ඔබට පහත දේවල් සිදු කිරීමට අවශ්ය විට ප්රයෝජනවත් විය හැකිය:<br/><br/> <ol> <li> වර්ණ වඩාත් නිවැරදිව බැලීම</li> <li> ඔබට අවධානය යොමු කිරීමට උදව් වීමට වර්ණ ඉවත් කිරීම</li> </ol>"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> මගින් ඉක්මවන ලදී"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ක් පමණ ඉතිරියි"</string> @@ -515,6 +515,7 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"ඔබ ක්රියාවිරහිත කරන තුරු"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"මේ දැන්"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"දුරකථන ස්පීකරය"</string> + <string name="media_transfer_this_phone" msgid="7194341457812151531">"මෙම දුරකථනය"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"සම්බන්ධ කිරීමේ ගැටලුවකි උපාංගය ක්රියාවිරහිත කර & ආපසු ක්රියාත්මක කරන්න"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"රැහැන්ගත කළ ඕඩියෝ උපාංගය"</string> <string name="help_label" msgid="3528360748637781274">"උදවු & ප්රතිපෝෂණ"</string> diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml index c817ed0e200c..d9d53515351f 100644 --- a/packages/SettingsLib/res/values-sk/strings.xml +++ b/packages/SettingsLib/res/values-sk/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomália (červená a zelená)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomália (modrá a žltá)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Úprava farieb"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Úprava farieb umožňuje nastaviť spôsob zobrazovania farieb vo vašom zariadení"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Prekonané predvoľbou <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Zostáva približne <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -517,6 +518,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Dokým funkciu nevypnete"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Teraz"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Reproduktor telefónu"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Pri pripájaní sa vyskytol problém. Zariadenie vypnite a znova zapnite."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Audio zariadenie s káblom"</string> <string name="help_label" msgid="3528360748637781274">"Pomocník a spätná väzba"</string> diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml index 464b235e90da..81b1b60ac7fd 100644 --- a/packages/SettingsLib/res/values-sl/strings.xml +++ b/packages/SettingsLib/res/values-sl/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalija (rdeča – zelena)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalija (modra – rumena)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Popravljanje barv"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Popravljanje barv vam omogoča prilagajanje prikaza barv v napravi"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Preglasila nastavitev: <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Še približno <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -517,6 +518,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Dokler ne izklopite"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Pravkar"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Zvočnik telefona"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Težava pri povezovanju. Napravo izklopite in znova vklopite."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žična zvočna naprava"</string> <string name="help_label" msgid="3528360748637781274">"Pomoč in povratne informacije"</string> diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml index a2a63e165a96..b71e51f35bb4 100644 --- a/packages/SettingsLib/res/values-sq/strings.xml +++ b/packages/SettingsLib/res/values-sq/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomali (e kuqe - e gjelbër)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomali (e kaltër - e verdhë)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korrigjimi i ngjyrës"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Korrigjimi i ngjyrave të lejon të rregullosh mënyrën se si shfaqen ngjyrat në pajisjen tënde"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Mbivendosur nga <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Rreth <xliff:g id="TIME_REMAINING">%1$s</xliff:g> të mbetura"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Deri sa ta çaktivizosh"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Pikërisht tani"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Altoparlanti i telefonit"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem me lidhjen. Fike dhe ndize përsëri pajisjen"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Pajisja audio me tel"</string> <string name="help_label" msgid="3528360748637781274">"Ndihma dhe komentet"</string> diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml index 2119303410e0..4f37180c7f7e 100644 --- a/packages/SettingsLib/res/values-sr/strings.xml +++ b/packages/SettingsLib/res/values-sr/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалија (црвено-зелено)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалија (плаво-жуто)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Корекција боја"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Корекција боја вам омогућава да прилагодите начин на који се боје приказују на уређају"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Прилагодите начин на који се боје приказују на уређају. То може да буде корисно када желите:<br/><br/> <ol> <li> да вам се боје тачније приказују</li> <li> да уклоните боје како бисте се фокусирали</li> </ol>"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Замењује га <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>–<xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Преостало је око <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -516,6 +516,7 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Док не искључите"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Управо"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Звучник телефона"</string> + <string name="media_transfer_this_phone" msgid="7194341457812151531">"Овај телефон"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Проблем при повезивању. Искључите уређај, па га поново укључите"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Жичани аудио уређај"</string> <string name="help_label" msgid="3528360748637781274">"Помоћ и повратне информације"</string> diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml index c7a21692fea6..2ec2ded3d34f 100644 --- a/packages/SettingsLib/res/values-sv/strings.xml +++ b/packages/SettingsLib/res/values-sv/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomali (rött-grönt)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomali (blått-gult)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Färgkorrigering"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Med färgkorrigering kan du ändra hur färger visas på enheten"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Har åsidosatts av <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Cirka <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kvar"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Tills du inaktiverar funktionen"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Nyss"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Telefonens högtalare"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Det gick inte att ansluta. Stäng av enheten och slå på den igen"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Ljudenhet med kabelanslutning"</string> <string name="help_label" msgid="3528360748637781274">"Hjälp och feedback"</string> diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml index 60014f437c4b..410a4aa0bddc 100644 --- a/packages/SettingsLib/res/values-sw/strings.xml +++ b/packages/SettingsLib/res/values-sw/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (nyekundu-kijani)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (samawati-manjano)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Usahihishaji wa rangi"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Urekebishaji rangi hukuruhusu ubadilishe jinsi rangi zinavyoonyeshwa kwenye kifaa chako"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Badilisha jinsi rangi zinavyoonekana kwenye kifaa chako. Hali hii inaweza kuwa muhimu unapotaka:<br/><br/> <ol> <li> Kuona rangi kwa usahihi zaidi</li> <li> Kuondoa rangi ili kukusaidia kuwa makini</li> </ol>"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Imetanguliwa na <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Zimesalia takribani <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,6 +515,7 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Hadi utakapoizima"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Sasa hivi"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Spika ya simu"</string> + <string name="media_transfer_this_phone" msgid="7194341457812151531">"Simu hii"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Kuna tatizo la kuunganisha kwenye Intaneti. Zima kisha uwashe kifaa"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Kifaa cha sauti kinachotumia waya"</string> <string name="help_label" msgid="3528360748637781274">"Usaidizi na maoni"</string> diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml index 82cce1275b10..14eb25d36a64 100644 --- a/packages/SettingsLib/res/values-ta/strings.xml +++ b/packages/SettingsLib/res/values-ta/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"நிறம் அடையாளங்காண முடியாமை (சிவப்பு-பச்சை)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"நிறம் அடையாளங்காண முடியாமை (நீலம்-மஞ்சள்)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"வண்ணத்திருத்தம்"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"கலர் கரெக்ஷனைப் பயன்படுத்தி உங்கள் சாதனத்தில் வண்ணங்கள் காண்பிக்கப்படும் விதத்தைச் சரிசெய்யலாம்"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> மூலம் மேலெழுதப்பட்டது"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"கிட்டத்தட்ட <xliff:g id="TIME_REMAINING">%1$s</xliff:g> மீதமுள்ளது"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"ஆஃப் செய்யும் வரை"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"சற்றுமுன்"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"மொபைல் ஸ்பீக்கர்"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"இணைப்பதில் சிக்கல். சாதனத்தை ஆஃப் செய்து மீண்டும் ஆன் செய்யவும்"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"வயருடன்கூடிய ஆடியோ சாதனம்"</string> <string name="help_label" msgid="3528360748637781274">"உதவியும் கருத்தும்"</string> diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml index 3b04eb402585..e652ab71bba3 100644 --- a/packages/SettingsLib/res/values-te/strings.xml +++ b/packages/SettingsLib/res/values-te/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"ప్రొటానోమలీ (ఎరుపు-ఆకుపచ్చ రంగు)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ట్రైటనోమలీ (నీలం-పసుపు రంగు)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"కలర్ సరిచేయడం"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"\'కలర్ సరిచేయడం\' అనే ఫీచర్ సాయంతో, మీ పరికరంలో రంగులు కనిపించే పద్ధతిని మీరు మార్చగలుగుతారు"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ద్వారా భర్తీ చేయబడింది"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> సమయం మిగిలి ఉంది"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"మీరు ఆఫ్ చేసే వరకు"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"ఇప్పుడే"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"ఫోన్ స్పీకర్"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"కనెక్ట్ చేయడంలో సమస్య ఉంది. పరికరాన్ని ఆఫ్ చేసి, ఆపై తిరిగి ఆన్ చేయండి"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"వైర్ గల ఆడియో పరికరం"</string> <string name="help_label" msgid="3528360748637781274">"సహాయం & ఫీడ్బ్యాక్"</string> diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml index a9703213813e..4bd7b6ddd21e 100644 --- a/packages/SettingsLib/res/values-th/strings.xml +++ b/packages/SettingsLib/res/values-th/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"ตาบอดจางสีแดง (สีแดง/เขียว)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ตาบอดจางสีน้ำเงิน (สีน้ำเงิน/เหลือง)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"การแก้สี"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"การแก้สีช่วยให้คุณปรับการแสดงสีในอุปกรณ์ได้"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"ปรับวิธีแสดงสีในอุปกรณ์ การดำเนินการนี้จะเป็นประโยชน์เมื่อคุณต้องการดังนี้<br/><br/> <ol> <li> เห็นสีได้ถูกต้องยิ่งขึ้น</li> <li> นำสีออกเพื่อช่วยให้เห็นชัดเจนยิ่งขึ้น</li> </ol>"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"แทนที่โดย <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"เหลืออีกประมาณ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,6 +515,7 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"จนกว่าคุณจะปิด"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"เมื่อสักครู่"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"ลำโพงโทรศัพท์"</string> + <string name="media_transfer_this_phone" msgid="7194341457812151531">"โทรศัพท์เครื่องนี้"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"เกิดปัญหาในการเชื่อมต่อ ปิดอุปกรณ์แล้วเปิดใหม่อีกครั้ง"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"อุปกรณ์เสียงแบบมีสาย"</string> <string name="help_label" msgid="3528360748637781274">"ความช่วยเหลือและความคิดเห็น"</string> diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml index bedd00511118..e56e5b9b6077 100644 --- a/packages/SettingsLib/res/values-tl/strings.xml +++ b/packages/SettingsLib/res/values-tl/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (pula-berde)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (asul-dilaw)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Pagtatama ng kulay"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Nagbibigay-daan sa iyo ang pagtatama ng kulay na maisaayos kung paano ipinapakita ang mga kulay sa iyong device"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Isaayos kung paano ipinapakita ang mga kulay sa iyong device. Makakatulong ito kapag gusto mong:<br/><br/> <ol> <li> Makakita ng mas tumpak na mga kulay</li> <li> Mag-alis ng mga kulay para matulungan kang mag-focus</li> </ol>"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Na-override ng <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Humigit-kumulang <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ang natitira"</string> @@ -515,6 +515,7 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Hanggang sa i-off mo"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Ngayon lang"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Speaker ng telepono"</string> + <string name="media_transfer_this_phone" msgid="7194341457812151531">"Ang teleponong ito"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Nagkaproblema sa pagkonekta. I-off at pagkatapos ay i-on ang device"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired na audio device"</string> <string name="help_label" msgid="3528360748637781274">"Tulong at feedback"</string> diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml index 2b2b44e0f9dc..5fbf5d41e40b 100644 --- a/packages/SettingsLib/res/values-tr/strings.xml +++ b/packages/SettingsLib/res/values-tr/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomali (kırmızı-yeşil)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomali (mavi-sarı)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Renk düzeltme"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Renk düzeltme, renklerin cihazınızda nasıl görüntüleneceğini düzenlemenize olanak sağlar."</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> tarafından geçersiz kılındı"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Yaklaşık <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kaldı"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Siz kapatana kadar"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Az önce"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Telefon hoparlörü"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Bağlanırken sorun oluştu. Cihazı kapatıp tekrar açın"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Kablolu ses cihazı"</string> <string name="help_label" msgid="3528360748637781274">"Yardım ve geri bildirim"</string> diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml index 9c5e2aa858aa..4511a4bc9ab5 100644 --- a/packages/SettingsLib/res/values-uk/strings.xml +++ b/packages/SettingsLib/res/values-uk/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалія (червоний – зелений)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалія (синій – жовтий)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Корекція кольору"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Корекція кольору дає змогу регулювати відтінки зображення на екрані пристрою"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Замінено на <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Залишилося приблизно <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -517,6 +518,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Доки не вимкнути"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Щойно"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Динамік телефона"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Не вдається підключитися. Перезавантажте пристрій."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Дротовий аудіопристрій"</string> <string name="help_label" msgid="3528360748637781274">"Довідка й відгуки"</string> diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml index ee06623240de..e61d281a025f 100644 --- a/packages/SettingsLib/res/values-ur/strings.xml +++ b/packages/SettingsLib/res/values-ur/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (سرخ سبز)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (نیلا پیلا)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"رنگ کی اصلاح"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"رنگ کی اصلاح آپ کو یہ ایڈجسٹ کرنے کی سہولت دیتی ہے کہ آپ کے آلے پر رنگ کیسے ڈسپلے کئے جاتے ہیں"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> کے ذریعہ منسوخ کردیا گیا"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"تقریباً <xliff:g id="TIME_REMAINING">%1$s</xliff:g> باقی ہے"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"یہاں تک کہ آپ آف کر دیں"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"ابھی ابھی"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"فون اسپیکر"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"منسلک کرنے میں مسئلہ پیش آ گیا۔ آلہ کو آف اور بیک آن کریں"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"وائرڈ آڈیو آلہ"</string> <string name="help_label" msgid="3528360748637781274">"مدد اور تاثرات"</string> diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml index 29c0f91c4e60..0730c6cc1b50 100644 --- a/packages/SettingsLib/res/values-uz/strings.xml +++ b/packages/SettingsLib/res/values-uz/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaliya (qizil/yashil)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaliya (ko‘k/sariq)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Rangni tuzatish"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Ranglarni tuzatish orqali qurilmangizda ranglar qanday chiqishini tuzatish mumkin"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Qurilmadagi ranglar qanday chiqishini moslash Bu quyidagi amallarni bajarishga yordam beradi:<br/><br/> <ol> <li> Ranglarni yanada aniq koʻrish</li> <li> Diqqatni jamlash uchun ranglarni olib tashlash</li> </ol>"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> bilan almashtirildi"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Taxminan <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qoldi"</string> @@ -515,6 +515,7 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Rejimdan chiqilgunicha"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Hozir"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Telefon karnayi"</string> + <string name="media_transfer_this_phone" msgid="7194341457812151531">"Shu telefon"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ulanishda muammo yuz berdi. Qurilmani oʻchiring va yoqing"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Simli audio qurilma"</string> <string name="help_label" msgid="3528360748637781274">"Yordam/fikr-mulohaza"</string> diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml index 39beecd0a87a..148ed89dc6dd 100644 --- a/packages/SettingsLib/res/values-vi/strings.xml +++ b/packages/SettingsLib/res/values-vi/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Mù màu đỏ không hoàn toàn (đỏ-xanh lục)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Mù màu (xanh lam-vàng)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Chỉnh màu"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Với chế độ chỉnh màu, bạn có thể điều chỉnh cách các màu hiển thị trên thiết bị"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Điều chỉnh cách các màu hiển thị trên thiết bị. Tùy chọn này có thể hữu ích khi bạn muốn:<br/><br/> <ol> <li> Xem các màu chính xác hơn</li> <li> Loại bỏ các màu để giúp bạn tập trung</li> </ol>"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Bị ghi đè bởi <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Còn khoảng <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,6 +515,7 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Cho đến khi bạn tắt"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Vừa xong"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Loa điện thoại"</string> + <string name="media_transfer_this_phone" msgid="7194341457812151531">"Điện thoại này"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Sự cố kết nối. Hãy tắt thiết bị rồi bật lại"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Thiết bị âm thanh có dây"</string> <string name="help_label" msgid="3528360748637781274">"Trợ giúp và phản hồi"</string> diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml index 010a4dc9ea6c..7d1bde3d8c5c 100644 --- a/packages/SettingsLib/res/values-zh-rCN/strings.xml +++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"红色弱视(红绿不分)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"蓝色弱视(蓝黄不分)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"色彩校正"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"借助色彩校正功能,您可以调整设备上的颜色显示方式"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"已被“<xliff:g id="TITLE">%1$s</xliff:g>”覆盖"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"大约还可使用 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"直到您将其关闭"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"刚刚"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"手机扬声器"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"连接时遇到问题。请关闭并重新开启设备"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有线音频设备"</string> <string name="help_label" msgid="3528360748637781274">"帮助和反馈"</string> diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml index 1e06a91859e2..06b5cd0dfbaa 100644 --- a/packages/SettingsLib/res/values-zh-rHK/strings.xml +++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"紅色弱視 (紅綠)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"藍色弱視 (藍黃)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"色彩校正"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"色彩校正功能讓您調整裝置顯示的顏色"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"調整裝置顯示顏色的方式。這項設定適用於以下情況:<br/><br/> <ol> <li> 想讓裝置更準確地顯示顏色</li> <li> 移除顏色以提高專注力</li> </ol>"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"已由「<xliff:g id="TITLE">%1$s</xliff:g>」覆寫"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"還有大約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,6 +515,7 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"直至您關閉為止"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"剛剛"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"手機喇叭"</string> + <string name="media_transfer_this_phone" msgid="7194341457812151531">"這支手機"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"無法連接,請關閉裝置然後重新開機"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有線音響裝置"</string> <string name="help_label" msgid="3528360748637781274">"說明與意見反映"</string> diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml index 2c077e7991be..dcfc59934dd8 100644 --- a/packages/SettingsLib/res/values-zh-rTW/strings.xml +++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"紅色弱視 (紅-綠)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"藍色弱視 (藍-黃)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"色彩校正"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"色彩校正可讓你調整裝置上顯示的顏色"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"調整裝置顯示顏色的方式。這項設定適用於以下情況:<br/><br/> <ol> <li> 想讓裝置更準確地顯示顏色</li> <li> 移除顏色以提高專注力</li> </ol>"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"已改為<xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"還能使用約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,6 +515,7 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"直到你關閉為止"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"剛剛"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"手機喇叭"</string> + <string name="media_transfer_this_phone" msgid="7194341457812151531">"這支手機"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"無法連線,請關閉裝置後再重新開啟"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有線音訊裝置"</string> <string name="help_label" msgid="3528360748637781274">"說明與意見回饋"</string> diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml index 87cf75b0beaf..2297cbe77fac 100644 --- a/packages/SettingsLib/res/values-zu/strings.xml +++ b/packages/SettingsLib/res/values-zu/strings.xml @@ -424,7 +424,8 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"I-Protanomaly (bomvu-luhlaza)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"I-Tritanomaly (luhlaza okwesibhakabhaka-phuzi)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Ukulungiswa kombala"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Ukulungisa umbala kukuvumela ukuthi ulungise indlela imibala eboniswa ngayo kudivayisi yakho"</string> + <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> + <skip /> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Igitshezwe ngaphezulu yi-<xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Cishe u-<xliff:g id="TIME_REMAINING">%1$s</xliff:g> osele"</string> @@ -515,6 +516,8 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Uze uvale isikrini"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Khona manje"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Isipikha sefoni"</string> + <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> + <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Inkinga yokuxhumeka. Vala idivayisi futhi uphinde uyivule"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Idivayisi yomsindo enentambo"</string> <string name="help_label" msgid="3528360748637781274">"Usizo nempendulo"</string> diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index 96241194402a..efa9f3c16b48 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 --> diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java index ff70eda68a5d..9c0c80bff3df 100644 --- a/packages/SettingsLib/src/com/android/settingslib/Utils.java +++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java @@ -25,6 +25,7 @@ import android.location.LocationManager; import android.media.AudioManager; import android.net.ConnectivityManager; import android.net.NetworkCapabilities; +import android.net.TetheringManager; import android.net.vcn.VcnTransportInfo; import android.net.wifi.WifiInfo; import android.os.BatteryManager; @@ -90,10 +91,10 @@ public class Utils { * Return string resource that best describes combination of tethering * options available on this device. */ - public static int getTetheringLabel(ConnectivityManager cm) { - String[] usbRegexs = cm.getTetherableUsbRegexs(); - String[] wifiRegexs = cm.getTetherableWifiRegexs(); - String[] bluetoothRegexs = cm.getTetherableBluetoothRegexs(); + public static int getTetheringLabel(TetheringManager tm) { + String[] usbRegexs = tm.getTetherableUsbRegexs(); + String[] wifiRegexs = tm.getTetherableWifiRegexs(); + String[] bluetoothRegexs = tm.getTetherableBluetoothRegexs(); boolean usbAvailable = usbRegexs.length != 0; boolean wifiAvailable = wifiRegexs.length != 0; diff --git a/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java b/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java index 43717aba3abd..dfde3c7a2512 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.net.wifi.WifiManager.SubsystemRestartTrackingCallback; 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 @@ public class ConnectivitySubsystemsRecoveryManager { 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 @@ public class ConnectivitySubsystemsRecoveryManager { checkIfAllSubsystemsRestartsAreDone(); } } - }; + } public ConnectivitySubsystemsRecoveryManager(@NonNull Context context, @NonNull Handler handler) { @@ -201,12 +204,12 @@ public class ConnectivitySubsystemsRecoveryManager { } 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 0cd5e4ded168..1a08366734bc 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 @@ package com.android.settingslib.mobile; 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 @@ public class MobileStatusTracker { 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 @@ public class MobileStatusTracker { 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 @@ public class MobileStatusTracker { /* updateTelephony= */false, new MobileStatus(mMobileStatus))); } - public PhoneStateListener getPhoneStateListener() { - return mPhoneStateListener; + public MobileTelephonyCallback getTelephonyCallback() { + return mTelephonyCallback; } /** @@ -77,9 +77,9 @@ public class MobileStatusTracker { */ 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 @@ public class MobileStatusTracker { || 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/net/UidDetailProvider.java b/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java index dad82ee61e08..02326ea85ff6 100644 --- a/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java +++ b/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java @@ -26,7 +26,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.UserInfo; import android.content.res.Resources; import android.graphics.drawable.Drawable; -import android.net.ConnectivityManager; +import android.net.TetheringManager; import android.net.TrafficStats; import android.os.Process; import android.os.RemoteException; @@ -123,9 +123,8 @@ public class UidDetailProvider { detail.icon = pm.getDefaultActivityIcon(); return detail; case TrafficStats.UID_TETHERING: - final ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService( - Context.CONNECTIVITY_SERVICE); - detail.label = res.getString(Utils.getTetheringLabel(cm)); + final TetheringManager tm = mContext.getSystemService(TetheringManager.class); + detail.label = res.getString(Utils.getTetheringLabel(tm)); detail.icon = pm.getDefaultActivityIcon(); return detail; case Process.OTA_UPDATE_UID: diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java index a81a05f1147a..303ee3c9fca2 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 class AccessPoint implements Comparable<AccessPoint> { 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/SettingsLib/tests/integ/src/com/android/settingslib/widget/UsageProgressBarPreferenceTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/widget/UsageProgressBarPreferenceTest.java index 1a8477d9b86e..fe76b06a9b61 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/widget/UsageProgressBarPreferenceTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/widget/UsageProgressBarPreferenceTest.java @@ -127,4 +127,20 @@ public class UsageProgressBarPreferenceTest { assertThat(customContent.getChildAt(0)).isEqualTo(imageView); assertThat(customContent.getVisibility()).isEqualTo(View.VISIBLE); } + + @Test + public void setCustomContent_setImageViewTwice_oneAndLatestChild() { + final ImageView imageViewLegacy = mock(ImageView.class); + final ImageView imageViewNew = mock(ImageView.class); + mUsageProgressBarPreference.setCustomContent(imageViewLegacy); + mUsageProgressBarPreference.setCustomContent(imageViewNew); + + mUsageProgressBarPreference.onBindViewHolder(mViewHolder); + + final FrameLayout customContent = + (FrameLayout) mViewHolder.findViewById(R.id.custom_content); + assertThat(customContent.getChildCount()).isEqualTo(1); + assertThat(customContent.getChildAt(0)).isEqualTo(imageViewNew); + assertThat(customContent.getVisibility()).isEqualTo(View.VISIBLE); + } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchBarTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchBarTest.java index 9347609aab4e..a8077539b3a3 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchBarTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchBarTest.java @@ -23,8 +23,6 @@ import android.view.View; import android.widget.Switch; import android.widget.TextView; -import com.android.settingslib.RestrictedLockUtils; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -80,11 +78,4 @@ public class MainSwitchBarTest { assertThat(mBar.getVisibility()).isEqualTo(View.GONE); } - - @Test - public void disabledByAdmin_shouldDelegateToRestrictedIcon() { - mBar.setDisabledByAdmin(new RestrictedLockUtils.EnforcedAdmin()); - - assertThat(mBar.getDelegatingView().getId()).isEqualTo(R.id.restricted_icon); - } } diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 1393116a814e..8fe6ce839ef4 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -407,7 +407,6 @@ <!-- Permission required for GTS test - GtsAssistIntentTestCases --> <uses-permission android:name="android.permission.MANAGE_SOUND_TRIGGER" /> <uses-permission android:name="android.permission.CAPTURE_AUDIO_HOTWORD" /> - <uses-permission android:name="android.permission.BIND_VOICE_INTERACTION" /> <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" /> <uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" /> <uses-permission android:name="android.permission.BIND_RESUME_ON_REBOOT_SERVICE" /> @@ -418,6 +417,12 @@ <!-- 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" /> + + <!-- Permission required for CTS test - ClipboardManagerTest --> + <uses-permission android:name="android.permission.SET_CLIP_SOURCE" /> + <application android:label="@string/app_label" android:theme="@android:style/Theme.DeviceDefault.DayNight" android:defaultToDeviceProtectedStorage="true" diff --git a/packages/SystemUI/res/layout/keyguard_user_switcher.xml b/packages/SystemUI/res/layout/keyguard_user_switcher.xml index 253c03e9effb..7aafd895f723 100644 --- a/packages/SystemUI/res/layout/keyguard_user_switcher.xml +++ b/packages/SystemUI/res/layout/keyguard_user_switcher.xml @@ -30,34 +30,4 @@ android:layout_gravity="top|end" android:gravity="end" /> - <LinearLayout - android:id="@+id/end_guest_button" - android:layout_height="@dimen/end_guest_button_layout_height" - android:layout_width="wrap_content" - android:layout_gravity="center_horizontal|bottom" - android:layout_centerHorizontal="true" - android:layout_marginBottom="@dimen/end_guest_button_margin_bottom" - android:orientation="horizontal" - android:gravity="center" - android:paddingLeft="@dimen/end_guest_button_padding_horizontal" - android:paddingRight="@dimen/end_guest_button_padding_horizontal" - android:background="@drawable/end_guest_button_background" - android:visibility="gone"> - <ImageView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:gravity="center" - android:src="@drawable/ic_exit_to_app" - android:background="@android:color/transparent" - android:color="?attr/wallpaperTextColor" /> - <TextView - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:gravity="center" - android:fontFamily="@*android:string/config_bodyFontFamilyMedium" - android:textColor="?attr/wallpaperTextColor" - android:textSize="13sp" - android:text="@string/guest_exit_button" /> - </LinearLayout> - </com.android.systemui.statusbar.policy.KeyguardUserSwitcherView> diff --git a/packages/SystemUI/res/layout/quick_settings_footer.xml b/packages/SystemUI/res/layout/quick_settings_footer.xml index 13572fa9f4f3..db712e4b9f7a 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/tv_notification_panel.xml b/packages/SystemUI/res/layout/tv_notification_panel.xml index 8f00a727b912..eae44c8bcbb8 100644 --- a/packages/SystemUI/res/layout/tv_notification_panel.xml +++ b/packages/SystemUI/res/layout/tv_notification_panel.xml @@ -20,7 +20,7 @@ android:layout_width="@dimen/tv_notification_panel_width" android:layout_height="match_parent" android:layout_gravity="end" - android:background="@color/tv_notification_background_color" + android:background="@android:color/transparent" android:orientation="vertical"> <TextView 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 000000000000..0cfbf2e61dd1 --- /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 c3a62b05db20..0623205f9afb 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 0c0487dd8c10..cf7e9fd90a8c 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 ae8df906c974..db76744bb696 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 1f925708b2b7..47c86ec66ba5 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 e813a901c608..8b629c1d03b2 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 27d4b182b3f7..700484cbdd02 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 ab1cc69ee35c..7fe5fb48b127 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 6716e15ca6cd..4046f0f3e494 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 ee639d6e639c..c88b5782bb99 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 01a55d3d06ba..ed605d43ac1c 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 5d8ccbc1f52c..95775e9cfe7b 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 024b836bbe53..8f86d4277478 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 b1a7a5afd938..aad5d2576ed8 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 88dd62da811c..3266954d7be5 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 21330256d079..7ba79889e51e 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 0a0f8f7aab1e..5cff3c0be53d 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 403fdeec6641..0ee516615235 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 0a0f8f7aab1e..5cff3c0be53d 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 0a0f8f7aab1e..5cff3c0be53d 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 a665fb12b662..a9e20165d25b 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 c97194f1fe08..4157fca000af 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 4c5ef0b090fc..8d8f5b5c2846 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 65c5930d29d3..06fcd0534027 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 9cebde110938..2eab6eb61dfa 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 04b14f1c482b..b25f118f0cee 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 d08bfb5daabb..c9043d1fcbda 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 3d1ab93cb238..8e6c39c824c7 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 c6d0674f97a1..837a424f8b27 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 08841a2ef866..199dd543bb8f 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 867bc2f6d38b..d19c341c7ab6 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 a357ad2b09bc..764acad61b6f 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 d8064ab2fb64..55970a04b2a6 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 a736f88ffd6d..ee3f45db05d2 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 40ddf54cec04..84451eb7f490 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 e20dd51276e7..f694e1d0dec1 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 0c994209f544..08210ef1d5cc 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 527a6956d5e3..d47a4549e18a 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 9fc8b23c8e6e..e937a5aa68f8 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 1b18b5ce4607..802e160a205c 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 e2b9fac8f208..53cf03e12aaa 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 1fbb8a51372b..68519422352c 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 e6f96688a15d..d7faeecb26aa 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 15abcaa7d326..851039ffd1a8 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 78c2958f017c..d42899252bb7 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 7a4d7d2caf57..d726d55ca6f1 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 7070fa19802c..23df8bcebded 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 ff69e056793b..64b4d6df3f79 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 18816ad0c913..225b9aa7444a 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 59fc2d4849c2..c74786e9bf85 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 44883d6dd797..b54c6b02d11a 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 efb27110abe6..93d66f45be6b 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 fcff3dfea74e..093a03b4cd95 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 e723ec6f9035..ca5c6cf0d45b 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 c57a94c8a7cc..cd4d5907da16 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 997147dd15f0..52c289d34d9f 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 e03ee5bfb240..63a842356d8e 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 8ffc3f415442..9da7ad74c505 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 f03c31d313a6..c847d1545cb1 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 459b1631a373..53a71a6f74e5 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 e16b5ec73d15..f8c275d58cd7 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 efe0f064c350..ab53aa0fb2cb 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 3a82febd79b7..884b2101f90a 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 efe0f064c350..ab53aa0fb2cb 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 18093b4e5422..6a928da1a969 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 a9f7c02c4bde..f064e4f54f4b 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 5134e04d72d0..5a1f5993c817 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 d514b66e30ad..eba75e36db7f 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 b7b2dd0e4784..7bf496a2780e 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 9f4c1e183e79..ac22fea9c3c9 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 5c2fbac29e2d..bcfcf3083c62 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 5ca41ed1c7d7..f1f9f20b49ec 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 768e10ccf881..5a4088ed25f5 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 2ea5a6a35c2f..5750119f4c5b 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 03af2a0e3725..f39fa69054b7 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 5e37ed8a0fe8..a726dda73682 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 18313e405f98..92d5a66bb116 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 6b3015c899c4..c708b5a6a7c3 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 12b48306a175..e51122b36c75 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 3668f7e430c8..d2e37e7ac4bc 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 0732c7f3e82b..4615f4a7e55f 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 cc893037e1e5..ee97bc541c4f 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 92f9e67f5f08..bee359dd00c7 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 d2a232b6db22..7b4f663bc516 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 396484afb2ff..1dddeba06a8a 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 d4e05d0d29aa..c6f0ef9ae1c8 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 3bc1c8053db3..c36f7cd630a9 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/colors_tv.xml b/packages/SystemUI/res/values/colors_tv.xml index 0961f503e7d4..64c942de8875 100644 --- a/packages/SystemUI/res/values/colors_tv.xml +++ b/packages/SystemUI/res/values/colors_tv.xml @@ -34,6 +34,7 @@ <color name="tv_volume_dialog_seek_bar_fill">#FFF8F9FA</color> <color name="tv_volume_dialog_accent">#FFDADCE0</color> - <color name="tv_notification_background_color">#383838</color> + <color name="tv_notification_default_background_color">#383838</color> + <color name="tv_notification_blur_background_color">#a0383838</color> <color name="tv_notification_text_color">#FFFFFF</color> </resources> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index ea0ea5e9472a..392eb496031a 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1333,13 +1333,6 @@ <!-- Keyguard user switcher --> <dimen name="kg_user_switcher_text_size">16sp</dimen> - <!-- End guest session button --> - <dimen name="end_guest_button_layout_height">32dp</dimen> - <dimen name="end_guest_button_padding_horizontal">16dp</dimen> - <dimen name="end_guest_button_margin_bottom">96dp</dimen> - <dimen name="end_guest_button_border_size">1dp</dimen> - <dimen name="end_guest_button_corner_radius">16dp</dimen> - <!-- Opacity at which the background for the shutdown UI will be drawn. --> <item name="shutdown_scrim_behind_alpha" format="float" type="dimen">0.95</item> diff --git a/packages/SystemUI/res/values/dimens_tv.xml b/packages/SystemUI/res/values/dimens_tv.xml index 9545bfd088a0..5bd95ebc1c41 100644 --- a/packages/SystemUI/res/values/dimens_tv.xml +++ b/packages/SystemUI/res/values/dimens_tv.xml @@ -16,4 +16,5 @@ --> <resources> <dimen name="tv_notification_panel_width">360dp</dimen> + <dimen name="tv_notification_blur_radius">100dp</dimen> </resources>
\ No newline at end of file diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 5f8df5a13ad1..783f80c2ee02 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] --> @@ -1119,9 +1121,6 @@ <!-- Name for a freshly added user [CHAR LIMIT=30] --> <string name="user_new_user_name">New user</string> - <!-- Label for button that exits guest session and clears the guest user data [CHAR LIMIT=50]--> - <string name="guest_exit_button">End guest session</string> - <!-- Title of the confirmation dialog when exiting guest session [CHAR LIMIT=NONE] --> <string name="guest_exit_guest_dialog_title">Remove guest?</string> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 2d202fb45bbc..ec26b8d7a6a8 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/res/values/styles_tv.xml b/packages/SystemUI/res/values/styles_tv.xml index cb433f3a6009..3e090269699b 100644 --- a/packages/SystemUI/res/values/styles_tv.xml +++ b/packages/SystemUI/res/values/styles_tv.xml @@ -30,5 +30,6 @@ <item name="android:backgroundDimEnabled">false</item> <item name="android:windowNoTitle">true</item> <item name="android:windowContentOverlay">@null</item> + <item name="android:windowIsFloating">true</item> </style> </resources> 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 e5ced3ec3dc2..54242bece2b6 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 @@ package com.android.systemui.shared.recents; */ 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 000000000000..eb3e60cec5c5 --- /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 5c943f63a9a1..49e86f55bb9e 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 @@ package com.android.systemui.shared.recents; 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 android.view.MotionEvent; 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 @@ interface ISystemUiProxy { 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 e6477f158c27..400bf15f8c65 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 @@ public class RemoteAnimationAdapterCompat { // 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 @@ public class RemoteAnimationAdapterCompat { 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 @@ public class RemoteAnimationAdapterCompat { } } 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/systemui/biometrics/UdfpsAnimation.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimation.java index a02900328ae7..a51b6fd16445 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 abstract class UdfpsAnimation extends Drawable { } 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 28b57195c5d4..015a598e972b 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.Canvas; 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 @@ public class UdfpsAnimationEnroll extends UdfpsAnimation { 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 @@ public class UdfpsAnimationEnroll extends UdfpsAnimation { 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 @@ public class UdfpsAnimationEnroll extends UdfpsAnimation { } @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 @@ public class UdfpsAnimationEnroll extends UdfpsAnimation { } } 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 f4dd181eb329..43ecf6778022 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.NonNull; 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 @@ public abstract class UdfpsAnimationView extends FrameLayout implements DozeRece @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - getUdfpsAnimation().onDestroy(); + + if (getUdfpsAnimation() != null) { + getUdfpsAnimation().onDestroy(); + } } private int expansionToAlpha(float expansion) { @@ -78,11 +82,19 @@ public abstract class UdfpsAnimationView extends FrameLayout implements DozeRece } void onIlluminationStarting() { + if (getUdfpsAnimation() == null) { + return; + } + getUdfpsAnimation().setIlluminationShowing(true); postInvalidate(); } void onIlluminationStopped() { + if (getUdfpsAnimation() == null) { + return; + } + getUdfpsAnimation().setIlluminationShowing(false); postInvalidate(); } @@ -131,4 +143,14 @@ public abstract class UdfpsAnimationView extends FrameLayout implements DozeRece } 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 000000000000..515b442b61f6 --- /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 19e774937e20..543df33dd5d7 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 @@ package com.android.systemui.biometrics; 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 @@ public class UdfpsAnimationViewEnroll extends UdfpsAnimationView 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 class UdfpsAnimationViewEnroll extends UdfpsAnimationView public void setEnrollHelper(@NonNull UdfpsEnrollHelper helper) { mEnrollHelper = helper; + mUdfpsAnimation.setEnrollHelper(helper); } @Override @@ -81,4 +83,14 @@ public class UdfpsAnimationViewEnroll extends UdfpsAnimationView 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 e1d7eb3cbb19..1d789ca15dfb 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -20,7 +20,10 @@ import static com.android.internal.util.Preconditions.checkArgument; import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.SuppressLint; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.res.Resources; import android.graphics.PixelFormat; import android.graphics.Point; @@ -28,11 +31,15 @@ import android.graphics.RectF; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.IUdfpsOverlayController; +import android.os.SystemClock; +import android.hardware.fingerprint.IUdfpsOverlayControllerCallback; +import android.os.RemoteException; 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 +73,9 @@ public class UdfpsController implements DozeReceiver, HbmCallback { 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,12 +88,16 @@ public class UdfpsController implements DozeReceiver, HbmCallback { @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; - // Reason the overlay has been requested. See IUdfpsOverlayController for definitions. - private int mRequestReason; - @Nullable UdfpsEnrollHelper mEnrollHelper; + // The current request from FingerprintService. Null if no current request. + @Nullable ServerRequest mServerRequest; // The fingerprint AOD trigger doesn't provide an ACTION_UP/ACTION_CANCEL event to tell us when // to turn off high brightness mode. To get around this limitation, the state of the AOD @@ -92,39 +106,84 @@ public class UdfpsController implements DozeReceiver, HbmCallback { private boolean mIsAodInterruptActive; @Nullable private Runnable mCancelAodTimeoutAction; + /** + * Keeps track of state within a single FingerprintService request. Note that this state + * persists across configuration changes, etc, since it is considered a single request. + * + * TODO: Perhaps we can move more global variables into here + */ + private static class ServerRequest { + // Reason the overlay has been requested. See IUdfpsOverlayController for definitions. + final int mRequestReason; + @NonNull final IUdfpsOverlayControllerCallback mCallback; + @Nullable final UdfpsEnrollHelper mEnrollHelper; + + ServerRequest(int requestReason, @NonNull IUdfpsOverlayControllerCallback callback, + @Nullable UdfpsEnrollHelper enrollHelper) { + mRequestReason = requestReason; + mCallback = callback; + mEnrollHelper = enrollHelper; + } + + void onEnrollmentProgress(int remaining) { + if (mEnrollHelper != null) { + mEnrollHelper.onEnrollmentProgress(remaining); + } + } + + void onEnrollmentHelp() { + if (mEnrollHelper != null) { + mEnrollHelper.onEnrollmentHelp(); + } + } + + void onUserCanceled() { + try { + mCallback.onUserCanceled(); + } catch (RemoteException e) { + Log.e(TAG, "Remote exception", e); + } + } + } + public class UdfpsOverlayController extends IUdfpsOverlayController.Stub { @Override - public void showUdfpsOverlay(int sensorId, int reason) { + public void showUdfpsOverlay(int sensorId, int reason, + @NonNull IUdfpsOverlayControllerCallback callback) { + final UdfpsEnrollHelper enrollHelper; if (reason == IUdfpsOverlayController.REASON_ENROLL_FIND_SENSOR || reason == IUdfpsOverlayController.REASON_ENROLL_ENROLLING) { - mEnrollHelper = new UdfpsEnrollHelper(reason); + enrollHelper = new UdfpsEnrollHelper(mContext, reason); } else { - mEnrollHelper = null; + enrollHelper = null; } - UdfpsController.this.showOverlay(reason); + + mServerRequest = new ServerRequest(reason, callback, enrollHelper); + updateOverlay(); } @Override public void hideUdfpsOverlay(int sensorId) { - UdfpsController.this.hideOverlay(); + mServerRequest = null; + updateOverlay(); } @Override public void onEnrollmentProgress(int sensorId, int remaining) { - if (mEnrollHelper == null) { - Log.e(TAG, "onEnrollProgress received but helper is null"); + if (mServerRequest == null) { + Log.e(TAG, "onEnrollProgress received but serverRequest is null"); return; } - mEnrollHelper.onEnrollmentProgress(remaining); + mServerRequest.onEnrollmentProgress(remaining); } @Override public void onEnrollmentHelp(int sensorId) { - if (mEnrollHelper == null) { - Log.e(TAG, "onEnrollmentHelp received but helper is null"); + if (mServerRequest == null) { + Log.e(TAG, "onEnrollmentHelp received but serverRequest is null"); return; } - mEnrollHelper.onEnrollmentHelp(); + mServerRequest.onEnrollmentHelp(); } @Override @@ -136,46 +195,111 @@ public class UdfpsController implements DozeReceiver, HbmCallback { } } - @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)); + } + + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (mServerRequest != null + && Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) { + Log.d(TAG, "ACTION_CLOSE_SYSTEM_DIALOGS received"); + mServerRequest.onUserCanceled(); + mServerRequest = null; + updateOverlay(); + } + } }; @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: + // 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(); + } + // 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 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(); + 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(); + } } - return true; + 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 @@ -206,6 +330,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback { WindowManager.LayoutParams.TYPE_BOOT_PROGRESS, WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, PixelFormat.TRANSLUCENT); mCoreLayoutParams.setTitle(TAG); @@ -216,6 +341,10 @@ public class UdfpsController implements DozeReceiver, HbmCallback { mCoreLayoutParams.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY; mFingerprintManager.setUdfpsOverlayController(new UdfpsOverlayController()); + + final IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); + context.registerReceiver(mBroadcastReceiver, filter); } @Nullable @@ -231,6 +360,9 @@ public class UdfpsController implements DozeReceiver, HbmCallback { @Override public void dozeTimeTick() { + if (mView == null) { + return; + } mView.dozeTimeTick(); } @@ -247,27 +379,9 @@ public class UdfpsController implements DozeReceiver, HbmCallback { mSensorProps.sensorLocationY + mSensorProps.sensorRadius); } - private void showOverlay(int reason) { - if (mIsOverlayRequested) { - return; - } - mIsOverlayRequested = true; - mRequestReason = reason; - updateOverlay(); - } - - private void hideOverlay() { - if (!mIsOverlayRequested) { - return; - } - mIsOverlayRequested = false; - mRequestReason = IUdfpsOverlayController.REASON_UNKNOWN; - updateOverlay(); - } - private void updateOverlay() { - if (mIsOverlayRequested) { - showUdfpsOverlay(mRequestReason); + if (mServerRequest != null) { + showUdfpsOverlay(mServerRequest.mRequestReason); } else { hideUdfpsOverlay(); } @@ -358,23 +472,29 @@ public class UdfpsController implements DozeReceiver, HbmCallback { 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(mServerRequest.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 942fa7aae0bc..14eca1b1cb2c 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 @@ package com.android.systemui.biometrics; 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 @@ import android.hardware.fingerprint.IUdfpsOverlayController; 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 @@ public class UdfpsEnrollHelper { mTotalSteps = remaining; } + if (remaining != mRemainingSteps) { + mLocationsEnrolled++; + } + + mRemainingSteps = remaining; + if (mListener != null) { mListener.onEnrollmentProgress(remaining, mTotalSteps); } @@ -67,8 +107,21 @@ public class UdfpsEnrollHelper { // 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 cd849e63ba9c..a52bddc1dcd5 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.content.res.TypedArray; 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 @@ public class UdfpsView extends FrameLayout implements DozeReceiver, UdfpsIllumin 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 @@ public class UdfpsView extends FrameLayout implements DozeReceiver, UdfpsIllumin 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/DefaultActivityBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java index 8d2639d4cdd0..242c6afebc3e 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java @@ -21,6 +21,7 @@ import android.app.Activity; import com.android.systemui.ForegroundServicesDialog; import com.android.systemui.keyguard.WorkLockActivity; import com.android.systemui.people.PeopleSpaceActivity; +import com.android.systemui.people.widget.LaunchConversationActivity; import com.android.systemui.screenrecord.ScreenRecordDialog; import com.android.systemui.screenshot.LongScreenshotActivity; import com.android.systemui.settings.brightness.BrightnessDialog; @@ -106,4 +107,10 @@ public abstract class DefaultActivityBinder { @IntoMap @ClassKey(LongScreenshotActivity.class) public abstract Activity bindLongScreenshotActivity(LongScreenshotActivity activity); + + /** Inject into LaunchConversationActivity. */ + @Binds + @IntoMap + @ClassKey(LaunchConversationActivity.class) + public abstract Activity bindLaunchConversationActivity(LaunchConversationActivity activity); } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java index 04c4e977b2cf..1c5715c0296d 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.IActivityTaskManager; 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 @@ public class FrameworkServicesModule { @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 bd3f5a6d82a5..7fb7d8b0eaa5 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.BroadcastReceiver 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 @@ class MediaOutputDialogReceiver @Inject constructor( 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 70b7b047eebc..4491cc12a3cb 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 @@ public class NavigationBarController implements Callbacks, } } else { for (int i = 0; i < mNavigationBars.size(); i++) { - mNavigationBars.get(i).onConfigurationChanged(newConfig); + mNavigationBars.valueAt(i).onConfigurationChanged(newConfig); } } } @@ -193,7 +193,7 @@ public class NavigationBarController implements Callbacks, 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 @@ public class NavigationBarController implements Callbacks, 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 2ea8657f88e5..a69ec278be91 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.Activity; 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.provider.Settings; 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 @@ public class PeopleSpaceActivity extends Activity { 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 @@ public class PeopleSpaceActivity extends Activity { 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 @@ public class PeopleSpaceActivity extends Activity { + 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 41080afb3604..502c95c47d03 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 @@ public class PeopleSpaceUtils { } @Nullable - private static PeopleSpaceTile getPeopleSpaceTile(IPeopleManager peopleManager, + public static PeopleSpaceTile getPeopleSpaceTile(IPeopleManager peopleManager, AppWidgetManager appWidgetManager, Context context, int appWidgetId) { try { @@ -230,7 +230,7 @@ public class PeopleSpaceUtils { 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 @@ public class PeopleSpaceUtils { } } + /** 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 @@ public class PeopleSpaceUtils { 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 @@ public class PeopleSpaceUtils { } /** 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 @@ public class PeopleSpaceUtils { 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 @@ public class PeopleSpaceUtils { 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 @@ public class PeopleSpaceUtils { 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) { @@ -645,6 +609,8 @@ public class PeopleSpaceUtils { PeopleSpaceWidgetProvider.EXTRA_PACKAGE_NAME, tile.getPackageName()); activityIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_USER_HANDLE, tile.getUserHandle()); + activityIntent.putExtra( + PeopleSpaceWidgetProvider.EXTRA_NOTIFICATION_KEY, tile.getNotificationKey()); views.setOnClickPendingIntent(R.id.item, PendingIntent.getActivity( context, appWidgetId, @@ -992,7 +958,7 @@ public class PeopleSpaceUtils { } /** 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 +1031,19 @@ public class PeopleSpaceUtils { * <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/LaunchConversationActivity.java b/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java index 13e30f920f42..48f6184a96d9 100644 --- a/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java +++ b/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java @@ -17,21 +17,38 @@ package com.android.systemui.people.widget; import android.app.Activity; +import android.content.Context; import android.content.Intent; import android.content.pm.LauncherApps; import android.os.Bundle; +import android.os.ServiceManager; import android.os.UserHandle; +import android.service.notification.NotificationStats; +import android.text.TextUtils; import android.util.Log; import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.UiEventLoggerImpl; +import com.android.internal.statusbar.IStatusBarService; +import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.people.PeopleSpaceUtils; +import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; + +import javax.inject.Inject; /** Proxy activity to launch ShortcutInfo's conversation. */ public class LaunchConversationActivity extends Activity { private static final String TAG = "PeopleSpaceLaunchConv"; private static final boolean DEBUG = PeopleSpaceUtils.DEBUG; private UiEventLogger mUiEventLogger = new UiEventLoggerImpl(); + private NotificationEntryManager mNotificationEntryManager; + + @Inject + public LaunchConversationActivity(NotificationEntryManager notificationEntryManager) { + super(); + mNotificationEntryManager = notificationEntryManager; + } @Override public void onCreate(Bundle savedInstanceState) { @@ -43,6 +60,8 @@ public class LaunchConversationActivity extends Activity { String packageName = intent.getStringExtra(PeopleSpaceWidgetProvider.EXTRA_PACKAGE_NAME); UserHandle userHandle = intent.getParcelableExtra( PeopleSpaceWidgetProvider.EXTRA_USER_HANDLE); + String notificationKey = + intent.getStringExtra(PeopleSpaceWidgetProvider.EXTRA_NOTIFICATION_KEY); if (tileId != null && !tileId.isEmpty()) { if (DEBUG) { @@ -54,12 +73,56 @@ public class LaunchConversationActivity extends Activity { getApplicationContext().getSystemService(LauncherApps.class); launcherApps.startShortcut( packageName, tileId, null, null, userHandle); + + IStatusBarService statusBarService = IStatusBarService.Stub.asInterface( + ServiceManager.getService(Context.STATUS_BAR_SERVICE)); + clearNotificationIfPresent( + statusBarService, notificationKey, packageName, userHandle); } catch (Exception e) { - Log.e(TAG, "Exception starting shortcut:" + e); + Log.e(TAG, "Exception:" + e); } } else { if (DEBUG) Log.d(TAG, "Trying to launch conversation with null shortcutInfo."); } finish(); } + + void clearNotificationIfPresent(IStatusBarService statusBarService, + String notifKey, String packageName, UserHandle userHandle) { + if (TextUtils.isEmpty(notifKey)) { + if (DEBUG) Log.d(TAG, "Skipping clear notification: notification key is empty"); + return; + } + + try { + if (statusBarService == null || mNotificationEntryManager == null) { + if (DEBUG) { + Log.d(TAG, "Skipping clear notification: null services, key: " + notifKey); + } + return; + } + + NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(notifKey); + if (entry == null || entry.getRanking() == null) { + if (DEBUG) { + Log.d(TAG, "Skipping clear notification: NotificationEntry or its Ranking" + + " is null, key: " + notifKey); + } + return; + } + + int count = mNotificationEntryManager.getActiveNotificationsCount(); + int rank = entry.getRanking().getRank(); + NotificationVisibility notifVisibility = NotificationVisibility.obtain(notifKey, + rank, count, true); + + if (DEBUG) Log.d(TAG, "Clearing notification, key: " + notifKey + ", rank: " + rank); + statusBarService.onNotificationClear( + packageName, userHandle.getIdentifier(), notifKey, + NotificationStats.DISMISSAL_OTHER, + NotificationStats.DISMISS_SENTIMENT_POSITIVE, notifVisibility); + } catch (Exception e) { + Log.e(TAG, "Exception cancelling notification:" + e); + } + } } 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 9e5c786b9a63..22ee9e89d0a0 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.NotificationListenerService; 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 @@ public class PeopleSpaceWidgetManager { 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 @@ public class PeopleSpaceWidgetManager { 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 @@ public class PeopleSpaceWidgetManager { * 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 @@ public class PeopleSpaceWidgetManager { 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 @@ public class PeopleSpaceWidgetManager { } /** + * 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 @@ public class PeopleSpaceWidgetManager { @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 @@ public class PeopleSpaceWidgetManager { 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 @@ public class PeopleSpaceWidgetManager { 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 @@ public class PeopleSpaceWidgetManager { @Override public void onNotificationsInitialized() { if (DEBUG) Log.d(TAG, "onNotificationsInitialized"); - updateWidgets(); } @Override @@ -213,11 +304,131 @@ public class PeopleSpaceWidgetManager { 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 90baf56e0137..cccf7aa13028 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"; @@ -49,8 +35,28 @@ public class PeopleSpaceWidgetProvider extends AppWidgetProvider { public static final String EXTRA_TILE_ID = "extra_tile_id"; public static final String EXTRA_PACKAGE_NAME = "extra_package_name"; public static final String EXTRA_USER_HANDLE = "extra_user_handle"; + public static final String EXTRA_NOTIFICATION_KEY = "extra_notification_key"; + + public PeopleSpaceWidgetManager peopleSpaceWidgetManager; - public UiEventLogger mUiEventLogger = new UiEventLoggerImpl(); + /** 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 +64,32 @@ public class PeopleSpaceWidgetProvider extends AppWidgetProvider { 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); - - 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); + PeopleSpaceWidgetProvider.TileConversationListener + newListener = new PeopleSpaceWidgetProvider.TileConversationListener(); + peopleSpaceWidgetManager.registerConversationListenerIfNeeded(appWidgetId, + newListener); + } + return; + } - // 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); - - 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); + ensurePeopleSpaceWidgetManagerInitialized(context); + peopleSpaceWidgetManager.deleteWidgets(appWidgetIds); + } - 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 7679d4825475..8ec9b682ffdc 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 @@ class PrivacyDialog( 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 38e2ba4df79a..33ca7d6bafd8 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 @@ public class QSTileBaseView extends com.android.systemui.plugins.qs.QSTileView { 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/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java index 4bf27e2aa4b8..c46cc4f9aa0a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java @@ -71,7 +71,7 @@ public class RotationLockTile extends QSTileImpl<BooleanState> { @Override public Intent getLongClickIntent() { - return new Intent(Settings.ACTION_DISPLAY_SETTINGS); + return new Intent(Settings.ACTION_AUTO_ROTATE_SETTINGS); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index 5b2a7e7ff617..a87bfd83916a 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.settings.CurrentUserTracker; 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.onehanded.OneHanded; 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 @@ public class OverviewProxyService extends CurrentUserTracker implements 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 @@ public class OverviewProxyService extends CurrentUserTracker implements 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 @@ public class OverviewProxyService extends CurrentUserTracker implements } @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 @@ public class OverviewProxyService extends CurrentUserTracker implements } @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 @@ public class OverviewProxyService extends CurrentUserTracker implements 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 @@ public class OverviewProxyService extends CurrentUserTracker implements } @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 @@ public class OverviewProxyService extends CurrentUserTracker implements 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 @@ public class OverviewProxyService extends CurrentUserTracker implements // Connect to the service updateEnabledState(); startConnectionToCurrentUser(); + mStartingSurface = startingSurface; } @Override @@ -938,6 +977,18 @@ public class OverviewProxyService extends CurrentUserTracker implements } } + 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 197582104f8e..bd46ffec759b 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 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis 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/ImageExporter.java b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java index 8fc2830aa422..bc8adc9dad5b 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java @@ -41,6 +41,7 @@ import com.google.common.util.concurrent.ListenableFuture; import java.io.File; import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.time.Duration; @@ -110,6 +111,39 @@ class ImageExporter { } /** + * Stores the given Bitmap to a temp file. + */ + ListenableFuture<File> exportAsTempFile(Executor executor, Bitmap bitmap) { + return CallbackToFutureAdapter.getFuture( + (completer) -> { + executor.execute(() -> { + File cachePath; + try { + cachePath = File.createTempFile("long_screenshot_cache_", ".tmp"); + try (FileOutputStream stream = new FileOutputStream(cachePath)) { + bitmap.compress(mCompressFormat, mQuality, stream); + } catch (IOException e) { + if (cachePath.exists()) { + //noinspection ResultOfMethodCallIgnored + cachePath.delete(); + cachePath = null; + } + completer.setException(e); + } + if (cachePath != null) { + completer.set(cachePath); + } + } catch (IOException e) { + // Failed to create a new file + completer.setException(e); + } + }); + return "Bitmap#compress"; + } + ); + } + + /** * Export the image using the given executor. * * @param executor the thread for execution @@ -122,7 +156,7 @@ class ImageExporter { } /** - * Export the image using the given executor. + * Export the image to MediaStore and publish. * * @param executor the thread for execution * @param bitmap the bitmap to export @@ -131,8 +165,10 @@ class ImageExporter { */ ListenableFuture<Result> export(Executor executor, UUID requestId, Bitmap bitmap, ZonedDateTime captureTime) { - final Task task = - new Task(mResolver, requestId, bitmap, captureTime, mCompressFormat, mQuality); + + final Task task = new Task(mResolver, requestId, bitmap, captureTime, mCompressFormat, + mQuality, /* publish */ true); + return CallbackToFutureAdapter.getFuture( (completer) -> { executor.execute(() -> { @@ -147,12 +183,36 @@ class ImageExporter { ); } + /** + * Delete the entry. + * + * @param executor the thread for execution + * @param uri the uri of the image to publish + * + * @return a listenable future result + */ + ListenableFuture<Result> delete(Executor executor, Uri uri) { + return CallbackToFutureAdapter.getFuture((completer) -> { + executor.execute(() -> { + mResolver.delete(uri, null); + + Result result = new Result(); + result.uri = uri; + result.deleted = true; + completer.set(result); + }); + return "ContentResolver#delete"; + }); + } + static class Result { + Uri uri; UUID requestId; String fileName; long timestamp; - Uri uri; CompressFormat format; + boolean published; + boolean deleted; } private static class Task { @@ -163,9 +223,10 @@ class ImageExporter { private final CompressFormat mFormat; private final int mQuality; private final String mFileName; + private final boolean mPublish; Task(ContentResolver resolver, UUID requestId, Bitmap bitmap, ZonedDateTime captureTime, - CompressFormat format, int quality) { + CompressFormat format, int quality, boolean publish) { mResolver = resolver; mRequestId = requestId; mBitmap = bitmap; @@ -173,6 +234,7 @@ class ImageExporter { mFormat = format; mQuality = quality; mFileName = createFilename(mCaptureTime, mFormat); + mPublish = publish; } public Result execute() throws ImageExportException, InterruptedException { @@ -186,16 +248,21 @@ class ImageExporter { start = Instant.now(); } - uri = createEntry(mFormat, mCaptureTime, mFileName); + uri = createEntry(mResolver, mFormat, mCaptureTime, mFileName); throwIfInterrupted(); - writeImage(mBitmap, mFormat, mQuality, uri); + writeImage(mResolver, mBitmap, mFormat, mQuality, uri); throwIfInterrupted(); - writeExif(uri, mRequestId, mBitmap.getWidth(), mBitmap.getHeight(), mCaptureTime); + int width = mBitmap.getWidth(); + int height = mBitmap.getHeight(); + writeExif(mResolver, uri, mRequestId, width, height, mCaptureTime); throwIfInterrupted(); - publishEntry(uri); + if (mPublish) { + publishEntry(mResolver, uri); + result.published = true; + } result.timestamp = mCaptureTime.toInstant().toEpochMilli(); result.requestId = mRequestId; @@ -218,88 +285,89 @@ class ImageExporter { return result; } - Uri createEntry(CompressFormat format, ZonedDateTime time, String fileName) - throws ImageExportException { - Trace.beginSection("ImageExporter_createEntry"); - try { - final ContentValues values = createMetadata(time, format, fileName); + @Override + public String toString() { + return "export [" + mBitmap + "] to [" + mFormat + "] at quality " + mQuality; + } + } - Uri uri = mResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); - if (uri == null) { - throw new ImageExportException(RESOLVER_INSERT_RETURNED_NULL); - } - return uri; - } finally { - Trace.endSection(); + private static Uri createEntry(ContentResolver resolver, CompressFormat format, + ZonedDateTime time, String fileName) throws ImageExportException { + Trace.beginSection("ImageExporter_createEntry"); + try { + final ContentValues values = createMetadata(time, format, fileName); + + Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); + if (uri == null) { + throw new ImageExportException(RESOLVER_INSERT_RETURNED_NULL); } + return uri; + } finally { + Trace.endSection(); } + } - void writeImage(Bitmap bitmap, CompressFormat format, int quality, - Uri contentUri) throws ImageExportException { - Trace.beginSection("ImageExporter_writeImage"); - try (OutputStream out = mResolver.openOutputStream(contentUri)) { - long start = SystemClock.elapsedRealtime(); - if (!bitmap.compress(format, quality, out)) { - throw new ImageExportException(IMAGE_COMPRESS_RETURNED_FALSE); - } else if (LogConfig.DEBUG_STORAGE) { - Log.d(TAG, "Bitmap.compress took " - + (SystemClock.elapsedRealtime() - start) + " ms"); - } - } catch (IOException ex) { - throw new ImageExportException(OPEN_OUTPUT_STREAM_EXCEPTION, ex); - } finally { - Trace.endSection(); + private static void writeImage(ContentResolver resolver, Bitmap bitmap, CompressFormat format, + int quality, Uri contentUri) throws ImageExportException { + Trace.beginSection("ImageExporter_writeImage"); + try (OutputStream out = resolver.openOutputStream(contentUri)) { + long start = SystemClock.elapsedRealtime(); + if (!bitmap.compress(format, quality, out)) { + throw new ImageExportException(IMAGE_COMPRESS_RETURNED_FALSE); + } else if (LogConfig.DEBUG_STORAGE) { + Log.d(TAG, "Bitmap.compress took " + + (SystemClock.elapsedRealtime() - start) + " ms"); } + } catch (IOException ex) { + throw new ImageExportException(OPEN_OUTPUT_STREAM_EXCEPTION, ex); + } finally { + Trace.endSection(); } + } - void writeExif(Uri uri, UUID requestId, int width, int height, ZonedDateTime captureTime) - throws ImageExportException { - Trace.beginSection("ImageExporter_writeExif"); - ParcelFileDescriptor pfd = null; + private static void writeExif(ContentResolver resolver, Uri uri, UUID requestId, int width, + int height, ZonedDateTime captureTime) throws ImageExportException { + Trace.beginSection("ImageExporter_writeExif"); + ParcelFileDescriptor pfd = null; + try { + pfd = resolver.openFile(uri, "rw", null); + if (pfd == null) { + throw new ImageExportException(RESOLVER_OPEN_FILE_RETURNED_NULL); + } + ExifInterface exif; try { - pfd = mResolver.openFile(uri, "rw", null); - if (pfd == null) { - throw new ImageExportException(RESOLVER_OPEN_FILE_RETURNED_NULL); - } - ExifInterface exif; - try { - exif = new ExifInterface(pfd.getFileDescriptor()); - } catch (IOException e) { - throw new ImageExportException(EXIF_READ_EXCEPTION, e); - } - - updateExifAttributes(exif, requestId, width, height, captureTime); - try { - exif.saveAttributes(); - } catch (IOException e) { - throw new ImageExportException(EXIF_WRITE_EXCEPTION, e); - } - } catch (FileNotFoundException e) { - throw new ImageExportException(RESOLVER_OPEN_FILE_EXCEPTION, e); - } finally { - closeQuietly(pfd); - Trace.endSection(); + exif = new ExifInterface(pfd.getFileDescriptor()); + } catch (IOException e) { + throw new ImageExportException(EXIF_READ_EXCEPTION, e); } - } - void publishEntry(Uri uri) throws ImageExportException { - Trace.beginSection("ImageExporter_publishEntry"); + updateExifAttributes(exif, requestId, width, height, captureTime); try { - ContentValues values = new ContentValues(); - values.put(MediaStore.MediaColumns.IS_PENDING, 0); - values.putNull(MediaStore.MediaColumns.DATE_EXPIRES); - final int rowsUpdated = mResolver.update(uri, values, /* extras */ null); - if (rowsUpdated < 1) { - throw new ImageExportException(RESOLVER_UPDATE_ZERO_ROWS); - } - } finally { - Trace.endSection(); + exif.saveAttributes(); + } catch (IOException e) { + throw new ImageExportException(EXIF_WRITE_EXCEPTION, e); } + } catch (FileNotFoundException e) { + throw new ImageExportException(RESOLVER_OPEN_FILE_EXCEPTION, e); + } finally { + closeQuietly(pfd); + Trace.endSection(); } + } - @Override - public String toString() { - return "compress [" + mBitmap + "] to [" + mFormat + "] at quality " + mQuality; + private static void publishEntry(ContentResolver resolver, Uri uri) + throws ImageExportException { + Trace.beginSection("ImageExporter_publishEntry"); + try { + ContentValues values = new ContentValues(); + values.put(MediaStore.MediaColumns.IS_PENDING, 0); + values.putNull(MediaStore.MediaColumns.DATE_EXPIRES); + final int rowsUpdated = resolver.update(uri, values, /* extras */ null); + if (rowsUpdated < 1) { + throw new ImageExportException(RESOLVER_UPDATE_ZERO_ROWS); + } + } finally { + Trace.endSection(); } } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageLoader.java b/packages/SystemUI/src/com/android/systemui/screenshot/ImageLoader.java new file mode 100644 index 000000000000..988b93c8ca59 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageLoader.java @@ -0,0 +1,94 @@ +/* + * 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.screenshot; + +import android.annotation.Nullable; +import android.content.ContentResolver; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.os.ParcelFileDescriptor; + +import androidx.concurrent.futures.CallbackToFutureAdapter; + +import com.google.common.util.concurrent.ListenableFuture; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + +import javax.inject.Inject; + +/** Loads images. */ +public class ImageLoader { + private final ContentResolver mResolver; + + static class Result { + @Nullable Uri uri; + @Nullable File fileName; + @Nullable Bitmap bitmap; + } + + @Inject + ImageLoader(ContentResolver resolver) { + mResolver = resolver; + } + + /** + * Loads an image via URI from ContentResolver. + * + * @param uri the identifier of the image to load + * @return a listenable future result + */ + ListenableFuture<Result> load(Uri uri) { + return CallbackToFutureAdapter.getFuture(completer -> { + Result result = new Result(); + try (InputStream in = mResolver.openInputStream(uri)) { + result.uri = uri; + result.bitmap = BitmapFactory.decodeStream(in); + completer.set(result); + } + catch (IOException e) { + completer.setException(e); + } + return "BitmapFactory#decodeStream"; + }); + } + + /** + * Loads an image by physical filesystem name. The current user must have filesystem + * permissions to read this file/path. + * + * @param file the system file path of the image to load + * @return a listenable future result + */ + ListenableFuture<Result> load(File file) { + return CallbackToFutureAdapter.getFuture(completer -> { + try (InputStream in = new BufferedInputStream(new FileInputStream(file))) { + Result result = new Result(); + result.fileName = file; + result.bitmap = BitmapFactory.decodeStream(in); + completer.set(result); + } catch (IOException e) { + completer.setException(e); + } + return "BitmapFactory#decodeStream"; + }); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java b/packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java index ae3cd9996f04..6743afa3ab59 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java @@ -15,6 +15,7 @@ */ package com.android.systemui.screenshot; +import android.annotation.AnyThread; import android.graphics.Bitmap; import android.graphics.HardwareRenderer; import android.graphics.RecordingCanvas; @@ -26,6 +27,9 @@ import android.util.Log; import androidx.annotation.UiThread; +import com.android.internal.util.CallbackRegistry; +import com.android.internal.util.CallbackRegistry.NotifierCallback; + import java.util.ArrayList; import java.util.List; @@ -34,10 +38,14 @@ import java.util.List; * <p> * To display on-screen, use {@link #getDrawable()}. */ +@UiThread class ImageTileSet { private static final String TAG = "ImageTileSet"; + private CallbackRegistry<OnBoundsChangedListener, ImageTileSet, Rect> mOnBoundsListeners; + private CallbackRegistry<OnContentChangedListener, ImageTileSet, Rect> mContentListeners; + ImageTileSet(@UiThread Handler handler) { mHandler = handler; } @@ -64,15 +72,43 @@ class ImageTileSet { private OnContentChangedListener mOnContentChangedListener; private OnBoundsChangedListener mOnBoundsChangedListener; - void setOnBoundsChangedListener(OnBoundsChangedListener listener) { - mOnBoundsChangedListener = listener; - } - - void setOnContentChangedListener(OnContentChangedListener listener) { - mOnContentChangedListener = listener; + void addOnBoundsChangedListener(OnBoundsChangedListener listener) { + if (mOnBoundsListeners == null) { + mOnBoundsListeners = new CallbackRegistry<>( + new NotifierCallback<OnBoundsChangedListener, ImageTileSet, Rect>() { + @Override + public void onNotifyCallback(OnBoundsChangedListener callback, + ImageTileSet sender, + int arg, Rect newBounds) { + callback.onBoundsChanged(newBounds.left, newBounds.top, newBounds.right, + newBounds.bottom); + } + }); + } + mOnBoundsListeners.add(listener); + } + + void addOnContentChangedListener(OnContentChangedListener listener) { + if (mContentListeners == null) { + mContentListeners = new CallbackRegistry<>( + new NotifierCallback<OnContentChangedListener, ImageTileSet, Rect>() { + @Override + public void onNotifyCallback(OnContentChangedListener callback, + ImageTileSet sender, + int arg, Rect newBounds) { + callback.onContentChanged(); + } + }); + } + mContentListeners.add(listener); } + @AnyThread void addTile(ImageTile tile) { + if (!mHandler.getLooper().isCurrentThread()) { + mHandler.post(() -> addTile(tile)); + return; + } final Rect newBounds = new Rect(mBounds); final Rect newRect = tile.getLocation(); mTiles.add(tile); @@ -84,27 +120,15 @@ class ImageTileSet { notifyContentChanged(); } - void notifyContentChanged() { - if (mOnContentChangedListener == null) { - return; - } - if (mHandler.getLooper().isCurrentThread()) { - mOnContentChangedListener.onContentChanged(); - } else { - mHandler.post(() -> mOnContentChangedListener.onContentChanged()); + private void notifyContentChanged() { + if (mContentListeners != null) { + mContentListeners.notifyCallbacks(this, 0, null); } } - void notifyBoundsChanged(Rect bounds) { - if (mOnBoundsChangedListener == null) { - return; - } - if (mHandler.getLooper().isCurrentThread()) { - mOnBoundsChangedListener.onBoundsChanged( - bounds.left, bounds.top, bounds.right, bounds.bottom); - } else { - mHandler.post(() -> mOnBoundsChangedListener.onBoundsChanged( - bounds.left, bounds.top, bounds.right, bounds.bottom)); + private void notifyBoundsChanged(Rect bounds) { + if (mOnBoundsListeners != null) { + mOnBoundsListeners.notifyCallbacks(this, 0, bounds); } } @@ -180,8 +204,13 @@ class ImageTileSet { return mBounds.height(); } + @AnyThread void clear() { - if (mBounds.isEmpty()) { + if (!mHandler.getLooper().isCurrentThread()) { + mHandler.post(this::clear); + return; + } + if (mTiles.isEmpty()) { return; } mBounds.setEmpty(); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java index 9da6b8f240e9..b62e2c34ed6e 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java @@ -88,7 +88,7 @@ public class ScrollCaptureController { } private void onCaptureResult(CaptureResult result) { - Log.d(TAG, "onCaptureResult: " + result + " scrolling up: " + mScrollingUp + Log.d(TAG, "onCaptureResult: " + result + " scrolling " + (mScrollingUp ? "UP" : "DOWN") + " finish on boundary: " + mFinishOnBoundary); boolean emptyResult = result.captured.height() == 0; boolean partialResult = !emptyResult @@ -98,6 +98,7 @@ public class ScrollCaptureController { if (partialResult || emptyResult) { // Potentially reached a vertical boundary. Extend in the other direction. if (mFinishOnBoundary) { + Log.d(TAG, "Partial/empty: finished!"); finish = true; } else { // We hit a boundary, clear the tiles, capture everything in the opposite direction, @@ -105,16 +106,22 @@ public class ScrollCaptureController { mImageTileSet.clear(); mFinishOnBoundary = true; mScrollingUp = !mScrollingUp; + Log.d(TAG, "Partial/empty: cleared, switch direction to finish"); } } else { // Got the full requested result, but may have got enough bitmap data now int expectedTiles = mImageTileSet.size() + 1; - boolean hitMaxTiles = expectedTiles >= mSession.getMaxTiles(); - if (hitMaxTiles && mFinishOnBoundary) { + if (expectedTiles >= mSession.getMaxTiles()) { + Log.d(TAG, "Hit max tiles: finished"); + // If we ever hit the max tiles, we've got enough bitmap data to finish (even if we + // weren't sure we'd finish on this pass). finish = true; } else { - if (mScrollingUp) { + if (mScrollingUp && !mFinishOnBoundary) { + // During the initial scroll up, we only want to acquire the portion described + // by IDEAL_PORTION_ABOVE. if (expectedTiles >= mSession.getMaxTiles() * IDEAL_PORTION_ABOVE) { + Log.d(TAG, "Hit ideal portion above: clear and switch direction"); // We got enough above the start point, now see how far down it can go. mImageTileSet.clear(); mScrollingUp = false; diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TiledImageDrawable.java b/packages/SystemUI/src/com/android/systemui/screenshot/TiledImageDrawable.java index 4ec8eb22c67a..71df369aa7b8 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/TiledImageDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/TiledImageDrawable.java @@ -38,9 +38,10 @@ public class TiledImageDrawable extends Drawable { public TiledImageDrawable(ImageTileSet tiles) { mTiles = tiles; - mTiles.setOnContentChangedListener(this::onContentChanged); + mTiles.addOnContentChangedListener(this::onContentChanged); } + private void onContentChanged() { if (mNode != null && mNode.hasDisplayList()) { mNode.discardDisplayList(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java index 9ef304d7e83c..992015320fa0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java @@ -430,7 +430,7 @@ public class NotificationGroupingUtil { public static final int[] MARGIN_ADJUSTED_VIEWS = { R.id.notification_headerless_view_column, - R.id.line1, + R.id.title, R.id.notification_main_column, R.id.notification_header}; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index d2ddd212bda6..3496581b1b8a 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 @@ public class NotificationShelf extends ActivatableNotificationView implements handleCustomTransformHeight(view, expandingAnimated, iconState); float fullTransitionAmount; - float transitionAmount; + float iconTransitionAmount; float contentTransformationAmount; float shelfStart = getTranslationY(); boolean fullyInOrOut = true; @@ -549,18 +549,19 @@ public class NotificationShelf extends ActivatableNotificationView implements 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 @@ public class NotificationShelf extends ActivatableNotificationView implements 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 @@ public class NotificationShelf extends ActivatableNotificationView implements 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 @@ public class NotificationShelf extends ActivatableNotificationView implements || 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 @@ public class NotificationShelf extends ActivatableNotificationView implements ? fullTransitionAmount : transitionAmount; iconState.clampedAppearAmount = clampedAmount; - setIconTransformationAmount(view, transitionAmount, iconTransformDistance, - clampedAmount != transitionAmount, isLastChild); + setIconTransformationAmount(view, transitionAmount, isLastChild); } private boolean isTargetClipped(ExpandableView view) { @@ -708,110 +707,51 @@ public class NotificationShelf extends ActivatableNotificationView implements } private void setIconTransformationAmount(ExpandableView view, - float transitionAmount, float iconTransformDistance, boolean usingLinearInterpolation, + float transitionAmount, boolean isLastChild) { if (!(view instanceof ExpandableNotificationRow)) { return; } ExpandableNotificationRow row = (ExpandableNotificationRow) view; - StatusBarIconView icon = row.getShelfIcon(); NotificationIconContainer.IconState iconState = getIconState(icon); - 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; + if (iconState == null) { + return; + } + 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 = transitionAmount; - float shelfIconSize = mAmbientState.isFullyHidden() ? mHiddenShelfIconSize : mIconSize; - shelfIconSize = shelfIconSize * icon.getIconScale(); + // Fade in icons at shelf start + // This is important for conversation icons, which are badged and need x reset + iconState.xTranslation = mShelfIcons.getActualPaddingStart(); - // 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 - float shelfIconPositionX = icon.getLeft(); - shelfIconPositionX += (1.0f - icon.getIconScale()) * icon.getWidth() / 2.0f; - float iconXTranslation = NotificationUtils.interpolate( - iconStartPadding - shelfIconPositionX, - mShelfIcons.getActualPaddingStart(), - 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.xTranslation = iconXTranslation; - if (stayingInShelf) { - iconState.iconAppearAmount = 1.0f; - iconState.alpha = 1.0f; - iconState.scaleX = 1.0f; - iconState.scaleY = 1.0f; - iconState.hidden = false; - } - if (row.isAboveShelf() - || row.showingPulsing() - || (!row.isInShelf() && (isLastChild && row.areGutsExposed() - || row.getTranslationZ() > mAmbientState.getBaseZHeight()))) { - iconState.hidden = true; - } - int backgroundColor = getBackgroundColorWithoutTint(); - int shelfColor = icon.getContrastedStaticDrawableColor(backgroundColor); - if (!noIcon && shelfColor != StatusBarIconView.NO_COLOR) { - int iconColor = row.getOriginalIconColor(); - shelfColor = NotificationUtils.interpolateColors(iconColor, shelfColor, - iconState.iconAppearAmount); - } - iconState.iconColor = shelfColor; - } + if (stayingInShelf) { + iconState.iconAppearAmount = 1.0f; + iconState.alpha = 1.0f; + iconState.scaleX = 1.0f; + iconState.scaleY = 1.0f; + iconState.hidden = false; + } + if (row.isAboveShelf() + || row.showingPulsing() + || (!row.isInShelf() && (isLastChild && row.areGutsExposed() + || row.getTranslationZ() > mAmbientState.getBaseZHeight()))) { + iconState.hidden = true; + } + int backgroundColor = getBackgroundColorWithoutTint(); + int shelfColor = icon.getContrastedStaticDrawableColor(backgroundColor); + if (row.isShowingIcon() && shelfColor != StatusBarIconView.NO_COLOR) { + int iconColor = row.getOriginalIconColor(); + shelfColor = NotificationUtils.interpolateColors(iconColor, shelfColor, + iconState.iconAppearAmount); + } + iconState.iconColor = shelfColor; } private NotificationIconContainer.IconState getIconState(StatusBarIconView icon) { 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 d1ab7ea55d57..004cf9968a77 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 @@ class ConversationNotificationManager @Inject constructor( } 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 8a22b9f6891f..dbd8580b751e 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 @@ public final class NotificationEntry extends ListEntry { 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 @@ public final class NotificationEntry extends ListEntry { //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 @@ public final class NotificationEntry extends ListEntry { 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 ba45f9a687ed..5375ac345e50 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 @@ class IconManager @Inject constructor( // 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 52063285ac01..0f23b770aacd 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 @@ public class ExpandableNotificationRow extends ActivatableNotificationView 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 @@ public class ExpandableNotificationRow extends ActivatableNotificationView // The public layouts expand button is always visible mPublicLayout.updateExpandButtons(true); updateLimits(); - updateIconVisibilities(); updateShelfIconColor(); updateRippleAllowed(); if (mUpdateBackgroundOnUpdate) { @@ -883,7 +881,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView setDistanceToTopRoundness(NO_ROUNDNESS); mNotificationParent.updateBackgroundForGroupState(); } - updateIconVisibilities(); updateBackgroundClipping(); } @@ -1481,21 +1478,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView 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 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } } - /** 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); 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 b0b91bd5177c..d3065aa36a5f 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 @@ public class NotificationContentView extends FrameLayout { 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 class NotificationContentView extends FrameLayout { 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 @@ public class NotificationContentView extends FrameLayout { 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 @@ public class NotificationContentView extends FrameLayout { 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 7248bcef621c..151840afcef1 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 @@ public class NotificationBigPictureTemplateViewWrapper extends NotificationTempl 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 905bccfa6cdf..fb0fdcccd4b1 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 @@ class NotificationConversationTemplateViewWrapper constructor( ) } - 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 eb79e3c8a69a..bdafd232167d 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 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper { } @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 e9934c0053b0..e0b58125aabd 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 @@ import com.android.systemui.statusbar.notification.row.HybridNotificationView; 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 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp } 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 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp 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 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp 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 89babf0835c6..9ced12d32d27 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 @@ public abstract class NotificationViewWrapper implements TransformableView { 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/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java index 3739424b4f5d..d8ee102064e1 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 @@ public class NotificationChildrenContainer extends ViewGroup { 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/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index ae14fa943a4b..19b98953325f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -1051,9 +1051,7 @@ public class NotificationPanelViewController extends PanelViewController { .getVisibleNotificationCount() != 0 || mMediaDataManager.hasActiveMedia(); mKeyguardStatusViewController.setHasVisibleNotifications(hasVisibleNotifications); int userIconHeight = mKeyguardQsUserSwitchController != null - ? mKeyguardQsUserSwitchController.getUserIconHeight() - : (mKeyguardUserSwitcherController != null - ? mKeyguardUserSwitcherController.getUserIconHeight() : 0); + ? mKeyguardQsUserSwitchController.getUserIconHeight() : 0; mClockPositionAlgorithm.setup(mStatusBarHeaderHeightKeyguard, totalHeight - bottomPadding, mNotificationStackScrollLayoutController.getIntrinsicContentHeight(), diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index 7b2330bdcd6e..270a0f8c5d5e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -124,6 +124,12 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump public static final float BUSY_SCRIM_ALPHA = 1f; /** + * The default scrim under the expanded bubble stack. + * This should not be lower than 0.54, otherwise we won't pass GAR. + */ + public static final float BUBBLE_SCRIM_ALPHA = 0.6f; + + /** * Scrim opacity that can have text on top. */ public static final float GAR_SCRIM_ALPHA = 0.6f; @@ -207,8 +213,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump FeatureFlags featureFlags, @Main Executor mainExecutor) { mScrimStateListener = lightBarController::setScrimState; mDefaultScrimAlpha = featureFlags.isShadeOpaque() ? BUSY_SCRIM_ALPHA : GAR_SCRIM_ALPHA; - ScrimState.BUBBLE_EXPANDED.setBubbleAlpha(featureFlags.isShadeOpaque() - ? BUSY_SCRIM_ALPHA : GAR_SCRIM_ALPHA); + ScrimState.BUBBLE_EXPANDED.setBubbleAlpha(BUBBLE_SCRIM_ALPHA); mBlurUtils = blurUtils; mKeyguardStateController = keyguardStateController; 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 bf36435b78c9..0807f8aa5607 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 class StatusBar extends SystemUI implements DemoMode, */ 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/KeyguardUserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java index 5a80c05cc3cd..25e908450808 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java @@ -33,7 +33,6 @@ import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.LinearLayout; import com.android.keyguard.KeyguardConstants; import com.android.keyguard.KeyguardUpdateMonitor; @@ -83,12 +82,10 @@ public class KeyguardUserSwitcherController extends ViewController<KeyguardUserS // Child views of KeyguardUserSwitcherView private KeyguardUserSwitcherListView mListView; - private LinearLayout mEndGuestButton; // State info for the user switcher private boolean mUserSwitcherOpen; private int mCurrentUserId = UserHandle.USER_NULL; - private boolean mCurrentUserIsGuest; private int mBarState; private float mDarkAmount; @@ -185,11 +182,6 @@ public class KeyguardUserSwitcherController extends ViewController<KeyguardUserS if (DEBUG) Log.d(TAG, "onInit"); mListView = mView.findViewById(R.id.keyguard_user_switcher_list); - mEndGuestButton = mView.findViewById(R.id.end_guest_button); - - mEndGuestButton.setOnClickListener(v -> { - mUserSwitcherController.showExitGuestDialog(mCurrentUserId); - }); mView.setOnTouchListener((v, event) -> { if (!isListAnimating()) { @@ -209,9 +201,14 @@ public class KeyguardUserSwitcherController extends ViewController<KeyguardUserS mKeyguardUpdateMonitor.registerCallback(mInfoCallback); mStatusBarStateController.addCallback(mStatusBarStateListener); mScreenLifecycle.addObserver(mScreenObserver); - mView.addOnLayoutChangeListener(mBackground); - mView.setBackground(mBackground); - mBackground.setAlpha(0); + if (isSimpleUserSwitcher()) { + // Don't use the background for the simple user switcher + setUserSwitcherOpened(true /* open */, true /* animate */); + } else { + mView.addOnLayoutChangeListener(mBackground); + mView.setBackground(mBackground); + mBackground.setAlpha(0); + } } @Override @@ -291,7 +288,6 @@ public class KeyguardUserSwitcherController extends ViewController<KeyguardUserS } foundCurrentUser = true; mCurrentUserId = userTag.info.id; - mCurrentUserIsGuest = userTag.isGuest; // Current user is always visible newView.updateVisibilities(true /* showItem */, mUserSwitcherOpen /* showTextName */, false /* animate */); @@ -317,19 +313,10 @@ public class KeyguardUserSwitcherController extends ViewController<KeyguardUserS if (!foundCurrentUser) { Log.w(TAG, "Current user is not listed"); mCurrentUserId = UserHandle.USER_NULL; - mCurrentUserIsGuest = false; } } /** - * Get the height of the keyguard user switcher view when closed. - */ - public int getUserIconHeight() { - View firstChild = mListView.getChildAt(0); - return firstChild == null ? 0 : firstChild.getHeight(); - } - - /** * Set the visibility of the keyguard user switcher view based on some new state. */ public void setKeyguardUserSwitcherVisibility( @@ -406,7 +393,6 @@ public class KeyguardUserSwitcherController extends ViewController<KeyguardUserS private void updateVisibilities(boolean animate) { if (DEBUG) Log.d(TAG, String.format("updateVisibilities: animate=%b", animate)); - mEndGuestButton.animate().cancel(); if (mBgAnimator != null) { mBgAnimator.cancel(); } @@ -434,44 +420,6 @@ public class KeyguardUserSwitcherController extends ViewController<KeyguardUserS }); mBgAnimator.start(); } - - if (mUserSwitcherOpen && mCurrentUserIsGuest) { - // Show the "End guest session" button - mEndGuestButton.setVisibility(View.VISIBLE); - if (animate) { - mEndGuestButton.setAlpha(0f); - mEndGuestButton.animate() - .alpha(1f) - .setDuration(360) - .setInterpolator(Interpolators.ALPHA_IN) - .withEndAction(() -> { - mEndGuestButton.setClickable(true); - }); - } else { - mEndGuestButton.setClickable(true); - mEndGuestButton.setAlpha(1f); - } - } else { - // Hide the "End guest session" button. If it's already GONE, don't try to - // animate it or it will appear again for an instant. - mEndGuestButton.setClickable(false); - if (animate && mEndGuestButton.getVisibility() != View.GONE) { - mEndGuestButton.setVisibility(View.VISIBLE); - mEndGuestButton.setAlpha(1f); - mEndGuestButton.animate() - .alpha(0f) - .setDuration(360) - .setInterpolator(Interpolators.ALPHA_OUT) - .withEndAction(() -> { - mEndGuestButton.setVisibility(View.GONE); - mEndGuestButton.setAlpha(1f); - }); - } else { - mEndGuestButton.setVisibility(View.GONE); - mEndGuestButton.setAlpha(1f); - } - } - mListView.updateVisibilities(mUserSwitcherOpen, animate); } @@ -532,15 +480,6 @@ public class KeyguardUserSwitcherController extends ViewController<KeyguardUserS return createUserDetailItemView(convertView, parent, item); } - @Override - public String getName(Context context, UserSwitcherController.UserRecord item) { - if (item.isGuest) { - return context.getString(com.android.settingslib.R.string.guest_nickname); - } else { - return super.getName(context, item); - } - } - KeyguardUserDetailItemView convertOrInflate(View convertView, ViewGroup parent) { if (!(convertView instanceof KeyguardUserDetailItemView) || !(convertView.getTag() instanceof UserSwitcherController.UserRecord)) { @@ -608,18 +547,11 @@ public class KeyguardUserSwitcherController extends ViewController<KeyguardUserS } if (mKeyguardUserSwitcherController.isUserSwitcherOpen()) { - if (user.isCurrent) { - // Close the switcher if tapping the current user - mKeyguardUserSwitcherController.setUserSwitcherOpened( - false /* open */, true /* animate */); - } else if (user.isSwitchToEnabled) { - if (!user.isAddUser && !user.isRestricted && !user.isDisabledByAdmin) { - if (mCurrentUserView != null) { - mCurrentUserView.setActivated(false); - } - v.setActivated(true); - } + if (!user.isCurrent || user.isGuest) { onUserListItemClicked(user); + } else { + mKeyguardUserSwitcherController.closeSwitcherIfOpenAndNotSimple( + true /* animate */); } } else { // If switcher is closed, tapping anywhere in the view will open it diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java index 7c82c116eb3d..a815adfc9c9a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java @@ -35,20 +35,22 @@ public class KeyguardUserSwitcherListView extends AlphaOptimizedLinearLayout { private static final String TAG = "KeyguardUserSwitcherListView"; private static final boolean DEBUG = KeyguardConstants.DEBUG; - private static final int ANIMATION_DURATION_OPENING = 360; - private static final int ANIMATION_DURATION_CLOSING = 240; - private boolean mAnimating; private final AppearAnimationUtils mAppearAnimationUtils; private final DisappearAnimationUtils mDisappearAnimationUtils; public KeyguardUserSwitcherListView(Context context, AttributeSet attrs) { super(context, attrs); - setClipChildren(false); - mAppearAnimationUtils = new AppearAnimationUtils(context, ANIMATION_DURATION_OPENING, - -0.5f, 0.5f, Interpolators.FAST_OUT_SLOW_IN); - mDisappearAnimationUtils = new DisappearAnimationUtils(context, ANIMATION_DURATION_CLOSING, - 0.5f, 0.5f, Interpolators.FAST_OUT_LINEAR_IN); + mAppearAnimationUtils = new AppearAnimationUtils(context, + AppearAnimationUtils.DEFAULT_APPEAR_DURATION, + -0.5f /* translationScaleFactor */, + 0.5f /* delayScaleFactor */, + Interpolators.FAST_OUT_SLOW_IN); + mDisappearAnimationUtils = new DisappearAnimationUtils(context, + AppearAnimationUtils.DEFAULT_APPEAR_DURATION, + 0.2f /* translationScaleFactor */, + 0.2f /* delayScaleFactor */, + Interpolators.FAST_OUT_SLOW_IN_REVERSE); } /** @@ -82,69 +84,40 @@ public class KeyguardUserSwitcherListView extends AlphaOptimizedLinearLayout { mAnimating = false; - int userListCount = getChildCount(); - if (userListCount > 0) { - // The first child is always the current user. - KeyguardUserDetailItemView currentUserView = ((KeyguardUserDetailItemView) getChildAt( - 0)); - currentUserView.updateVisibilities(true /* showItem */, open /* showTextName */, - animate); - currentUserView.setClickable(true); - currentUserView.clearAnimation(); - } - - if (userListCount <= 1) { - return; - } - - if (animate) { - // Create an array of all the remaining users (that aren't the current user). - KeyguardUserDetailItemView[] otherUserViews = - new KeyguardUserDetailItemView[userListCount - 1]; - for (int i = 1, n = 0; i < userListCount; i++, n++) { - otherUserViews[n] = (KeyguardUserDetailItemView) getChildAt(i); - + int childCount = getChildCount(); + KeyguardUserDetailItemView[] userItemViews = new KeyguardUserDetailItemView[childCount]; + for (int i = 0; i < childCount; i++) { + userItemViews[i] = (KeyguardUserDetailItemView) getChildAt(i); + userItemViews[i].clearAnimation(); + if (i == 0) { + // The first child is always the current user. + userItemViews[i].updateVisibilities(true /* showItem */, open /* showTextName */, + animate); + userItemViews[i].setClickable(true); + } else { // Update clickable state immediately so that the menu feels more responsive - otherUserViews[n].setClickable(open); - + userItemViews[i].setClickable(open); // Before running the animation, ensure visibility is set correctly - otherUserViews[n].updateVisibilities( - true /* showItem */, true /* showTextName */, false /* animate */); - otherUserViews[n].clearAnimation(); + userItemViews[i].updateVisibilities(animate || open /* showItem */, + true /* showTextName */, false /* animate */); } + } + + if (animate) { + // AnimationUtils will immediately hide/show the first item in the array. Since the + // first view is the current user, we want to manage its visibility separately. + // Set first item to null so AnimationUtils ignores it. + userItemViews[0] = null; setClipChildren(false); setClipToPadding(false); - mAnimating = true; - - final int nonCurrentUserCount = otherUserViews.length; - if (open) { - mAppearAnimationUtils.startAnimation(otherUserViews, () -> { - setClipChildren(true); - setClipToPadding(true); - mAnimating = false; - }); - } else { - mDisappearAnimationUtils.startAnimation(otherUserViews, () -> { - setClipChildren(true); - setClipToPadding(true); - for (int i = 0; i < nonCurrentUserCount; i++) { - otherUserViews[i].updateVisibilities( - false /* showItem */, true /* showTextName */, false /* animate */); - } - mAnimating = false; - }); - } - } else { - for (int i = 1; i < userListCount; i++) { - KeyguardUserDetailItemView nonCurrentUserView = - ((KeyguardUserDetailItemView) getChildAt(i)); - nonCurrentUserView.clearAnimation(); - nonCurrentUserView.updateVisibilities( - open /* showItem */, true /* showTextName */, false /* animate */); - nonCurrentUserView.setClickable(open); - } + (open ? mAppearAnimationUtils : mDisappearAnimationUtils) + .startAnimation(userItemViews, () -> { + setClipChildren(true); + setClipToPadding(true); + mAnimating = false; + }); } } 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 ad4fa64ac905..edec61832c8e 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 @@ public class SmartReplyView extends ViewGroup { @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 @@ public class SmartReplyView extends ViewGroup { mBreakIterator = BreakIterator.getLineInstance(); - setBackgroundTintColor(mDefaultBackgroundColor); + setBackgroundTintColor(mDefaultBackgroundColor, false /* colorized */); reallocateCandidateButtonQueueForSqueezing(); } @@ -182,7 +183,7 @@ public class SmartReplyView extends ViewGroup { public void resetSmartSuggestions(View newSmartReplyContainer) { mSmartReplyContainer = newSmartReplyContainer; removeAllViews(); - setBackgroundTintColor(mDefaultBackgroundColor); + setBackgroundTintColor(mDefaultBackgroundColor, false /* colorized */); } /** Add buttons to the {@link SmartReplyView} */ @@ -676,19 +677,24 @@ public class SmartReplyView extends ViewGroup { 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/statusbar/tv/notifications/TvNotificationPanelActivity.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationPanelActivity.java index 30f401b91d25..b325b10957f7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationPanelActivity.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationPanelActivity.java @@ -20,15 +20,19 @@ import android.annotation.NonNull; import android.app.Activity; import android.app.NotificationManager; import android.content.Intent; +import android.graphics.drawable.ColorDrawable; import android.os.Bundle; import android.service.notification.StatusBarNotification; import android.util.SparseArray; +import android.view.Gravity; import android.view.View; import androidx.leanback.widget.VerticalGridView; import com.android.systemui.R; +import java.util.function.Consumer; + import javax.inject.Inject; /** @@ -42,6 +46,7 @@ public class TvNotificationPanelActivity extends Activity implements private VerticalGridView mNotificationListView; private View mNotificationPlaceholder; private boolean mPanelAlreadyOpen = false; + private final Consumer<Boolean> mBlurConsumer = this::enableBlur; @Inject public TvNotificationPanelActivity(TvNotificationHandler tvNotificationHandler) { @@ -103,6 +108,33 @@ public class TvNotificationPanelActivity extends Activity implements } @Override + public void onAttachedToWindow() { + super.onAttachedToWindow(); + getWindow().setGravity(Gravity.END); + getWindowManager().addCrossWindowBlurEnabledListener(mBlurConsumer); + } + + private void enableBlur(boolean enabled) { + if (enabled) { + int blurRadius = getResources().getDimensionPixelSize( + R.dimen.tv_notification_blur_radius); + getWindow().setBackgroundDrawable( + new ColorDrawable(getColor(R.color.tv_notification_blur_background_color))); + getWindow().setBackgroundBlurRadius(blurRadius); + } else { + getWindow().setBackgroundDrawable( + new ColorDrawable(getColor(R.color.tv_notification_default_background_color))); + getWindow().setBackgroundBlurRadius(0); + } + } + + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + getWindowManager().removeCrossWindowBlurEnabledListener(mBlurConsumer); + } + + @Override public void onDestroy() { super.onDestroy(); mTvNotificationHandler.setTvNotificationListener(null); diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java index e9e4380859b7..7244ffed61b9 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java @@ -300,7 +300,7 @@ public class TunerServiceImpl extends TunerService { dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mContext.getString(R.string.cancel), (DialogInterface.OnClickListener) null); dialog.setButton(DialogInterface.BUTTON_POSITIVE, - mContext.getString(R.string.guest_exit_guest_dialog_remove), (d, which) -> { + mContext.getString(R.string.qs_customize_remove), (d, which) -> { // Tell the tuner (in main SysUI process) to clear all its settings. mContext.sendBroadcast(new Intent(TunerService.ACTION_CLEAR)); // Disable access to tuner. diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java index ff2881953342..82dad68f238c 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java @@ -19,16 +19,15 @@ package com.android.systemui.wmshell; import android.content.Context; import android.os.Handler; -import com.android.systemui.dagger.WMComponent; import com.android.systemui.dagger.WMSingleton; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.WindowManagerShellWrapper; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.ShellExecutor; +import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.SystemWindows; import com.android.wm.shell.common.TaskStackListenerImpl; import com.android.wm.shell.common.annotations.ShellMainThread; -import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController; import com.android.wm.shell.pip.Pip; import com.android.wm.shell.pip.PipAnimationController; @@ -140,6 +139,7 @@ public abstract class TvPipModule { @Provides static PipTaskOrganizer providePipTaskOrganizer(Context context, TvPipMenuController tvPipMenuController, + SyncTransactionQueue syncTransactionQueue, PipBoundsState pipBoundsState, PipBoundsAlgorithm pipBoundsAlgorithm, PipAnimationController pipAnimationController, @@ -149,7 +149,8 @@ public abstract class TvPipModule { DisplayController displayController, PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer, @ShellMainThread ShellExecutor mainExecutor) { - return new PipTaskOrganizer(context, pipBoundsState, pipBoundsAlgorithm, + return new PipTaskOrganizer(context, + syncTransactionQueue, pipBoundsState, pipBoundsAlgorithm, tvPipMenuController, pipAnimationController, pipSurfaceTransactionHelper, pipTransitionController, splitScreenOptional, displayController, pipUiEventLogger, shellTaskOrganizer, mainExecutor); diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java index 78cd3a823aab..a12326961b08 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java @@ -17,6 +17,7 @@ package com.android.systemui.wmshell; import static android.os.Process.THREAD_PRIORITY_DISPLAY; +import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST; import android.animation.AnimationHandler; import android.app.ActivityTaskManager; @@ -61,6 +62,7 @@ import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.common.annotations.ChoreographerSfVsync; import com.android.wm.shell.common.annotations.ShellAnimationThread; import com.android.wm.shell.common.annotations.ShellMainThread; +import com.android.wm.shell.common.annotations.ShellSplashscreenThread; import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout; import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController; @@ -165,6 +167,19 @@ public abstract class WMShellBaseModule { } /** + * Provides a Shell splashscreen-thread Executor + */ + @WMSingleton + @Provides + @ShellSplashscreenThread + public static ShellExecutor provideSplashScreenExecutor() { + HandlerThread shellSplashscreenThread = new HandlerThread("wmshell.splashscreen", + THREAD_PRIORITY_TOP_APP_BOOST); + shellSplashscreenThread.start(); + return new HandlerExecutor(shellSplashscreenThread.getThreadHandler()); + } + + /** * Provide a Shell main-thread AnimationHandler. The AnimationHandler can be set on * {@link android.animation.ValueAnimator}s and will ensure that the animation will run on * the Shell main-thread with the SF vsync. @@ -328,12 +343,12 @@ public abstract class WMShellBaseModule { @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)); } // @@ -465,8 +480,8 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides static StartingWindowController provideStartingWindowController(Context context, - @ShellMainThread ShellExecutor mainExecutor) { - return new StartingWindowController(context, mainExecutor); + @ShellSplashscreenThread ShellExecutor executor) { + return new StartingWindowController(context, executor); } // diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java index 754b6a6435b4..d5183f85ad13 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java @@ -172,6 +172,7 @@ public class WMShellModule { @WMSingleton @Provides static PipTaskOrganizer providePipTaskOrganizer(Context context, + SyncTransactionQueue syncTransactionQueue, PipBoundsState pipBoundsState, PipBoundsAlgorithm pipBoundsAlgorithm, PhonePipMenuController menuPhoneController, @@ -182,7 +183,8 @@ public class WMShellModule { DisplayController displayController, PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer, @ShellMainThread ShellExecutor mainExecutor) { - return new PipTaskOrganizer(context, pipBoundsState, pipBoundsAlgorithm, + return new PipTaskOrganizer(context, + syncTransactionQueue, pipBoundsState, pipBoundsAlgorithm, menuPhoneController, pipAnimationController, pipSurfaceTransactionHelper, pipTransitionController, splitScreenOptional, displayController, pipUiEventLogger, shellTaskOrganizer, mainExecutor); 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 fb778e813adf..07686181649d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -31,6 +31,7 @@ import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.IUdfpsOverlayController; +import android.hardware.fingerprint.IUdfpsOverlayControllerCallback; import android.os.PowerManager; import android.os.RemoteException; import android.testing.AndroidTestingRunner; @@ -89,6 +90,8 @@ public class UdfpsControllerTest extends SysuiTestCase { private StatusBarStateController mStatusBarStateController; @Mock private StatusBar mStatusBar; + @Mock + private IUdfpsOverlayControllerCallback mUdfpsOverlayControllerCallback; private FakeExecutor mFgExecutor; @@ -152,7 +155,7 @@ public class UdfpsControllerTest extends SysuiTestCase { @Test public void dozeTimeTick() throws RemoteException { mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID, - IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD); + IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback); mFgExecutor.runAllReady(); mUdfpsController.dozeTimeTick(); verify(mUdfpsView).dozeTimeTick(); @@ -161,7 +164,7 @@ public class UdfpsControllerTest extends SysuiTestCase { @Test public void showUdfpsOverlay_addsViewToWindow() throws RemoteException { mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID, - IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD); + IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback); mFgExecutor.runAllReady(); verify(mWindowManager).addView(eq(mUdfpsView), any()); } @@ -169,7 +172,7 @@ public class UdfpsControllerTest extends SysuiTestCase { @Test public void hideUdfpsOverlay_removesViewFromWindow() throws RemoteException { mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID, - IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD); + IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback); mOverlayController.hideUdfpsOverlay(TEST_UDFPS_SENSOR_ID); mFgExecutor.runAllReady(); verify(mWindowManager).removeView(eq(mUdfpsView)); @@ -179,17 +182,20 @@ public class UdfpsControllerTest extends SysuiTestCase { 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, - IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD); + IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback); 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()); @@ -202,7 +208,7 @@ public class UdfpsControllerTest extends SysuiTestCase { public void aodInterrupt() throws RemoteException { // GIVEN that the overlay is showing mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID, - IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD); + IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback); mFgExecutor.runAllReady(); // WHEN fingerprint is requested because of AOD interrupt mUdfpsController.onAodInterrupt(0, 0, 2f, 3f); @@ -218,7 +224,7 @@ public class UdfpsControllerTest extends SysuiTestCase { public void cancelAodInterrupt() throws RemoteException { // GIVEN AOD interrupt mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID, - IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD); + IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback); mFgExecutor.runAllReady(); mUdfpsController.onAodInterrupt(0, 0, 0f, 0f); // WHEN it is cancelled @@ -231,7 +237,7 @@ public class UdfpsControllerTest extends SysuiTestCase { public void aodInterruptTimeout() throws RemoteException { // GIVEN AOD interrupt mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID, - IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD); + IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback); mFgExecutor.runAllReady(); mUdfpsController.onAodInterrupt(0, 0, 0f, 0f); // WHEN it times out @@ -244,7 +250,7 @@ public class UdfpsControllerTest extends SysuiTestCase { @Test public void registersAndUnregistersViewForCallbacks() throws RemoteException { mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID, - IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD); + IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback); mFgExecutor.runAllReady(); verify(mStatusBarStateController).addCallback(mUdfpsController.mStatusBarStateListener); verify(mStatusBar).addExpansionChangedListener( diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java new file mode 100644 index 000000000000..fce02174a1e0 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java @@ -0,0 +1,137 @@ +/* + * 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.people.widget; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.os.UserHandle; +import android.service.notification.NotificationListenerService; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper.RunWithLooper; + +import androidx.test.filters.SmallTest; + +import com.android.internal.statusbar.IStatusBarService; +import com.android.internal.statusbar.NotificationVisibility; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; + +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; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@RunWithLooper +public class LaunchConversationActivityTest extends SysuiTestCase { + private static final String EMPTY_STRING = ""; + private static final String PACKAGE_NAME = "com.android.systemui.tests"; + private static final String NOTIF_KEY = "notifKey"; + private static final String NOTIF_KEY_NO_ENTRY = "notifKeyNoEntry"; + private static final String NOTIF_KEY_NO_RANKING = "notifKeyNoRanking"; + + + private static final UserHandle USER_HANDLE = UserHandle.of(0); + private static final int NOTIF_COUNT = 10; + private static final int NOTIF_RANK = 2; + + private LaunchConversationActivity mActivity; + + @Mock + private NotificationEntryManager mNotificationEntryManager; + @Mock + private IStatusBarService mIStatusBarService; + @Mock + private NotificationEntry mNotifEntry; + @Mock + private NotificationEntry mNotifEntryNoRanking; + @Mock + private NotificationListenerService.Ranking mRanking; + + @Captor + private ArgumentCaptor<NotificationVisibility> mNotificationVisibilityCaptor; + + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mActivity = new LaunchConversationActivity(mNotificationEntryManager); + + when(mNotificationEntryManager.getActiveNotificationsCount()).thenReturn(NOTIF_COUNT); + when(mNotificationEntryManager.getPendingOrActiveNotif(NOTIF_KEY)).thenReturn(mNotifEntry); + when(mNotificationEntryManager.getPendingOrActiveNotif(NOTIF_KEY_NO_ENTRY)) + .thenReturn(null); + when(mNotificationEntryManager.getPendingOrActiveNotif(NOTIF_KEY_NO_RANKING)) + .thenReturn(mNotifEntryNoRanking); + when(mNotifEntry.getRanking()).thenReturn(mRanking); + when(mNotifEntryNoRanking.getRanking()).thenReturn(null); + when(mRanking.getRank()).thenReturn(NOTIF_RANK); + } + + @Test + public void testDoNotClearNotificationIfNoKey() throws Exception { + mActivity.clearNotificationIfPresent(mIStatusBarService, + EMPTY_STRING, PACKAGE_NAME, USER_HANDLE); + + verify(mIStatusBarService, never()).onNotificationClear( + any(), anyInt(), any(), anyInt(), anyInt(), any()); + } + + @Test + public void testDoNotClearNotificationIfNoNotificationEntry() throws Exception { + mActivity.clearNotificationIfPresent(mIStatusBarService, + NOTIF_KEY_NO_ENTRY, PACKAGE_NAME, USER_HANDLE); + + verify(mIStatusBarService, never()).onNotificationClear( + any(), anyInt(), any(), anyInt(), anyInt(), any()); + } + + @Test + public void testDoNotClearNotificationIfNoRanking() throws Exception { + mActivity.clearNotificationIfPresent(mIStatusBarService, + NOTIF_KEY_NO_RANKING, PACKAGE_NAME, USER_HANDLE); + + verify(mIStatusBarService, never()).onNotificationClear( + any(), anyInt(), any(), anyInt(), anyInt(), any()); + } + + @Test + public void testClearNotification() throws Exception { + mActivity.clearNotificationIfPresent(mIStatusBarService, + NOTIF_KEY, PACKAGE_NAME, USER_HANDLE); + + verify(mIStatusBarService, times(1)).onNotificationClear(any(), + anyInt(), any(), anyInt(), anyInt(), mNotificationVisibilityCaptor.capture()); + + NotificationVisibility nv = mNotificationVisibilityCaptor.getValue(); + assertThat(nv.count).isEqualTo(NOTIF_COUNT); + assertThat(nv.rank).isEqualTo(NOTIF_RANK); + } + +} 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 800d8593035d..f60fa099feaa 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 @@ package com.android.systemui.people.widget; 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.Notification; 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 android.testing.AndroidTestingRunner; 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.Captor; 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 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { 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 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { @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 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { 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 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { @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 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { @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 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { @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 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { @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 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { @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 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { @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 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { 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 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { @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 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { @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 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { } @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 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { @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 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { @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 class PeopleSpaceWidgetManagerTest extends SysuiTestCase { 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 class PeopleSpaceWidgetManagerTest extends SysuiTestCase { 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 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { @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 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { 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 000000000000..998e070009cc --- /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 6d2b8e415e96..25104b8b1d20 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.systemui.statusbar.phone.StatusBar; 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 @@ public class OverviewProxyServiceTest extends SysuiTestCase { @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 @@ public class OverviewProxyServiceTest extends SysuiTestCase { 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/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java index 21368d6d5309..b1f1b5e78b5c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java @@ -542,7 +542,7 @@ public class ScrimControllerTest extends SysuiTestCase { Assert.assertEquals(ScrimController.BUSY_SCRIM_ALPHA, mScrimBehind.getViewAlpha(), 0.0f); // Bubble scrim should be visible - Assert.assertEquals(ScrimController.BUSY_SCRIM_ALPHA, + Assert.assertEquals(ScrimController.BUBBLE_SCRIM_ALPHA, mScrimForBubble.getViewAlpha(), 0.0f); } 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 b1b71ccba8ce..999d2822c928 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; 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 @@ public class NetworkControllerBaseTest extends SysuiTestCase { protected NetworkControllerImpl mNetworkController; protected MobileSignalController mMobileSignalController; - protected PhoneStateListener mPhoneStateListener; protected SignalStrength mSignalStrength; protected ServiceState mServiceState; protected TelephonyDisplayInfo mTelephonyDisplayInfo; @@ -250,8 +249,6 @@ public class NetworkControllerBaseTest extends SysuiTestCase { 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 @@ public class NetworkControllerBaseTest extends SysuiTestCase { 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 @@ public class NetworkControllerBaseTest extends SysuiTestCase { 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/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java index f1fc0b7723fc..9b9937b9e260 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java @@ -955,8 +955,8 @@ public class BubblesTest extends SysuiTestCase { @Test public void testNotifyShadeSuppressionChange_notificationDismiss() { - Bubbles.NotificationSuppressionChangedListener listener = - mock(Bubbles.NotificationSuppressionChangedListener.class); + Bubbles.SuppressionChangedListener listener = + mock(Bubbles.SuppressionChangedListener.class); mBubbleData.setSuppressionChangedListener(listener); mEntryListener.onPendingEntryAdded(mRow.getEntry()); @@ -979,8 +979,8 @@ public class BubblesTest extends SysuiTestCase { @Test public void testNotifyShadeSuppressionChange_bubbleExpanded() { - Bubbles.NotificationSuppressionChangedListener listener = - mock(Bubbles.NotificationSuppressionChangedListener.class); + Bubbles.SuppressionChangedListener listener = + mock(Bubbles.SuppressionChangedListener.class); mBubbleData.setSuppressionChangedListener(listener); mEntryListener.onPendingEntryAdded(mRow.getEntry()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java index 9e10b21ce3b7..b0ec628b638b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java @@ -789,8 +789,8 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { @Test public void testNotifyShadeSuppressionChange_notificationDismiss() { - Bubbles.NotificationSuppressionChangedListener listener = - mock(Bubbles.NotificationSuppressionChangedListener.class); + Bubbles.SuppressionChangedListener listener = + mock(Bubbles.SuppressionChangedListener.class); mBubbleData.setSuppressionChangedListener(listener); mEntryListener.onEntryAdded(mRow.getEntry()); @@ -812,8 +812,8 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { @Test public void testNotifyShadeSuppressionChange_bubbleExpanded() { - Bubbles.NotificationSuppressionChangedListener listener = - mock(Bubbles.NotificationSuppressionChangedListener.class); + Bubbles.SuppressionChangedListener listener = + mock(Bubbles.SuppressionChangedListener.class); mBubbleData.setSuppressionChangedListener(listener); mEntryListener.onEntryAdded(mRow.getEntry()); diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java index 39efe731ce8a..806a25a748e2 100644 --- a/rs/java/android/renderscript/RenderScript.java +++ b/rs/java/android/renderscript/RenderScript.java @@ -1363,13 +1363,6 @@ public class RenderScript { mApplicationContext = ctx.getApplicationContext(); } mRWLock = new ReentrantReadWriteLock(); - try { - registerNativeAllocation.invoke(sRuntime, 4 * 1024 * 1024); // 4MB for GC sake - } catch (Exception e) { - Log.e(RenderScript.LOG_TAG, "Couldn't invoke registerNativeAllocation:" + e); - throw new RSRuntimeException("Couldn't invoke registerNativeAllocation:" + e); - } - } /** diff --git a/services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java b/services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java new file mode 100644 index 000000000000..715697d82cad --- /dev/null +++ b/services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java @@ -0,0 +1,293 @@ +/* + * 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.autofill; + +import static android.service.autofill.FillRequest.INVALID_REQUEST_ID; + +import static com.android.server.autofill.Helper.sVerbose; + +import android.annotation.Nullable; +import android.annotation.UserIdInt; +import android.app.AppGlobals; +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.graphics.drawable.Drawable; +import android.os.Handler; +import android.os.ICancellationSignal; +import android.os.RemoteException; +import android.service.autofill.Dataset; +import android.service.autofill.FillResponse; +import android.service.autofill.IFillCallback; +import android.service.autofill.SaveInfo; +import android.text.TextUtils; +import android.text.format.DateUtils; +import android.util.Slog; +import android.view.autofill.AutofillId; +import android.view.autofill.IAutoFillManagerClient; +import android.view.inputmethod.InlineSuggestionsRequest; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.infra.AndroidFuture; + +import java.util.List; +import java.util.concurrent.CancellationException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Maintains a client suggestions session with the + * {@link android.view.autofill.AutofillRequestCallback} through the {@link IAutoFillManagerClient}. + * + */ +final class ClientSuggestionsSession { + + private static final String TAG = "ClientSuggestionsSession"; + private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 15 * DateUtils.SECOND_IN_MILLIS; + + private final int mSessionId; + private final IAutoFillManagerClient mClient; + private final Handler mHandler; + private final ComponentName mComponentName; + + private final RemoteFillService.FillServiceCallbacks mCallbacks; + + private final Object mLock = new Object(); + @GuardedBy("mLock") + private AndroidFuture<FillResponse> mPendingFillRequest; + @GuardedBy("mLock") + private int mPendingFillRequestId = INVALID_REQUEST_ID; + + ClientSuggestionsSession(int sessionId, IAutoFillManagerClient client, Handler handler, + ComponentName componentName, RemoteFillService.FillServiceCallbacks callbacks) { + mSessionId = sessionId; + mClient = client; + mHandler = handler; + mComponentName = componentName; + mCallbacks = callbacks; + } + + void onFillRequest(int requestId, InlineSuggestionsRequest inlineRequest, int flags) { + final AtomicReference<ICancellationSignal> cancellationSink = new AtomicReference<>(); + final AtomicReference<AndroidFuture<FillResponse>> futureRef = new AtomicReference<>(); + final AndroidFuture<FillResponse> fillRequest = new AndroidFuture<>(); + + mHandler.post(() -> { + if (sVerbose) { + Slog.v(TAG, "calling onFillRequest() for id=" + requestId); + } + + try { + mClient.requestFillFromClient(requestId, inlineRequest, + new FillCallbackImpl(fillRequest, futureRef, cancellationSink)); + } catch (RemoteException e) { + fillRequest.completeExceptionally(e); + } + }); + + fillRequest.orTimeout(TIMEOUT_REMOTE_REQUEST_MILLIS, TimeUnit.MILLISECONDS); + futureRef.set(fillRequest); + + synchronized (mLock) { + mPendingFillRequest = fillRequest; + mPendingFillRequestId = requestId; + } + + fillRequest.whenComplete((res, err) -> mHandler.post(() -> { + synchronized (mLock) { + mPendingFillRequest = null; + mPendingFillRequestId = INVALID_REQUEST_ID; + } + if (err == null) { + processAutofillId(res); + mCallbacks.onFillRequestSuccess(requestId, res, + mComponentName.getPackageName(), flags); + } else { + Slog.e(TAG, "Error calling on client fill request", err); + if (err instanceof TimeoutException) { + dispatchCancellationSignal(cancellationSink.get()); + mCallbacks.onFillRequestTimeout(requestId); + } else if (err instanceof CancellationException) { + dispatchCancellationSignal(cancellationSink.get()); + } else { + mCallbacks.onFillRequestFailure(requestId, err.getMessage()); + } + } + })); + } + + /** + * Gets the application info for the component. + */ + @Nullable + static ApplicationInfo getAppInfo(ComponentName comp, @UserIdInt int userId) { + try { + ApplicationInfo si = AppGlobals.getPackageManager().getApplicationInfo( + comp.getPackageName(), + PackageManager.GET_META_DATA, + userId); + if (si != null) { + return si; + } + } catch (RemoteException e) { + } + return null; + } + + /** + * Gets the user-visible name of the application. + */ + @Nullable + @GuardedBy("mLock") + static CharSequence getAppLabelLocked(Context context, ApplicationInfo appInfo) { + return appInfo == null ? null : appInfo.loadSafeLabel( + context.getPackageManager(), 0 /* do not ellipsize */, + TextUtils.SAFE_STRING_FLAG_FIRST_LINE | TextUtils.SAFE_STRING_FLAG_TRIM); + } + + /** + * Gets the user-visible icon of the application. + */ + @Nullable + @GuardedBy("mLock") + static Drawable getAppIconLocked(Context context, ApplicationInfo appInfo) { + return appInfo == null ? null : appInfo.loadIcon(context.getPackageManager()); + } + + int cancelCurrentRequest() { + synchronized (mLock) { + return mPendingFillRequest != null && mPendingFillRequest.cancel(false) + ? mPendingFillRequestId + : INVALID_REQUEST_ID; + } + } + + /** + * The {@link AutofillId} which the client gets from its view is not contain the session id, + * but Autofill framework is using the {@link AutofillId} with a session id. So before using + * those ids in the Autofill framework, applies the current session id. + * + * @param res which response need to apply for a session id + */ + private void processAutofillId(FillResponse res) { + if (res == null) { + return; + } + + final List<Dataset> datasets = res.getDatasets(); + if (datasets != null && !datasets.isEmpty()) { + for (int i = 0; i < datasets.size(); i++) { + final Dataset dataset = datasets.get(i); + if (dataset != null) { + applySessionId(dataset.getFieldIds()); + } + } + } + + final SaveInfo saveInfo = res.getSaveInfo(); + if (saveInfo != null) { + applySessionId(saveInfo.getOptionalIds()); + applySessionId(saveInfo.getRequiredIds()); + applySessionId(saveInfo.getSanitizerValues()); + applySessionId(saveInfo.getTriggerId()); + } + } + + private void applySessionId(List<AutofillId> ids) { + if (ids == null || ids.isEmpty()) { + return; + } + + for (int i = 0; i < ids.size(); i++) { + applySessionId(ids.get(i)); + } + } + + private void applySessionId(AutofillId[][] ids) { + if (ids == null) { + return; + } + for (int i = 0; i < ids.length; i++) { + applySessionId(ids[i]); + } + } + + private void applySessionId(AutofillId[] ids) { + if (ids == null) { + return; + } + for (int i = 0; i < ids.length; i++) { + applySessionId(ids[i]); + } + } + + private void applySessionId(AutofillId id) { + if (id == null) { + return; + } + id.setSessionId(mSessionId); + } + + private void dispatchCancellationSignal(@Nullable ICancellationSignal signal) { + if (signal == null) { + return; + } + try { + signal.cancel(); + } catch (RemoteException e) { + Slog.e(TAG, "Error requesting a cancellation", e); + } + } + + private class FillCallbackImpl extends IFillCallback.Stub { + final AndroidFuture<FillResponse> mFillRequest; + final AtomicReference<AndroidFuture<FillResponse>> mFutureRef; + final AtomicReference<ICancellationSignal> mCancellationSink; + + FillCallbackImpl(AndroidFuture<FillResponse> fillRequest, + AtomicReference<AndroidFuture<FillResponse>> futureRef, + AtomicReference<ICancellationSignal> cancellationSink) { + mFillRequest = fillRequest; + mFutureRef = futureRef; + mCancellationSink = cancellationSink; + } + + @Override + public void onCancellable(ICancellationSignal cancellation) { + AndroidFuture<FillResponse> future = mFutureRef.get(); + if (future != null && future.isCancelled()) { + dispatchCancellationSignal(cancellation); + } else { + mCancellationSink.set(cancellation); + } + } + + @Override + public void onSuccess(FillResponse response) { + mFillRequest.complete(response); + } + + @Override + public void onFailure(int requestId, CharSequence message) { + String errorMessage = message == null ? "" : String.valueOf(message); + mFillRequest.completeExceptionally( + new RuntimeException(errorMessage)); + } + } +} diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 6d72ca7bae25..b7f736e4dc33 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -26,6 +26,7 @@ import static android.view.autofill.AutofillManager.ACTION_START_SESSION; import static android.view.autofill.AutofillManager.ACTION_VALUE_CHANGED; import static android.view.autofill.AutofillManager.ACTION_VIEW_ENTERED; import static android.view.autofill.AutofillManager.ACTION_VIEW_EXITED; +import static android.view.autofill.AutofillManager.FLAG_ENABLED_CLIENT_SUGGESTIONS; import static android.view.autofill.AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM; import static android.view.autofill.AutofillManager.getSmartSuggestionModeToString; @@ -53,6 +54,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentSender; +import android.content.pm.ApplicationInfo; import android.graphics.Bitmap; import android.graphics.Rect; import android.graphics.drawable.Drawable; @@ -91,6 +93,7 @@ import android.util.ArrayMap; 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 +225,13 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState 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 +340,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState @GuardedBy("mLock") private ArrayList<AutofillId> mAugmentedAutofillableIds; - @Nullable + @NonNull private final AutofillInlineSessionController mInlineSessionController; /** @@ -338,6 +348,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState */ private final AssistDataReceiverImpl mAssistReceiver = new AssistDataReceiverImpl(); + @Nullable + private ClientSuggestionsSession mClientSuggestionsSession; + void onSwitchInputMethodLocked() { // One caveat is that for the case where the focus is on a field for which regular autofill // returns null, and augmented autofill is triggered, and then the user switches the input @@ -408,6 +421,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState /** Whether the current {@link FillResponse} is expired. */ @GuardedBy("mLock") private boolean mExpiredResponse; + + /** Whether the client is using {@link android.view.autofill.AutofillRequestCallback}. */ + @GuardedBy("mLock") + private boolean mClientSuggestionsEnabled; } /** @@ -720,30 +737,39 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } /** - * Cancels the last request sent to the {@link #mRemoteFillService}. + * Cancels the last request sent to the {@link #mRemoteFillService} or the + * {@link #mClientSuggestionsSession}. */ @GuardedBy("mLock") private void cancelCurrentRequestLocked() { - if (mRemoteFillService == null) { - wtf(null, "cancelCurrentRequestLocked() called without a remote service. " - + "mForAugmentedAutofillOnly: %s", mSessionFlags.mAugmentedAutofillOnly); + if (mRemoteFillService == null && mClientSuggestionsSession == null) { + wtf(null, "cancelCurrentRequestLocked() called without a remote service or a " + + "client suggestions session. mForAugmentedAutofillOnly: %s", + mSessionFlags.mAugmentedAutofillOnly); return; } - final int canceledRequest = mRemoteFillService.cancelCurrentRequest(); - // Remove the FillContext as there will never be a response for the service - if (canceledRequest != INVALID_REQUEST_ID && mContexts != null) { - final int numContexts = mContexts.size(); + if (mRemoteFillService != null) { + final int canceledRequest = mRemoteFillService.cancelCurrentRequest(); - // It is most likely the last context, hence search backwards - for (int i = numContexts - 1; i >= 0; i--) { - if (mContexts.get(i).getRequestId() == canceledRequest) { - if (sDebug) Slog.d(TAG, "cancelCurrentRequest(): id = " + canceledRequest); - mContexts.remove(i); - break; + // Remove the FillContext as there will never be a response for the service + if (canceledRequest != INVALID_REQUEST_ID && mContexts != null) { + final int numContexts = mContexts.size(); + + // It is most likely the last context, hence search backwards + for (int i = numContexts - 1; i >= 0; i--) { + if (mContexts.get(i).getRequestId() == canceledRequest) { + if (sDebug) Slog.d(TAG, "cancelCurrentRequest(): id = " + canceledRequest); + mContexts.remove(i); + break; + } } } } + + if (mClientSuggestionsSession != null) { + mClientSuggestionsSession.cancelCurrentRequest(); + } } private boolean isViewFocusedLocked(int flags) { @@ -808,33 +834,57 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // structure is taken. This causes only one fill request per burst of focus changes. cancelCurrentRequestLocked(); - // Only ask IME to create inline suggestions request if Autofill provider supports it and - // the render service is available except the autofill is triggered manually and the view - // is also not focused. + // Only ask IME to create inline suggestions request when + // 1. Autofill provider supports it or client enabled client suggestions. + // 2. The render service is available. + // 3. The view is focused. (The view may not be focused if the autofill is triggered + // manually.) final RemoteInlineSuggestionRenderService remoteRenderService = mService.getRemoteInlineSuggestionRenderServiceLocked(); - if (mSessionFlags.mInlineSupportedByService + if ((mSessionFlags.mInlineSupportedByService || mSessionFlags.mClientSuggestionsEnabled) && remoteRenderService != null && isViewFocusedLocked(flags)) { - Consumer<InlineSuggestionsRequest> inlineSuggestionsRequestConsumer = - mAssistReceiver.newAutofillRequestLocked(viewState, - /* isInlineRequest= */ true); + Consumer<InlineSuggestionsRequest> inlineSuggestionsRequestConsumer; + if (mSessionFlags.mClientSuggestionsEnabled) { + final int finalRequestId = requestId; + inlineSuggestionsRequestConsumer = (inlineSuggestionsRequest) -> { + // Using client suggestions + synchronized (mLock) { + onClientFillRequestLocked(finalRequestId, inlineSuggestionsRequest); + } + viewState.resetState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST); + }; + } else { + inlineSuggestionsRequestConsumer = mAssistReceiver.newAutofillRequestLocked( + viewState, /* 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) ); viewState.setState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST); } + } else if (mSessionFlags.mClientSuggestionsEnabled) { + // Request client suggestions for the dropdown mode + onClientFillRequestLocked(requestId, null); } else { mAssistReceiver.newAutofillRequestLocked(viewState, /* isInlineRequest= */ false); } + if (mSessionFlags.mClientSuggestionsEnabled) { + // Using client suggestions, unnecessary request AssistStructure + return; + } + // Now request the assist structure data. try { final Bundle receiverExtras = new Bundle(); @@ -884,10 +934,13 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mComponentName = componentName; mCompatMode = compatMode; mSessionState = STATE_ACTIVE; + synchronized (mLock) { mSessionFlags = new SessionFlags(); mSessionFlags.mAugmentedAutofillOnly = forAugmentedAutofillOnly; mSessionFlags.mInlineSupportedByService = mService.isInlineSuggestionsEnabledLocked(); + mSessionFlags.mClientSuggestionsEnabled = + (mFlags & FLAG_ENABLED_CLIENT_SUGGESTIONS) != 0; setClientLocked(client); } @@ -3019,13 +3072,22 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState filterText = value.getTextValue().toString(); } - final CharSequence serviceLabel; - final Drawable serviceIcon; + final CharSequence targetLabel; + final Drawable targetIcon; synchronized (mLock) { - serviceLabel = mService.getServiceLabelLocked(); - serviceIcon = mService.getServiceIconLocked(); + if (mSessionFlags.mClientSuggestionsEnabled) { + final ApplicationInfo appInfo = ClientSuggestionsSession.getAppInfo(mComponentName, + mService.getUserId()); + targetLabel = ClientSuggestionsSession.getAppLabelLocked( + mService.getMaster().getContext(), appInfo); + targetIcon = ClientSuggestionsSession.getAppIconLocked( + mService.getMaster().getContext(), appInfo); + } else { + targetLabel = mService.getServiceLabelLocked(); + targetIcon = mService.getServiceIconLocked(); + } } - if (serviceLabel == null || serviceIcon == null) { + if (targetLabel == null || targetIcon == null) { wtf(null, "onFillReady(): no service label or icon"); return; } @@ -3045,7 +3107,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState getUiForShowing().showFillUi(filledId, response, filterText, mService.getServicePackageName(), mComponentName, - serviceLabel, serviceIcon, this, id, mCompatMode); + targetLabel, targetIcon, this, id, mCompatMode); mService.logDatasetShown(id, mClientState); @@ -3668,11 +3730,27 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState 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 { @@ -3685,6 +3763,21 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } } + @GuardedBy("mLock") + private void onClientFillRequestLocked(int requestId, + InlineSuggestionsRequest inlineSuggestionsRequest) { + if (mClientSuggestionsSession == null) { + mClientSuggestionsSession = new ClientSuggestionsSession(id, mClient, mHandler, + mComponentName, this); + } + + if (mContexts == null) { + mContexts = new ArrayList<>(1); + } + + mClientSuggestionsSession.onFillRequest(requestId, inlineSuggestionsRequest, mFlags); + } + /** * The result of checking whether to show the save dialog, when session can be saved. * diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java index 21cae453d702..52237c934797 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 com.android.internal.util.function.pooled.PooledLambda.obtainRunna 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 @@ public class CompanionDeviceManagerService extends SystemService implements Bind checkCallerIsSystemOr(callingPackage); int userId = getCallingUserId(); checkUsesFeature(callingPackage, userId); + checkProfilePermissions(request); mFindDeviceCallback = callback; mRequest = request; @@ -519,6 +521,21 @@ public class CompanionDeviceManagerService extends SystemService implements Bind } } + 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 @@ public class CompanionDeviceManagerService extends SystemService implements Bind 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 99ce2db006ce..8ccfad6fe061 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -223,7 +223,6 @@ filegroup { "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/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java index 342208c8a32b..c2957780c9d7 100644 --- a/services/core/java/android/content/pm/PackageManagerInternal.java +++ b/services/core/java/android/content/pm/PackageManagerInternal.java @@ -69,7 +69,6 @@ public abstract class PackageManagerInternal { PACKAGE_BROWSER, PACKAGE_SYSTEM_TEXT_CLASSIFIER, PACKAGE_PERMISSION_CONTROLLER, - PACKAGE_WELLBEING, PACKAGE_DOCUMENTER, PACKAGE_CONFIGURATOR, PACKAGE_INCIDENT_REPORT_APPROVER, diff --git a/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java index fe3042d9da54..d83e2fd2090d 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.Build; 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 com.android.internal.util.XmlUtils; 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 @@ public class BootReceiver extends BroadcastReceiver { 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 @@ public class BootReceiver extends BroadcastReceiver { } }.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 4ca6f73755f0..9a5e4ca0068a 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -191,7 +191,6 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IBatteryStats; 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; @@ -200,10 +199,10 @@ import com.android.net.module.util.BaseNetdUnsolicitedEventListener; 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; @@ -1039,6 +1038,16 @@ public class ConnectivityService extends IConnectivityManager.Stub public IBatteryStats getBatteryStatsService() { return BatteryStatsService.getService(); } + + /** + * @see BatteryStatsManager + */ + public void reportNetworkInterfaceForTransports(Context context, String iface, + int[] transportTypes) { + final BatteryStatsManager batteryStats = + context.getSystemService(BatteryStatsManager.class); + batteryStats.reportNetworkInterfaceForTransports(iface, transportTypes); + } } public ConnectivityService(Context context) { @@ -1213,9 +1222,6 @@ public class ConnectivityService extends IConnectivityManager.Stub 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); @@ -1890,24 +1896,46 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + // 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 (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()) { + 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. + // 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) : NetworkState contains a copy of the + // 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.getNetworkState()); + result.add(nai.getNetworkStateSnapshot()); } } - return result.toArray(new NetworkState[result.size()]); + return result; } @Override @@ -5031,10 +5059,16 @@ public class ConnectivityService extends IConnectivityManager.Stub 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() { @@ -6257,13 +6291,13 @@ public class ConnectivityService extends IConnectivityManager.Stub oldLp != null ? oldLp.getAllInterfaceNames() : null, newLp != null ? newLp.getAllInterfaceNames() : null); if (!interfaceDiff.added.isEmpty()) { - final IBatteryStats bs = mDeps.getBatteryStatsService(); for (final String iface : interfaceDiff.added) { try { if (DBG) log("Adding iface " + iface + " to network " + netId); mNetd.networkAddInterface(netId, iface); wakeupModifyInterface(iface, caps, true); - bs.noteNetworkInterfaceForTransports(iface, caps.getTransportTypes()); + mDeps.reportNetworkInterfaceForTransports(mContext, iface, + caps.getTransportTypes()); } catch (Exception e) { loge("Exception adding interface: " + e); } @@ -6472,7 +6506,7 @@ public class ConnectivityService extends IConnectivityManager.Stub @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. @@ -6522,7 +6556,7 @@ public class ConnectivityService extends IConnectivityManager.Stub 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); @@ -7165,7 +7199,7 @@ public class ConnectivityService extends IConnectivityManager.Stub toUidRangeStableParcels(nri.getUids())); } } catch (RemoteException | ServiceSpecificException e) { - loge("Exception setting OEM network preference default network", e); + loge("Exception setting app default network", e); } } @@ -7252,7 +7286,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } 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. @@ -9050,7 +9084,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } final ArraySet<NetworkRequestInfo> nris = new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(preference); - updateDefaultNetworksForOemNetworkPreference(nris); + replaceDefaultNetworkRequestsForPreference(nris); mOemNetworkPreferences = preference; // TODO http://b/176496396 persist data to shared preferences. @@ -9058,12 +9092,12 @@ public class ConnectivityService extends IConnectivityManager.Stub try { listener.onComplete(); } catch (RemoteException e) { - loge("handleMessage.EVENT_SET_OEM_NETWORK_PREFERENCE failed", 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)); @@ -9149,6 +9183,14 @@ public class ConnectivityService extends IConnectivityManager.Stub 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}. */ @@ -9177,6 +9219,14 @@ public class ConnectivityService extends IConnectivityManager.Stub @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(); @@ -9185,7 +9235,10 @@ public class ConnectivityService extends IConnectivityManager.Stub 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 @@ -9225,7 +9278,11 @@ public class ConnectivityService extends IConnectivityManager.Stub + " 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); } @@ -9258,16 +9315,5 @@ public class ConnectivityService extends IConnectivityManager.Stub 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/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java index 2906ceebca58..906702866889 100644 --- a/services/core/java/com/android/server/IntentResolver.java +++ b/services/core/java/com/android/server/IntentResolver.java @@ -839,23 +839,34 @@ public abstract class IntentResolver<F, R extends Object> { } }; + // 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 f5c2aacaebb0..960922ed2192 100644 --- a/services/core/java/com/android/server/PackageWatchdog.java +++ b/services/core/java/com/android/server/PackageWatchdog.java @@ -182,6 +182,9 @@ public class PackageWatchdog { 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 @@ public class PackageWatchdog { } } + @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 @@ public class PackageWatchdog { } } + 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/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 5a5f1a3f3723..978bd643f9b7 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.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.telephony.data.ApnSetting; @@ -153,7 +154,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 class TelephonyRegistry extends ITelephonyRegistry.Stub { */ 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } if (events.contains( - PhoneStateListener.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED)) { + TelephonyCallback.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED)) { try { r.callback.onPhysicalChannelConfigChanged( mPhysicalChannelConfigs); @@ -1156,7 +1157,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { // 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { .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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { * {@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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - 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 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - 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 8d5d3d939e4b..cd3892da43e4 100644 --- a/services/core/java/com/android/server/VcnManagementService.java +++ b/services/core/java/com/android/server/VcnManagementService.java @@ -16,6 +16,9 @@ package com.android.server; +import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; +import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE; +import static android.net.vcn.VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED; import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; @@ -35,7 +38,9 @@ import android.net.vcn.IVcnManagementService; 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.VcnManager.VcnStatusCode; import android.net.vcn.VcnUnderlyingNetworkPolicy; import android.net.wifi.WifiInfo; import android.os.Binder; @@ -313,8 +318,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { /** Gets the subId indicated by the given {@link WifiInfo}. */ public int getSubIdForWifiInfo(@NonNull WifiInfo wifiInfo) { - // TODO(b/178501049): use the subId indicated by WifiInfo#getSubscriptionId - return SubscriptionManager.INVALID_SUBSCRIPTION_ID; + return wifiInfo.getSubscriptionId(); } /** Creates a new LocationPermissionChecker for the provided Context. */ @@ -420,6 +424,11 @@ public class VcnManagementService extends IVcnManagementService.Stub { // Carrier App manually removing/adding a VcnConfig. if (mVcns.get(uuidToTeardown) == instanceToTeardown) { stopVcnLocked(uuidToTeardown); + + // TODO(b/181789060): invoke asynchronously after Vcn notifies + // through VcnCallback + notifyAllPermissionedStatusCallbacksLocked( + uuidToTeardown, VCN_STATUS_CODE_INACTIVE); } } }, instanceToTeardown, CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); @@ -454,6 +463,17 @@ public class VcnManagementService extends IVcnManagementService.Stub { } @GuardedBy("mLock") + private void notifyAllPermissionedStatusCallbacksLocked( + @NonNull ParcelUuid subGroup, @VcnStatusCode int statusCode) { + for (final VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) { + if (isCallbackPermissioned(cbInfo, subGroup)) { + Binder.withCleanCallingIdentity( + () -> cbInfo.mCallback.onVcnStatusChanged(statusCode)); + } + } + } + + @GuardedBy("mLock") private void startVcnLocked(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) { Slog.v(TAG, "Starting VCN config for subGrp: " + subscriptionGroup); @@ -469,6 +489,9 @@ public class VcnManagementService extends IVcnManagementService.Stub { // Now that a new VCN has started, notify all registered listeners to refresh their // UnderlyingNetworkPolicy. notifyAllPolicyListenersLocked(); + + // TODO(b/181789060): invoke asynchronously after Vcn notifies through VcnCallback + notifyAllPermissionedStatusCallbacksLocked(subscriptionGroup, VCN_STATUS_CODE_ACTIVE); } @GuardedBy("mLock") @@ -477,7 +500,16 @@ public class VcnManagementService extends IVcnManagementService.Stub { Slog.v(TAG, "Starting or updating VCN config for subGrp: " + subscriptionGroup); if (mVcns.containsKey(subscriptionGroup)) { - mVcns.get(subscriptionGroup).updateConfig(config); + final Vcn vcn = mVcns.get(subscriptionGroup); + final boolean isActive = vcn.isActive(); + vcn.updateConfig(config); + + // Only notify VcnStatusCallbacks if this VCN was previously in Safe Mode + if (!isActive) { + // TODO(b/181789060): invoke asynchronously after Vcn notifies through VcnCallback + notifyAllPermissionedStatusCallbacksLocked( + subscriptionGroup, VCN_STATUS_CODE_ACTIVE); + } } else { startVcnLocked(subscriptionGroup, config); } @@ -530,9 +562,17 @@ public class VcnManagementService extends IVcnManagementService.Stub { Binder.withCleanCallingIdentity(() -> { synchronized (mLock) { mConfigs.remove(subscriptionGroup); + final boolean vcnExists = mVcns.containsKey(subscriptionGroup); stopVcnLocked(subscriptionGroup); + if (vcnExists) { + // TODO(b/181789060): invoke asynchronously after Vcn notifies through + // VcnCallback + notifyAllPermissionedStatusCallbacksLocked( + subscriptionGroup, VCN_STATUS_CODE_NOT_CONFIGURED); + } + writeConfigsToDiskLocked(); } }); @@ -603,18 +643,20 @@ public class VcnManagementService extends IVcnManagementService.Stub { android.Manifest.permission.NETWORK_FACTORY, "Must have permission NETWORK_FACTORY to register a policy listener"); - PolicyListenerBinderDeath listenerBinderDeath = new PolicyListenerBinderDeath(listener); + Binder.withCleanCallingIdentity(() -> { + PolicyListenerBinderDeath listenerBinderDeath = new PolicyListenerBinderDeath(listener); - synchronized (mLock) { - mRegisteredPolicyListeners.put(listener.asBinder(), listenerBinderDeath); + synchronized (mLock) { + mRegisteredPolicyListeners.put(listener.asBinder(), listenerBinderDeath); - try { - listener.asBinder().linkToDeath(listenerBinderDeath, 0 /* flags */); - } catch (RemoteException e) { - // Remote binder already died - cleanup registered Listener - listenerBinderDeath.binderDied(); + try { + listener.asBinder().linkToDeath(listenerBinderDeath, 0 /* flags */); + } catch (RemoteException e) { + // Remote binder already died - cleanup registered Listener + listenerBinderDeath.binderDied(); + } } - } + }); } /** Removes the provided listener from receiving VcnUnderlyingNetworkPolicy updates. */ @@ -624,14 +666,31 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull IVcnUnderlyingNetworkPolicyListener listener) { requireNonNull(listener, "listener was null"); - synchronized (mLock) { - PolicyListenerBinderDeath listenerBinderDeath = - mRegisteredPolicyListeners.remove(listener.asBinder()); + Binder.withCleanCallingIdentity(() -> { + synchronized (mLock) { + PolicyListenerBinderDeath listenerBinderDeath = + mRegisteredPolicyListeners.remove(listener.asBinder()); - if (listenerBinderDeath != null) { - listener.asBinder().unlinkToDeath(listenerBinderDeath, 0 /* flags */); + if (listenerBinderDeath != null) { + listener.asBinder().unlinkToDeath(listenerBinderDeath, 0 /* flags */); + } } + }); + } + + private int getSubIdForNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) { + if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) + && networkCapabilities.getNetworkSpecifier() instanceof TelephonyNetworkSpecifier) { + TelephonyNetworkSpecifier telephonyNetworkSpecifier = + (TelephonyNetworkSpecifier) networkCapabilities.getNetworkSpecifier(); + return telephonyNetworkSpecifier.getSubscriptionId(); + } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) + && networkCapabilities.getTransportInfo() instanceof WifiInfo) { + WifiInfo wifiInfo = (WifiInfo) networkCapabilities.getTransportInfo(); + return mDeps.getSubIdForWifiInfo(wifiInfo); } + + return SubscriptionManager.INVALID_SUBSCRIPTION_ID; } /** @@ -651,51 +710,47 @@ public class VcnManagementService extends IVcnManagementService.Stub { "Must have permission NETWORK_FACTORY or be the SystemServer to get underlying" + " Network policies"); - // Defensive copy in case this call is in-process and the given NetworkCapabilities mutates - networkCapabilities = new NetworkCapabilities(networkCapabilities); + return Binder.withCleanCallingIdentity(() -> { + // Defensive copy in case this call is in-process and the given NetworkCapabilities + // mutates + final NetworkCapabilities ncCopy = new NetworkCapabilities(networkCapabilities); - int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; - if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) - && networkCapabilities.getNetworkSpecifier() instanceof TelephonyNetworkSpecifier) { - TelephonyNetworkSpecifier telephonyNetworkSpecifier = - (TelephonyNetworkSpecifier) networkCapabilities.getNetworkSpecifier(); - subId = telephonyNetworkSpecifier.getSubscriptionId(); - } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) - && networkCapabilities.getTransportInfo() instanceof WifiInfo) { - WifiInfo wifiInfo = (WifiInfo) networkCapabilities.getTransportInfo(); - subId = mDeps.getSubIdForWifiInfo(wifiInfo); - } - - boolean isVcnManagedNetwork = false; - boolean isRestrictedCarrierWifi = false; - if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - synchronized (mLock) { - ParcelUuid subGroup = mLastSnapshot.getGroupForSubId(subId); + final int subId = getSubIdForNetworkCapabilities(ncCopy); + boolean isVcnManagedNetwork = false; + boolean isRestrictedCarrierWifi = false; + if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + synchronized (mLock) { + ParcelUuid subGroup = mLastSnapshot.getGroupForSubId(subId); - Vcn vcn = mVcns.get(subGroup); - if (vcn != null) { - if (vcn.isActive()) { - isVcnManagedNetwork = true; - } + final Vcn vcn = mVcns.get(subGroup); + if (vcn != null) { + if (vcn.isActive()) { + isVcnManagedNetwork = true; + } - if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { - // Carrier WiFi always restricted if VCN exists (even in safe mode). - isRestrictedCarrierWifi = true; + if (ncCopy.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { + // Carrier WiFi always restricted if VCN exists (even in safe mode). + isRestrictedCarrierWifi = true; + } } } } - } - if (isVcnManagedNetwork) { - networkCapabilities.removeCapability( - NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); - } + final NetworkCapabilities.Builder ncBuilder = new NetworkCapabilities.Builder(ncCopy); - if (isRestrictedCarrierWifi) { - networkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); - } + if (isVcnManagedNetwork) { + ncBuilder.removeCapability( + NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); + } + + if (isRestrictedCarrierWifi) { + ncBuilder.removeCapability( + NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); + } - return new VcnUnderlyingNetworkPolicy(false /* isTearDownRequested */, networkCapabilities); + return new VcnUnderlyingNetworkPolicy( + false /* isTearDownRequested */, ncBuilder.build()); + }); } /** Binder death recipient used to remove registered VcnStatusCallbacks. */ @@ -724,6 +779,26 @@ public class VcnManagementService extends IVcnManagementService.Stub { } } + 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 +833,27 @@ public class VcnManagementService extends IVcnManagementService.Stub { } 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 +902,6 @@ public class VcnManagementService extends IVcnManagementService.Stub { 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) { @@ -835,16 +911,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { } notifyAllPolicyListenersLocked(); - - // Notify all registered StatusCallbacks for this subGroup - for (VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) { - if (isCallbackPermissioned(cbInfo)) { - Binder.withCleanCallingIdentity( - () -> - cbInfo.mCallback.onVcnStatusChanged( - VCN_STATUS_CODE_SAFE_MODE)); - } - } + notifyAllPermissionedStatusCallbacksLocked(mSubGroup, VCN_STATUS_CODE_SAFE_MODE); } } @@ -862,7 +929,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { // 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/Watchdog.java b/services/core/java/com/android/server/Watchdog.java index 5b5043141315..963664149b38 100644 --- a/services/core/java/com/android/server/Watchdog.java +++ b/services/core/java/com/android/server/Watchdog.java @@ -75,7 +75,8 @@ public class Watchdog { // can trigger the watchdog. // Note 2: The debug value is already below the wait time in ZygoteConnection. Wrapped // applications may not work with a debug build. CTS will fail. - private static final long DEFAULT_TIMEOUT = DB ? 10 * 1000 : 60 * 1000; + private static final long DEFAULT_TIMEOUT = + (DB ? 10 * 1000 : 60 * 1000) * Build.HW_TIMEOUT_MULTIPLIER; private static final long CHECK_INTERVAL = DEFAULT_TIMEOUT / 2; // These are temporally ordered: larger values as lateness increases diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 277cb8c877dd..f768db1d0821 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -178,14 +178,14 @@ public final class ActiveServices { private static final boolean SHOW_DUNGEON_NOTIFICATION = false; // How long we wait for a service to finish executing. - static final int SERVICE_TIMEOUT = 20*1000; + static final int SERVICE_TIMEOUT = 20 * 1000 * Build.HW_TIMEOUT_MULTIPLIER; // How long we wait for a service to finish executing. static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10; // How long the startForegroundService() grace period is to get around to // calling startForeground() before we ANR + stop it. - static final int SERVICE_START_FOREGROUND_TIMEOUT = 10*1000; + static final int SERVICE_START_FOREGROUND_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER; final ActivityManagerService mAm; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 874e5272764c..4073eba01e69 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -44,13 +44,12 @@ import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.FactoryTest.FACTORY_TEST_OFF; -import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; +import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL; import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH; 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; @@ -68,6 +67,7 @@ import static android.os.Process.SHELL_UID; import static android.os.Process.SIGNAL_USR1; import static android.os.Process.SYSTEM_UID; import static android.os.Process.THREAD_PRIORITY_FOREGROUND; +import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST; import static android.os.Process.ZYGOTE_POLICY_FLAG_BATCH_LAUNCH; import static android.os.Process.ZYGOTE_POLICY_FLAG_EMPTY; import static android.os.Process.ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE; @@ -92,6 +92,7 @@ import static android.text.format.DateUtils.DAY_IN_MILLIS; 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 +105,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ; 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; @@ -409,10 +409,6 @@ import java.util.concurrent.atomic.AtomicInteger; public class ActivityManagerService extends IActivityManager.Stub implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback, ActivityManagerGlobalLock { - /** - * Priority we boost main thread and RT of top app to. - */ - public static final int TOP_APP_PRIORITY_BOOST = -10; private static final String SYSTEM_PROPERTY_DEVICE_PROVISIONED = "persist.sys.device_provisioned"; @@ -453,7 +449,7 @@ public class ActivityManagerService extends IActivityManager.Stub // How long we wait for a launched process to attach to the activity manager // before we decide it's never going to come up for real. - static final int PROC_START_TIMEOUT = 10*1000; + static final int PROC_START_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER; // How long we wait to kill an application zygote, after the last process using // it has gone away. static final int KILL_APP_ZYGOTE_DELAY_MS = 5 * 1000; @@ -465,8 +461,8 @@ public class ActivityManagerService extends IActivityManager.Stub static final int PROC_START_TIMEOUT_WITH_WRAPPER = 1200*1000; // How long we allow a receiver to run before giving up on it. - static final int BROADCAST_FG_TIMEOUT = 10*1000; - static final int BROADCAST_BG_TIMEOUT = 60*1000; + static final int BROADCAST_FG_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER; + static final int BROADCAST_BG_TIMEOUT = 60 * 1000 * Build.HW_TIMEOUT_MULTIPLIER; public static final int MY_PID = myPid(); @@ -514,7 +510,8 @@ public class ActivityManagerService extends IActivityManager.Stub private static final int MAX_BUGREPORT_TITLE_SIZE = 50; private static final int MAX_BUGREPORT_DESCRIPTION_SIZE = 150; - private static final int NATIVE_DUMP_TIMEOUT_MS = 2000; // 2 seconds; + private static final int NATIVE_DUMP_TIMEOUT_MS = + 2000 * Build.HW_TIMEOUT_MULTIPLIER; // 2 seconds; private static final int JAVA_DUMP_MINIMUM_SIZE = 100; // 100 bytes. OomAdjuster mOomAdjuster; @@ -1178,14 +1175,16 @@ public class ActivityManagerService extends IActivityManager.Stub 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 +1197,8 @@ public class ActivityManagerService extends IActivityManager.Stub proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.TYPE, type); proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.REASON_CODE, reasonCode); + proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.CALLING_UID, + callingUid); proto.end(token); } } @@ -4968,7 +4969,7 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public List<ResolveInfo> queryIntentComponentsForIntentSender( + public ParceledListSlice<ResolveInfo> queryIntentComponentsForIntentSender( IIntentSender pendingResult, int matchFlags) { enforceCallingPermission(Manifest.permission.GET_INTENT_SENDER_INTENT, "queryIntentComponentsForIntentSender()"); @@ -4986,15 +4987,15 @@ public class ActivityManagerService extends IActivityManager.Stub 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); } @@ -6759,7 +6760,7 @@ public class ActivityManagerService extends IActivityManager.Stub setThreadScheduler(proc.getRenderThreadTid(), SCHED_FIFO | SCHED_RESET_ON_FORK, 1); } else { - setThreadPriority(proc.getRenderThreadTid(), TOP_APP_PRIORITY_BOOST); + setThreadPriority(proc.getRenderThreadTid(), THREAD_PRIORITY_TOP_APP_BOOST); } } } else { @@ -9231,6 +9232,8 @@ public class ActivityManagerService extends IActivityManager.Stub pw.print(ptw.type); pw.print(" "); pw.print(ptw.reasonCode); + pw.print(" "); + pw.print(ptw.callingUid); } } } @@ -10785,9 +10788,12 @@ public class ActivityManagerService extends IActivityManager.Stub 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) { @@ -14510,7 +14516,8 @@ public class ActivityManagerService extends IActivityManager.Stub 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(); @@ -14541,7 +14548,8 @@ public class ActivityManagerService extends IActivityManager.Stub 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); } } @@ -16642,7 +16650,7 @@ public class ActivityManagerService extends IActivityManager.Stub throw new SecurityException("Calling uid " + callingUid + " cannot set locusId" + "for package " + activity.getPackageName()); } - + mActivityTaskManager.setLocusId(locusId, appToken); if (mUsageStatsService != null) { mUsageStatsService.reportLocusUpdate(activity, userId, locusId, appToken); } diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 5ad77a3a412a..b8e06ee51754 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -1705,7 +1705,14 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println("Hanging the system..."); pw.flush(); - mInterface.hang(new Binder(), allowRestart); + try { + mInterface.hang(getShellCallback().getShellCallbackBinder(), allowRestart); + } catch (NullPointerException e) { + pw.println("Hanging failed, since caller " + Binder.getCallingPid() + + " did not provide a ShellCallback!"); + pw.flush(); + return 1; + } return 0; } diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java index f8494d8a7c04..31ea14a73409 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 @@ public class AppProfiler { 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/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java index fc28bfbea710..e2086b01ec13 100644 --- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java +++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java @@ -194,6 +194,11 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { final WifiManager wm = mInjector.getSystemService(WifiManager.class); final TelephonyManager tm = mInjector.getSystemService(TelephonyManager.class); final PowerStatsInternal psi = mInjector.getLocalService(PowerStatsInternal.class); + final int voltageMv; + synchronized (mStats) { + voltageMv = mStats.getBatteryVoltageMvLocked(); + } + synchronized (mWorkerLock) { mWifiManager = wm; mTelephony = tm; @@ -212,7 +217,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { // According to spec, initialEcrs will include 0s for consumers that haven't // used any energy yet, as long as they are supported; however, // attributed uid energies will be absent if their energy is 0. - mMeasuredEnergySnapshot.updateAndGetDelta(initialEcrs); + mMeasuredEnergySnapshot.updateAndGetDelta(initialEcrs, voltageMv); } catch (TimeoutException | InterruptedException e) { Slog.w(TAG, "timeout or interrupt reading initial getEnergyConsumedAsync: " + e); @@ -584,10 +589,15 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { Slog.w(TAG, "exception reading modem stats: " + e.getCause()); } - final MeasuredEnergySnapshot.MeasuredEnergyDeltaData measuredEnergyDeltas; + final MeasuredEnergySnapshot.MeasuredEnergyDeltaData measuredEnergyDelta; if (mMeasuredEnergySnapshot == null || futureECRs == null) { - measuredEnergyDeltas = null; + measuredEnergyDelta = null; } else { + final int voltageMv; + synchronized (mStats) { + voltageMv = mStats.getBatteryVoltageMvLocked(); + } + EnergyConsumerResult[] ecrs; try { ecrs = futureECRs.get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); @@ -599,7 +609,8 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { Slog.wtf(TAG, "exception reading getEnergyConsumedAsync: " + e.getCause()); ecrs = null; } - measuredEnergyDeltas = mMeasuredEnergySnapshot.updateAndGetDelta(ecrs); + + measuredEnergyDelta = mMeasuredEnergySnapshot.updateAndGetDelta(ecrs, voltageMv); } final long elapsedRealtime = SystemClock.elapsedRealtime(); @@ -620,7 +631,14 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { onBattery = mStats.isOnBatteryLocked(); onBatteryScreenOff = mStats.isOnBatteryScreenOffLocked(); } - mStats.updateCpuTimeLocked(onBattery, onBatteryScreenOff); + + final long[] cpuClusterChargeUC; + if (measuredEnergyDelta == null) { + cpuClusterChargeUC = null; + } else { + cpuClusterChargeUC = measuredEnergyDelta.cpuClusterChargeUC; + } + mStats.updateCpuTimeLocked(onBattery, onBatteryScreenOff, cpuClusterChargeUC); } if (updateFlags == UPDATE_ALL) { @@ -633,20 +651,22 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { } // Inform mStats about each applicable measured energy. - if (measuredEnergyDeltas != null) { - final long displayEnergy = measuredEnergyDeltas.displayEnergyUJ; - if (displayEnergy != MeasuredEnergySnapshot.UNAVAILABLE) { + if (measuredEnergyDelta != null) { + final long displayChargeUC = measuredEnergyDelta.displayChargeUC; + if (displayChargeUC != MeasuredEnergySnapshot.UNAVAILABLE) { // If updating, pass in what BatteryExternalStatsWorker thinks screenState is. - mStats.updateDisplayEnergyLocked(displayEnergy, screenState, elapsedRealtime); + mStats.updateDisplayMeasuredEnergyStatsLocked(displayChargeUC, screenState, + elapsedRealtime); } } // Inform mStats about each applicable custom energy bucket. - if (measuredEnergyDeltas != null && measuredEnergyDeltas.otherTotalEnergyUJ != null) { + if (measuredEnergyDelta != null + && measuredEnergyDelta.otherTotalChargeUC != null) { // Iterate over the custom (EnergyConsumerType.OTHER) ordinals. - for (int ord = 0; ord < measuredEnergyDeltas.otherTotalEnergyUJ.length; ord++) { - long totalEnergy = measuredEnergyDeltas.otherTotalEnergyUJ[ord]; - SparseLongArray uidEnergies = measuredEnergyDeltas.otherUidEnergiesUJ[ord]; - mStats.updateCustomMeasuredEnergyDataLocked(ord, totalEnergy, uidEnergies); + for (int ord = 0; ord < measuredEnergyDelta.otherTotalChargeUC.length; ord++) { + long totalEnergy = measuredEnergyDelta.otherTotalChargeUC[ord]; + SparseLongArray uidEnergies = measuredEnergyDelta.otherUidChargesUC[ord]; + mStats.updateCustomMeasuredEnergyStatsLocked(ord, totalEnergy, uidEnergies); } } @@ -664,7 +684,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { if (wifiInfo != null) { if (wifiInfo.isValid()) { - // TODO: wifiEnergyDelta = measuredEnergyDeltas.consumerTypeEnergyUJ + // TODO: wifiEnergyDelta = measuredEnergyDelta.consumerTypeEnergyUJ // .get(EnergyConsumerType.WIFI, MeasuredEnergySnapshot.UNAVAILABLE) mStats.updateWifiState(extractDeltaLocked(wifiInfo) /*, TODO: wifiEnergyDelta */, elapsedRealtime, uptime); @@ -785,7 +805,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { /** * Map the {@link EnergyConsumerType}s in the given energyArray to - * their corresponding {@link MeasuredEnergyStats.StandardEnergyBucket}s. + * their corresponding {@link MeasuredEnergyStats.StandardPowerBucket}s. * Does not include custom energy buckets (which are always, by definition, supported). * * @return array with true for index i if standard energy bucket i is supported. @@ -795,15 +815,18 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { if (idToConsumer == null) { return null; } - final boolean[] buckets = new boolean[MeasuredEnergyStats.NUMBER_STANDARD_ENERGY_BUCKETS]; + final boolean[] buckets = new boolean[MeasuredEnergyStats.NUMBER_STANDARD_POWER_BUCKETS]; final int size = idToConsumer.size(); for (int idx = 0; idx < size; idx++) { final EnergyConsumer consumer = idToConsumer.valueAt(idx); switch (consumer.type) { case EnergyConsumerType.DISPLAY: - buckets[MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_ON] = true; - buckets[MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_DOZE] = true; - buckets[MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_OTHER] = true; + buckets[MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON] = true; + buckets[MeasuredEnergyStats.POWER_BUCKET_SCREEN_DOZE] = true; + buckets[MeasuredEnergyStats.POWER_BUCKET_SCREEN_OTHER] = true; + break; + case EnergyConsumerType.CPU_CLUSTER: + buckets[MeasuredEnergyStats.POWER_BUCKET_CPU] = true; break; } } diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index 82f72e8cc1ac..dbfa7f34c6f9 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -83,6 +83,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.net.module.util.PermissionUtils; import com.android.server.LocalServices; import com.android.server.Watchdog; import com.android.server.net.BaseNetworkObserver; @@ -371,6 +372,9 @@ public final class BatteryStatsService extends IBatteryStats.Stub } Watchdog.getInstance().addMonitor(this); + + final DataConnectionStats dataConnectionStats = new DataConnectionStats(mContext, mHandler); + dataConnectionStats.startMonitoring(); } private final class LocalService extends BatteryStatsInternal { @@ -1778,7 +1782,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub @Override public void noteNetworkInterfaceForTransports(final String iface, int[] transportTypes) { - enforceCallingPermission(); + PermissionUtils.enforceNetworkStackPermission(mContext); synchronized (mLock) { mHandler.post(() -> { mStats.noteNetworkInterfaceForTransports(iface, transportTypes); diff --git a/services/core/java/com/android/server/am/BroadcastConstants.java b/services/core/java/com/android/server/am/BroadcastConstants.java index 494f06ebc324..e580327631eb 100644 --- a/services/core/java/com/android/server/am/BroadcastConstants.java +++ b/services/core/java/com/android/server/am/BroadcastConstants.java @@ -18,6 +18,7 @@ package com.android.server.am; import android.content.ContentResolver; import android.database.ContentObserver; +import android.os.Build; import android.os.Handler; import android.provider.Settings; import android.util.KeyValueListParser; @@ -42,12 +43,13 @@ public class BroadcastConstants { "bcast_allow_bg_activity_start_timeout"; // All time intervals are in milliseconds - private static final long DEFAULT_TIMEOUT = 10_000; - private static final long DEFAULT_SLOW_TIME = 5_000; - private static final long DEFAULT_DEFERRAL = 5_000; + private static final long DEFAULT_TIMEOUT = 10_000 * Build.HW_TIMEOUT_MULTIPLIER; + private static final long DEFAULT_SLOW_TIME = 5_000 * Build.HW_TIMEOUT_MULTIPLIER; + private static final long DEFAULT_DEFERRAL = 5_000 * Build.HW_TIMEOUT_MULTIPLIER; private static final float DEFAULT_DEFERRAL_DECAY_FACTOR = 0.75f; private static final long DEFAULT_DEFERRAL_FLOOR = 0; - private static final long DEFAULT_ALLOW_BG_ACTIVITY_START_TIMEOUT = 10_000; + private static final long DEFAULT_ALLOW_BG_ACTIVITY_START_TIMEOUT = + 10_000 * Build.HW_TIMEOUT_MULTIPLIER; // All time constants are in milliseconds diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index 06cacc70a9b8..81c4c8605fb4 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -930,6 +930,8 @@ public final class BroadcastQueue { } 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()); diff --git a/services/core/java/com/android/server/connectivity/DataConnectionStats.java b/services/core/java/com/android/server/am/DataConnectionStats.java index 15f43a0481bd..6e39a4c802d9 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.telephony.TelephonyManager; 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 @@ public class DataConnectionStats extends BroadcastReceiver { 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 @@ public class DataConnectionStats extends BroadcastReceiver { 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 @@ public class DataConnectionStats extends BroadcastReceiver { } } - 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/MeasuredEnergySnapshot.java b/services/core/java/com/android/server/am/MeasuredEnergySnapshot.java index 9e0aa32a0b9e..9b2ca136bdfb 100644 --- a/services/core/java/com/android/server/am/MeasuredEnergySnapshot.java +++ b/services/core/java/com/android/server/am/MeasuredEnergySnapshot.java @@ -25,6 +25,7 @@ import android.hardware.power.stats.EnergyConsumerResult; import android.hardware.power.stats.EnergyConsumerType; import android.util.Slog; import android.util.SparseArray; +import android.util.SparseIntArray; import android.util.SparseLongArray; import com.android.internal.annotations.VisibleForTesting; @@ -38,11 +39,16 @@ import java.io.PrintWriter; public class MeasuredEnergySnapshot { private static final String TAG = "MeasuredEnergySnapshot"; + private static final int MILLIVOLTS_PER_VOLT = 1000; + public static final long UNAVAILABLE = -1L; /** Map of {@link EnergyConsumer#id} to its corresponding {@link EnergyConsumer}. */ private final SparseArray<EnergyConsumer> mEnergyConsumers; + /** Number of ordinals for {@link EnergyConsumerType#CPU_CLUSTER}. */ + private final int mNumCpuClusterOrdinals; + /** Number of ordinals for {@link EnergyConsumerType#OTHER}. */ private final int mNumOtherOrdinals; @@ -59,6 +65,14 @@ public class MeasuredEnergySnapshot { private final SparseLongArray mMeasuredEnergySnapshots; /** + * Voltage snapshots, mapping {@link EnergyConsumer#id} to voltage (mV) from the last time + * each {@link EnergyConsumer} was updated. + * + * see {@link mMeasuredEnergySnapshots}. + */ + private final SparseIntArray mVoltageSnapshots; + + /** * Energy snapshots <b>per uid</b> from the last time each {@link EnergyConsumer} of type * {@link EnergyConsumerType#OTHER} was updated. * It maps each OTHER {@link EnergyConsumer#id} to a SparseLongArray, which itself maps each @@ -77,8 +91,11 @@ public class MeasuredEnergySnapshot { MeasuredEnergySnapshot(@NonNull SparseArray<EnergyConsumer> idToConsumerMap) { mEnergyConsumers = idToConsumerMap; mMeasuredEnergySnapshots = new SparseLongArray(mEnergyConsumers.size()); + mVoltageSnapshots = new SparseIntArray(mEnergyConsumers.size()); - mNumOtherOrdinals = calculateNumOtherOrdinals(idToConsumerMap); + mNumCpuClusterOrdinals = calculateNumOrdinals(EnergyConsumerType.CPU_CLUSTER, + idToConsumerMap); + mNumOtherOrdinals = calculateNumOrdinals(EnergyConsumerType.OTHER, idToConsumerMap); mAttributionSnapshots = new SparseArray<>(mNumOtherOrdinals); } @@ -90,16 +107,19 @@ public class MeasuredEnergySnapshot { return mNumOtherOrdinals; } - /** Class for returning measured energy delta data. */ + /** Class for returning the relevant data calculated from the measured energy delta */ static class MeasuredEnergyDeltaData { - /** The energyUJ for {@link EnergyConsumerType#DISPLAY}. */ - public long displayEnergyUJ = UNAVAILABLE; + /** The chargeUC for {@link EnergyConsumerType#DISPLAY}. */ + public long displayChargeUC = UNAVAILABLE; + + /** The chargeUC for {@link EnergyConsumerType#CPU_CLUSTER}s. */ + public long[] cpuClusterChargeUC = null; - /** Map of {@link EnergyConsumerType#OTHER} ordinals to their total energyUJ. */ - public @Nullable long[] otherTotalEnergyUJ = null; + /** Map of {@link EnergyConsumerType#OTHER} ordinals to their total chargeUC. */ + public @Nullable long[] otherTotalChargeUC = null; - /** Map of {@link EnergyConsumerType#OTHER} ordinals to their {uid->energyUJ} maps. */ - public @Nullable SparseLongArray[] otherUidEnergiesUJ = null; + /** Map of {@link EnergyConsumerType#OTHER} ordinals to their {uid->chargeUC} maps. */ + public @Nullable SparseLongArray[] otherUidChargesUC = null; } /** @@ -108,19 +128,28 @@ public class MeasuredEnergySnapshot { * * @param ecrs EnergyConsumerResults for some (possibly not all) {@link EnergyConsumer}s. * Consumers that are not present are ignored (they are *not* treated as 0). + * @param voltageMV current voltage. * * @return a MeasuredEnergyDeltaData, containing maps from the updated consumers to - * their corresponding energy deltas. + * their corresponding charge deltas. * Fields with no interesting data (consumers not present in ecrs or with no energy * difference) will generally be left as their default values. - * otherTotalEnergyUJ and otherUidEnergiesUJ are always either both null or both of + * otherTotalChargeUC and otherUidChargesUC are always either both null or both of * length {@link #getNumOtherOrdinals()}. * Returns null, if ecrs is null or empty. */ - public @Nullable MeasuredEnergyDeltaData updateAndGetDelta(EnergyConsumerResult[] ecrs) { + public @Nullable MeasuredEnergyDeltaData updateAndGetDelta(EnergyConsumerResult[] ecrs, + int voltageMV) { if (ecrs == null || ecrs.length == 0) { return null; } + if (voltageMV <= 0) { + Slog.wtf(TAG, "Unexpected battery voltage (" + voltageMV + + " mV) when taking measured energy snapshot"); + // TODO (b/181685156): consider adding the nominal voltage to power profile and + // falling back to it if measured voltage is unavailable. + return null; + } final MeasuredEnergyDeltaData output = new MeasuredEnergyDeltaData(); for (final EnergyConsumerResult ecr : ecrs) { @@ -138,12 +167,15 @@ public class MeasuredEnergySnapshot { final int type = consumer.type; final int ordinal = consumer.ordinal; - // Look up, and update, the old energy information about this consumer. + // Look up, and update, the old energy and voltage information about this consumer. final long oldEnergyUJ = mMeasuredEnergySnapshots.get(consumerId, UNAVAILABLE); + final int oldVoltageMV = mVoltageSnapshots.get(consumerId); mMeasuredEnergySnapshots.put(consumerId, newEnergyUJ); - final SparseLongArray otherUidEnergies - = updateAndGetDeltaForTypeOther(consumer, newAttributions); + mVoltageSnapshots.put(consumerId, voltageMV); + final int avgVoltageMV = (oldVoltageMV + voltageMV + 1) / 2; + final SparseLongArray otherUidCharges = + updateAndGetDeltaForTypeOther(consumer, newAttributions, avgVoltageMV); // Everything is fully done being updated. We now calculate the delta for returning. // NB: Since sum(attribution.energyUWs)<=energyUWs we assume that if deltaEnergy==0 @@ -152,24 +184,36 @@ public class MeasuredEnergySnapshot { if (oldEnergyUJ < 0) continue; // Generally happens only on initialization. if (newEnergyUJ == oldEnergyUJ) continue; + final long deltaUJ = newEnergyUJ - oldEnergyUJ; - if (deltaUJ < 0) { - Slog.e(TAG, "EnergyConsumer " + consumer.name + ": new energy (" + newEnergyUJ - + ") < old energy (" + oldEnergyUJ + "). Skipping. "); + if (deltaUJ < 0 || oldVoltageMV <= 0) { + Slog.e(TAG, "Bad data! EnergyConsumer " + consumer.name + + ": new energy (" + newEnergyUJ + ") < old energy (" + oldEnergyUJ + + "), new voltage (" + voltageMV + "), old voltage (" + oldVoltageMV + + "). Skipping. "); continue; } + final long deltaChargeUC = calculateChargeConsumedUC(deltaUJ, avgVoltageMV); switch (type) { case EnergyConsumerType.DISPLAY: - output.displayEnergyUJ = deltaUJ; + output.displayChargeUC = deltaChargeUC; break; + + case EnergyConsumerType.CPU_CLUSTER: + if (output.cpuClusterChargeUC == null) { + output.cpuClusterChargeUC = new long[mNumCpuClusterOrdinals]; + } + output.cpuClusterChargeUC[ordinal] = deltaChargeUC; + break; + case EnergyConsumerType.OTHER: - if (output.otherTotalEnergyUJ == null) { - output.otherTotalEnergyUJ = new long[getNumOtherOrdinals()]; - output.otherUidEnergiesUJ = new SparseLongArray[getNumOtherOrdinals()]; + if (output.otherTotalChargeUC == null) { + output.otherTotalChargeUC = new long[getNumOtherOrdinals()]; + output.otherUidChargesUC = new SparseLongArray[getNumOtherOrdinals()]; } - output.otherTotalEnergyUJ[ordinal] = deltaUJ; - output.otherUidEnergiesUJ[ordinal] = otherUidEnergies; + output.otherTotalChargeUC[ordinal] = deltaChargeUC; + output.otherUidChargesUC[ordinal] = otherUidCharges; break; default: Slog.w(TAG, "Ignoring consumer " + consumer.name + " of unknown type " + type); @@ -182,19 +226,21 @@ public class MeasuredEnergySnapshot { /** * For a consumer of type {@link EnergyConsumerType#OTHER}, updates * {@link #mAttributionSnapshots} with freshly measured energies (per uid) and returns the - * difference (delta) between the previously stored values and the passed-in values. + * charge consumed (in microcouloumbs) between the previously stored values and the passed-in + * values. * * @param consumerInfo a consumer of type {@link EnergyConsumerType#OTHER}. * @param newAttributions Record of uids and their new energyUJ values. * Any uid not present is treated as having energy 0. * If null or empty, all uids are treated as having energy 0. - * @return A map (in the sense of {@link MeasuredEnergyDeltaData#otherUidEnergiesUJ} for this - * consumer) of uid -> energyDelta, with all uids that have a non-zero energyDelta. + * @param avgVoltageMV The average voltage since the last snapshot. + * @return A map (in the sense of {@link MeasuredEnergyDeltaData#otherUidChargesUC} for this + * consumer) of uid -> chargeDelta, with all uids that have a non-zero chargeDelta. * Returns null if no delta available to calculate. */ private @Nullable SparseLongArray updateAndGetDeltaForTypeOther( @NonNull EnergyConsumer consumerInfo, - @Nullable EnergyConsumerAttribution[] newAttributions) { + @Nullable EnergyConsumerAttribution[] newAttributions, int avgVoltageMV) { if (consumerInfo.type != EnergyConsumerType.OTHER) { return null; @@ -217,8 +263,8 @@ public class MeasuredEnergySnapshot { return null; } - // Map uid -> energyDelta. No initial capacity since many deltas might be 0. - final SparseLongArray uidEnergyDeltas = new SparseLongArray(); + // Map uid -> chargeDelta. No initial capacity since many deltas might be 0. + final SparseLongArray uidChargeDeltas = new SparseLongArray(); for (EnergyConsumerAttribution newAttribution : newAttributions) { final int uid = newAttribution.uid; @@ -231,14 +277,17 @@ public class MeasuredEnergySnapshot { if (oldEnergyUJ < 0) continue; if (newEnergyUJ == oldEnergyUJ) continue; final long deltaUJ = newEnergyUJ - oldEnergyUJ; - if (deltaUJ < 0) { + if (deltaUJ < 0 || avgVoltageMV <= 0) { Slog.e(TAG, "EnergyConsumer " + consumerInfo.name + ": new energy (" + newEnergyUJ - + ") but old energy (" + oldEnergyUJ + "). Skipping. "); + + ") but old energy (" + oldEnergyUJ + "). Average voltage (" + avgVoltageMV + + ")Skipping. "); continue; } - uidEnergyDeltas.put(uid, deltaUJ); + + final long deltaChargeUC = calculateChargeConsumedUC(deltaUJ, avgVoltageMV); + uidChargeDeltas.put(uid, deltaChargeUC); } - return uidEnergyDeltas; + return uidChargeDeltas; } /** Dump debug data. */ @@ -255,22 +304,33 @@ public class MeasuredEnergySnapshot { for (int i = 0; i < mMeasuredEnergySnapshots.size(); i++) { final int id = mMeasuredEnergySnapshots.keyAt(i); final long energyUJ = mMeasuredEnergySnapshots.valueAt(i); - pw.println(String.format(" Consumer %d has energy %d uJ}", id, energyUJ)); + final long voltageMV = mVoltageSnapshots.valueAt(i); + pw.println(String.format(" Consumer %d has energy %d uJ at %d mV", id, energyUJ, + voltageMV)); } pw.println("List of the " + mNumOtherOrdinals + " OTHER EnergyConsumers:"); pw.println(" " + mAttributionSnapshots); pw.println(); } - /** Determines the number of ordinals for {@link EnergyConsumerType#OTHER}. */ - private static int calculateNumOtherOrdinals(SparseArray<EnergyConsumer> idToConsumer) { + /** Determines the number of ordinals for a given {@link EnergyConsumerType}. */ + private static int calculateNumOrdinals(@EnergyConsumerType int type, + SparseArray<EnergyConsumer> idToConsumer) { if (idToConsumer == null) return 0; - int numOtherOrdinals = 0; + int numOrdinals = 0; final int size = idToConsumer.size(); for (int idx = 0; idx < size; idx++) { final EnergyConsumer consumer = idToConsumer.valueAt(idx); - if (consumer.type == EnergyConsumerType.OTHER) numOtherOrdinals++; + if (consumer.type == type) numOrdinals++; } - return numOtherOrdinals; + return numOrdinals; + } + + /** Calculate charge consumption (in microcouloumbs) from a given energy and voltage */ + private long calculateChargeConsumedUC(long deltaEnergyUJ, int avgVoltageMV) { + // To overflow, a 3.7V 10000mAh battery would need to completely drain 69244 times + // since the last snapshot. Round up to the nearest whole long. + return (deltaEnergyUJ * MILLIVOLTS_PER_VOLT + (avgVoltageMV + 1) / 2) / avgVoltageMV; } + } diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 06e879b549af..939d35fdb5ef 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -49,6 +49,7 @@ import static android.os.Process.THREAD_GROUP_DEFAULT; import static android.os.Process.THREAD_GROUP_RESTRICTED; import static android.os.Process.THREAD_GROUP_TOP_APP; import static android.os.Process.THREAD_PRIORITY_DISPLAY; +import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST; import static android.os.Process.setProcessGroup; import static android.os.Process.setThreadPriority; import static android.os.Process.setThreadScheduler; @@ -68,7 +69,6 @@ import static com.android.server.am.ActivityManagerService.TAG_BACKUP; import static com.android.server.am.ActivityManagerService.TAG_LRU; import static com.android.server.am.ActivityManagerService.TAG_OOM_ADJ; import static com.android.server.am.ActivityManagerService.TAG_UID_OBSERVERS; -import static com.android.server.am.ActivityManagerService.TOP_APP_PRIORITY_BOOST; import static com.android.server.am.AppProfiler.TAG_PSS; import static com.android.server.am.ProcessList.TAG_PROCESS_OBSERVERS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; @@ -343,7 +343,7 @@ public final class OomAdjuster { // The process group is usually critical to the response time of foreground app, so the // setter should apply it as soon as possible. final ServiceThread adjusterThread = - new ServiceThread(TAG, TOP_APP_PRIORITY_BOOST, false /* allowIo */); + new ServiceThread(TAG, THREAD_PRIORITY_TOP_APP_BOOST, false /* allowIo */); adjusterThread.start(); adjusterThread.getThreadHandler().post(() -> Process.setThreadGroupAndCpuset( adjusterThread.getThreadId(), THREAD_GROUP_TOP_APP)); @@ -2647,11 +2647,11 @@ public final class OomAdjuster { } } else { // Boost priority for top app UI and render threads - setThreadPriority(app.getPid(), TOP_APP_PRIORITY_BOOST); + setThreadPriority(app.getPid(), THREAD_PRIORITY_TOP_APP_BOOST); if (renderThreadTid != 0) { try { setThreadPriority(renderThreadTid, - TOP_APP_PRIORITY_BOOST); + THREAD_PRIORITY_TOP_APP_BOOST); } catch (IllegalArgumentException e) { // thread died, ignore } @@ -2813,7 +2813,7 @@ public final class OomAdjuster { // is not ready when attaching. if (Process.getProcessGroup(app.getPid()) == THREAD_GROUP_TOP_APP) { app.getWindowProcessController().onTopProcChanged(); - setThreadPriority(app.getPid(), TOP_APP_PRIORITY_BOOST); + setThreadPriority(app.getPid(), THREAD_PRIORITY_TOP_APP_BOOST); } else { fallbackReason = "not expected top priority"; } diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java index 26ce0d77e0af..0eae6617ba86 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 @@ public final class GameManagerService extends IGameManagerService.Stub { /** * SystemService lifecycle for GameService. + * * @hide */ public static class Lifecycle extends SystemService { @@ -169,40 +170,70 @@ public final class GameManagerService extends IGameManagerService.Stub { } } - 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); } + } - userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), - Binder.getCallingUid(), userId, false, true, "getGameMode", - "com.android.server.app.GameManagerService"); - + 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; } - GameManagerSettings userSettings = mSettings.get(userId); - return userSettings.getGameModeLocked(packageName); + + 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 - @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 @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"); + + 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) + 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", "com.android.server.app.GameManagerService"); 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 000000000000..b0335fe404f4 --- /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 32ae87898085..2c0a5891c4b9 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.GuardedBy; 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 @@ public final class AppHibernationService extends SystemService { intentFilter.addAction(ACTION_PACKAGE_REMOVED); intentFilter.addDataScheme("package"); userAllContext.registerReceiver(mBroadcastReceiver, intentFilter); + + LocalServices.addService(AppHibernationManagerInternal.class, mLocalService); } @Override @@ -311,17 +314,8 @@ public final class AppHibernationService extends SystemService { private void unhibernatePackageForUser(@NonNull String packageName, int userId, UserLevelState pkgState) { Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "unhibernatePackage"); - final long caller = Binder.clearCallingIdentity(); - try { - mIPackageManager.setPackageStoppedState(packageName, false, userId); - pkgState.hibernated = false; - } catch (RemoteException e) { - throw new IllegalStateException( - "Failed to unhibernate due to manager not being available", e); - } finally { - Binder.restoreCallingIdentity(caller); - Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); - } + pkgState.hibernated = false; + Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); } /** @@ -545,6 +539,36 @@ public final class AppHibernationService extends SystemService { } } + 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 11125dd55665..4a12ff6932de 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 @@ public class AppOpsService extends IAppOpsService.Stub { 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 @@ public class AppOpsService extends IAppOpsService.Stub { 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 @@ public class AppOpsService extends IAppOpsService.Stub { event.numUnfinishedStarts++; mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName, - tag, uidState, flags); + tag, uidState, flags, startTime); } /** @@ -1017,11 +1015,7 @@ public class AppOpsService extends IAppOpsService.Stub { 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 @@ public class AppOpsService extends IAppOpsService.Stub { mFile.failWrite(stream); } } - mHistoricalRegistry.mDiscreteRegistry.writeAndClearAccessHistory(); + mHistoricalRegistry.writeAndClearDiscreteHistory(); } static class Shell extends ShellCommand { @@ -6125,8 +6119,7 @@ public class AppOpsService extends IAppOpsService.Stub { 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 76990453ee03..a99d90883f87 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 @@ final class DiscreteRegistry { 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 1c43fedd3112..0fcf5ee35e11 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 @@ final class HistoricalRegistry { 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 @@ final class HistoricalRegistry { } 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 @@ final class HistoricalRegistry { 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 @@ final class HistoricalRegistry { 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 @@ final class HistoricalRegistry { 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 @@ final class HistoricalRegistry { 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 @@ final class HistoricalRegistry { } } - 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/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index f72fb1f74fa8..e4fc89540b98 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -25,6 +25,7 @@ import android.bluetooth.BluetoothProfile; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; +import android.media.AudioAttributes; import android.media.AudioDeviceAttributes; import android.media.AudioDeviceInfo; import android.media.AudioManager; @@ -80,7 +81,7 @@ import java.util.concurrent.atomic.AtomicBoolean; private final @NonNull Context mContext; /** Forced device usage for communications sent to AudioSystem */ - private AudioDeviceAttributes mPreferredDeviceforComm; + private AudioDeviceAttributes mPreferredCommunicationDevice; private int mCommunicationStrategyId = -1; // Manages all connected devices, only ever accessed on the message loop @@ -152,7 +153,7 @@ import java.util.concurrent.atomic.AtomicBoolean; private void init() { setupMessaging(mContext); - mPreferredDeviceforComm = null; + mPreferredCommunicationDevice = null; initCommunicationStrategyId(); mSystemServer.registerUserStartedReceiver(mContext); @@ -260,11 +261,11 @@ import java.util.concurrent.atomic.AtomicBoolean; * @param device Device selected or null to unselect. * @param eventSource for logging purposes */ - /*package*/ boolean setDeviceForCommunication( + /*package*/ boolean setCommunicationDevice( IBinder cb, int pid, AudioDeviceInfo device, String eventSource) { if (AudioService.DEBUG_COMM_RTE) { - Log.v(TAG, "setDeviceForCommunication, device: " + device + ", pid: " + pid); + Log.v(TAG, "setCommunicationDevice, device: " + device + ", pid: " + pid); } synchronized (mSetModeLock) { @@ -385,13 +386,21 @@ import java.util.concurrent.atomic.AtomicBoolean; * Returns the device currently requested for communication use case. * @return AudioDeviceInfo the requested device for communication. */ - AudioDeviceInfo getDeviceForCommunication() { + AudioDeviceInfo getCommunicationDevice() { synchronized (mDeviceStateLock) { AudioDeviceAttributes device = requestedCommunicationDevice(); if (device == null) { - return null; + AudioAttributes attr = + AudioProductStrategy.getAudioAttributesForStrategyWithLegacyStreamType( + AudioSystem.STREAM_VOICE_CALL); + List<AudioDeviceAttributes> devices = AudioSystem.getDevicesForAttributes(attr); + if (devices.isEmpty()) { + return null; + } + device = devices.get(0); } - return AudioManager.getDeviceInfoFromType(device.getType()); + return AudioManager.getDeviceInfoFromTypeAndAddress( + device.getType(), device.getAddress()); } } @@ -415,7 +424,7 @@ import java.util.concurrent.atomic.AtomicBoolean; * @return true if speakerphone is active, false otherwise. */ /*package*/ boolean isSpeakerphoneOn() { - AudioDeviceAttributes device = getPreferredDeviceForComm(); + AudioDeviceAttributes device = getPreferredCommunicationDevice(); if (device == null) { return false; } @@ -586,7 +595,7 @@ import java.util.concurrent.atomic.AtomicBoolean; * @return true if Bluetooth SCO is active , false otherwise. */ /*package*/ boolean isBluetoothScoOn() { - AudioDeviceAttributes device = getPreferredDeviceForComm(); + AudioDeviceAttributes device = getPreferredCommunicationDevice(); if (device == null) { return false; } @@ -736,8 +745,8 @@ import java.util.concurrent.atomic.AtomicBoolean; @GuardedBy("mDeviceStateLock") private void dispatchCommunicationDevice() { - AudioDeviceInfo device = getDeviceForCommunication(); - int portId = (getDeviceForCommunication() == null) ? 0 : device.getId(); + AudioDeviceInfo device = getCommunicationDevice(); + int portId = (getCommunicationDevice() == null) ? 0 : device.getId(); if (portId == mCurCommunicationPortId) { return; } @@ -1010,8 +1019,13 @@ import java.util.concurrent.atomic.AtomicBoolean; pw.println(" " + prefix + "pid: " + cl.getPid() + " device: " + cl.getDevice() + " cb: " + cl.getBinder()); }); - pw.println("\n" + prefix + "mPreferredDeviceforComm: " - + mPreferredDeviceforComm); + pw.println("\n" + prefix + "mPreferredCommunicationDevice: " + + mPreferredCommunicationDevice); + + pw.println(prefix + "Selected Communication Device: " + + ((getCommunicationDevice() == null) ? "None" + : new AudioDeviceAttributes(getCommunicationDevice()))); + pw.println(prefix + "mCommunicationStrategyId: " + mCommunicationStrategyId); @@ -1201,11 +1215,9 @@ import java.util.concurrent.atomic.AtomicBoolean; case MSG_I_SET_MODE_OWNER_PID: synchronized (mSetModeLock) { synchronized (mDeviceStateLock) { - if (mModeOwnerPid != msg.arg1) { - mModeOwnerPid = msg.arg1; - if (msg.arg2 != AudioSystem.MODE_RINGTONE) { - onUpdateCommunicationRoute("setNewModeOwner"); - } + mModeOwnerPid = msg.arg1; + if (msg.arg2 != AudioSystem.MODE_RINGTONE) { + onUpdateCommunicationRoute("setNewModeOwner"); } } } @@ -1664,7 +1676,7 @@ import java.util.concurrent.atomic.AtomicBoolean; * @return selected forced usage for communication. */ @GuardedBy("mDeviceStateLock") - @Nullable private AudioDeviceAttributes getPreferredDeviceForComm() { + @Nullable private AudioDeviceAttributes getPreferredCommunicationDevice() { boolean btSCoOn = mBluetoothScoOn && mBtHelper.isBluetoothScoOn(); if (btSCoOn) { // Use the SCO device known to BtHelper so that it matches exactly @@ -1692,24 +1704,27 @@ import java.util.concurrent.atomic.AtomicBoolean; // @GuardedBy("mSetModeLock") @GuardedBy("mDeviceStateLock") private void onUpdateCommunicationRoute(String eventSource) { - mPreferredDeviceforComm = getPreferredDeviceForComm(); + mPreferredCommunicationDevice = getPreferredCommunicationDevice(); if (AudioService.DEBUG_COMM_RTE) { - Log.v(TAG, "onUpdateCommunicationRoute, mPreferredDeviceforComm: " - + mPreferredDeviceforComm + " eventSource: " + eventSource); + Log.v(TAG, "onUpdateCommunicationRoute, mPreferredCommunicationDevice: " + + mPreferredCommunicationDevice + " eventSource: " + eventSource); } + AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent( + "onUpdateCommunicationRoute, mPreferredCommunicationDevice: " + + mPreferredCommunicationDevice + " eventSource: " + eventSource))); - if (mPreferredDeviceforComm == null + if (mPreferredCommunicationDevice == null || !AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains( - mPreferredDeviceforComm.getInternalType())) { + mPreferredCommunicationDevice.getInternalType())) { AudioSystem.setParameters("BT_SCO=off"); } else { AudioSystem.setParameters("BT_SCO=on"); } - if (mPreferredDeviceforComm == null) { + if (mPreferredCommunicationDevice == null) { postRemovePreferredDevicesForStrategy(mCommunicationStrategyId); } else { postSetPreferredDevicesForStrategy( - mCommunicationStrategyId, Arrays.asList(mPreferredDeviceforComm)); + mCommunicationStrategyId, Arrays.asList(mPreferredCommunicationDevice)); } mAudioService.postUpdateRingerModeServiceInt(); dispatchCommunicationDevice(); diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index 076cbffc0a29..9b88c9a7b1fb 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -662,6 +662,11 @@ public class AudioDeviceInventory { /*package*/ int removePreferredDevicesForStrategySync(int strategy) { final long identity = Binder.clearCallingIdentity(); + + AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent( + "removePreferredDevicesForStrategySync, strategy: " + + strategy)).printLog(TAG)); + final int status = mAudioSystem.removeDevicesRoleForStrategy( strategy, AudioSystem.DEVICE_ROLE_PREFERRED); Binder.restoreCallingIdentity(identity); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index f5b94177a2d9..68f10a5106ef 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -4761,8 +4761,19 @@ public class AudioService extends IAudioService.Stub return false; } - /** @see AudioManager#setDeviceForCommunication(int) */ - public boolean setDeviceForCommunication(IBinder cb, int portId) { + /** @see AudioManager#getAvailableCommunicationDevices(int) */ + public int[] getAvailableCommunicationDeviceIds() { + ArrayList<Integer> deviceIds = new ArrayList<>(); + AudioDeviceInfo[] devices = AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_OUTPUTS); + for (AudioDeviceInfo device : devices) { + if (isValidCommunicationDevice(device)) { + deviceIds.add(device.getId()); + } + } + return deviceIds.stream().mapToInt(Integer::intValue).toArray(); + } + /** @see AudioManager#setCommunicationDevice(int) */ + public boolean setCommunicationDevice(IBinder cb, int portId) { final int uid = Binder.getCallingUid(); final int pid = Binder.getCallingPid(); @@ -4776,7 +4787,7 @@ public class AudioService extends IAudioService.Stub throw new IllegalArgumentException("invalid device type " + device.getType()); } } - final String eventSource = new StringBuilder("setDeviceForCommunication(") + final String eventSource = new StringBuilder("setCommunicationDevice(") .append(") from u/pid:").append(uid).append("/") .append(pid).toString(); @@ -4786,7 +4797,7 @@ public class AudioService extends IAudioService.Stub deviceType = device.getPort().type(); deviceAddress = device.getAddress(); } else { - AudioDeviceInfo curDevice = mDeviceBroker.getDeviceForCommunication(); + AudioDeviceInfo curDevice = mDeviceBroker.getCommunicationDevice(); if (curDevice != null) { deviceType = curDevice.getPort().type(); deviceAddress = curDevice.getAddress(); @@ -4796,7 +4807,7 @@ public class AudioService extends IAudioService.Stub // was selected if (deviceType != AudioSystem.DEVICE_OUT_DEFAULT) { new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE - + MediaMetrics.SEPARATOR + "setDeviceForCommunication") + + MediaMetrics.SEPARATOR + "setCommunicationDevice") .set(MediaMetrics.Property.DEVICE, AudioSystem.getDeviceName(deviceType)) .set(MediaMetrics.Property.ADDRESS, deviceAddress) @@ -4807,15 +4818,15 @@ public class AudioService extends IAudioService.Stub final long ident = Binder.clearCallingIdentity(); boolean status = - mDeviceBroker.setDeviceForCommunication(cb, pid, device, eventSource); + mDeviceBroker.setCommunicationDevice(cb, pid, device, eventSource); Binder.restoreCallingIdentity(ident); return status; } - /** @see AudioManager#getDeviceForCommunication() */ - public int getDeviceForCommunication() { + /** @see AudioManager#getCommunicationDevice() */ + public int getCommunicationDevice() { final long ident = Binder.clearCallingIdentity(); - AudioDeviceInfo device = mDeviceBroker.getDeviceForCommunication(); + AudioDeviceInfo device = mDeviceBroker.getCommunicationDevice(); Binder.restoreCallingIdentity(ident); if (device == null) { return 0; @@ -6958,7 +6969,10 @@ public class AudioService extends IAudioService.Stub 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 000000000000..9f0a2baea91d --- /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 b6d647289ed8..cc60fe1200b1 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 @@ public class FocusRequester { */ 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 @@ public class FocusRequester { mGrantFlags = grantFlags; mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE; mFocusLossWasNotified = true; + mFocusLossFadeLimbo = false; mFocusController = ctlr; mSdkTarget = sdk; } @@ -115,6 +121,7 @@ public class FocusRequester { mFocusGainRequest = afi.getGainRequest(); mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE; mFocusLossWasNotified = true; + mFocusLossFadeLimbo = false; mGrantFlags = afi.getFlags(); mSdkTarget = afi.getSdkTarget(); @@ -132,6 +139,13 @@ public class FocusRequester { 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 @@ public class FocusRequester { + " -- 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 @@ public class FocusRequester { 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 @@ public class FocusRequester { 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 @@ public class FocusRequester { @GuardedBy("MediaFocusControl.mAudioFocusLock") void handleFocusGainFromRequest(int focusRequestResult) { if (focusRequestResult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { - mFocusController.unduckPlayers(this); + mFocusController.restoreVShapedPlayers(this); } } @@ -375,7 +400,7 @@ public class FocusRequester { 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 @@ public class FocusRequester { 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 b1633b01df90..1dcfdaec44ec 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.MediaMetrics; 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 @@ public class MediaFocusControl implements PlayerFocusEnforcer { */ 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 @@ public class MediaFocusControl implements PlayerFocusEnforcer { 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 @@ public class MediaFocusControl implements PlayerFocusEnforcer { } @Override - public void unduckPlayers(@NonNull FocusRequester winner) { - mFocusEnforcer.unduckPlayers(winner); + public void restoreVShapedPlayers(@NonNull FocusRequester winner) { + mFocusEnforcer.restoreVShapedPlayers(winner); } @Override @@ -133,6 +143,16 @@ public class MediaFocusControl implements PlayerFocusEnforcer { 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 @@ public class MediaFocusControl implements PlayerFocusEnforcer { { //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 @@ public class MediaFocusControl implements PlayerFocusEnforcer { abandonSource = fr.toAudioFocusInfo(); } // stack entry not used anymore, clear references - fr.release(); + fr.maybeRelease(); } } } @@ -1134,4 +1154,57 @@ public class MediaFocusControl implements PlayerFocusEnforcer { 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 8af1b5be1517..47c91e6c23dd 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 final class PlaybackActivityMonitor 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 @@ public final class PlaybackActivityMonitor } if (change && event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) { mDuckingManager.checkDuck(apc); + mFadingManager.checkFade(apc); } } if (change) { @@ -320,6 +322,7 @@ public final class PlaybackActivityMonitor "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 @@ public final class PlaybackActivityMonitor // 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 @@ public final class PlaybackActivityMonitor } @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 @@ public final class PlaybackActivityMonitor } } + 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 @@ public final class PlaybackActivityMonitor } } - 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 @@ public final class PlaybackActivityMonitor @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 @@ public final class PlaybackActivityMonitor } } - 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 89e7b7828b15..fb72ac282e8d 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 @@ public interface PlayerFocusEnforcer { 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 @@ public interface PlayerFocusEnforcer { * 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/sensors/AcquisitionClient.java b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java index b3580fb79042..93fea90cd89a 100644 --- a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java @@ -80,6 +80,18 @@ public abstract class AcquisitionClient<T> extends HalClientMonitor<T> implement onErrorInternal(errorCode, vendorCode, true /* finish */); } + /** + * Notifies the caller that the operation was canceled by the user. Note that the actual + * operation still needs to wait for the HAL to send ERROR_CANCELED. + */ + public void onUserCanceled() { + // Send USER_CANCELED, but do not finish. Wait for the HAL to respond with ERROR_CANCELED, + // which then finishes the AcquisitionClient's lifecycle. + onErrorInternal(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED, 0 /* vendorCode */, + false /* finish */); + stopHalOperation(); + } + protected void onErrorInternal(int errorCode, int vendorCode, boolean finish) { // In some cases, the framework will send an error to the caller before a true terminal // case (success, failure, or error) is received from the HAL (e.g. versions of fingerprint 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 d7e08e462777..7a846f5b14a5 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 @@ import com.android.server.biometrics.sensors.GenerateChallengeClient; */ 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 @@ public class FaceGenerateChallengeClient extends GenerateChallengeClient<ISessio @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 afa5bd22e081..b4c9b290cd06 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 @@ public class TestHal extends IFace.Stub { 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/UdfpsHelper.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java index 37f8e8c2c1ee..f0e45978c365 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java @@ -22,9 +22,12 @@ import android.content.Context; import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.IUdfpsOverlayController; +import android.hardware.fingerprint.IUdfpsOverlayControllerCallback; import android.os.RemoteException; import android.util.Slog; +import com.android.server.biometrics.sensors.AcquisitionClient; + /** * Contains helper methods for under-display fingerprint HIDL. */ @@ -77,12 +80,22 @@ public class UdfpsHelper { } public static void showUdfpsOverlay(int sensorId, int reason, - @Nullable IUdfpsOverlayController udfpsOverlayController) { + @Nullable IUdfpsOverlayController udfpsOverlayController, + @NonNull AcquisitionClient<?> client) { if (udfpsOverlayController == null) { return; } + + final IUdfpsOverlayControllerCallback callback = + new IUdfpsOverlayControllerCallback.Stub() { + @Override + public void onUserCanceled() { + client.onUserCanceled(); + } + }; + try { - udfpsOverlayController.showUdfpsOverlay(sensorId, reason); + udfpsOverlayController.showUdfpsOverlay(sensorId, reason, callback); } catch (RemoteException e) { Slog.e(TAG, "Remote exception when showing the UDFPS overlay", e); } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java index f9527d9379bc..e2743f624c37 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java @@ -89,7 +89,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<ISession> imp @Override protected void startHalOperation() { UdfpsHelper.showUdfpsOverlay(getSensorId(), Utils.getUdfpsAuthReason(this), - mUdfpsOverlayController); + mUdfpsOverlayController, this); try { mCancellationSignal = getFreshDaemon().authenticate(mSequentialId, mOperationId); } catch (RemoteException e) { diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java index bcd1b8bc9976..620a9cf3e6f2 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java @@ -72,7 +72,7 @@ class FingerprintDetectClient extends AcquisitionClient<ISession> { protected void startHalOperation() { UdfpsHelper.showUdfpsOverlay(getSensorId(), IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, - mUdfpsOverlayController); + mUdfpsOverlayController, this); try { mCancellationSignal = getFreshDaemon().detectInteraction(mSequentialId); } catch (RemoteException e) { diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java index ae64c77f1365..63fa66cdca20 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java @@ -121,7 +121,7 @@ class FingerprintEnrollClient extends EnrollClient<ISession> implements Udfps { protected void startHalOperation() { UdfpsHelper.showUdfpsOverlay(getSensorId(), UdfpsHelper.getReasonFromEnrollReason(mEnrollReason), - mUdfpsOverlayController); + mUdfpsOverlayController, this); try { mCancellationSignal = getFreshDaemon().enroll(mSequentialId, HardwareAuthTokenUtils.toHardwareAuthToken(mHardwareAuthToken)); 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 402886b0e92c..3c9cceddb5fd 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 @@ import com.android.server.biometrics.sensors.GenerateChallengeClient; */ 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 @@ class FingerprintGenerateChallengeClient extends GenerateChallengeClient<ISessio @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 9db2fcfd1b5b..8547a689dfb1 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 @@ public class TestHal extends IFingerprint.Stub { 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/hidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java index 83a3d9492b22..db371125478d 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java @@ -120,7 +120,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi @Override protected void startHalOperation() { UdfpsHelper.showUdfpsOverlay(getSensorId(), Utils.getUdfpsAuthReason(this), - mUdfpsOverlayController); + mUdfpsOverlayController, this); try { // GroupId was never used. In fact, groupId is always the same as userId. getFreshDaemon().authenticate(mOperationId, getTargetUserId()); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java index 8acb284667c7..db44aee1c0ed 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java @@ -85,7 +85,7 @@ class FingerprintDetectClient extends AcquisitionClient<IBiometricsFingerprint> protected void startHalOperation() { UdfpsHelper.showUdfpsOverlay(getSensorId(), IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, - mUdfpsOverlayController); + mUdfpsOverlayController, this); try { getFreshDaemon().authenticate(0 /* operationId */, getTargetUserId()); } catch (RemoteException e) { diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java index 33db64c3259b..41d23089a530 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java @@ -84,7 +84,7 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint protected void startHalOperation() { UdfpsHelper.showUdfpsOverlay(getSensorId(), UdfpsHelper.getReasonFromEnrollReason(mEnrollReason), - mUdfpsOverlayController); + mUdfpsOverlayController, this); try { // GroupId was never used. In fact, groupId is always the same as userId. getFreshDaemon().enroll(mHardwareAuthToken, getTargetUserId(), mTimeoutSec); diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java index 088249e81171..7dfecd56eaf5 100644 --- a/services/core/java/com/android/server/clipboard/ClipboardService.java +++ b/services/core/java/com/android/server/clipboard/ClipboardService.java @@ -179,8 +179,7 @@ public class ClipboardService extends SystemService { private final ContentCaptureManagerInternal mContentCaptureInternal; private final AutofillManagerInternal mAutofillInternal; private final IBinder mPermissionOwner; - private HostClipboardMonitor mHostClipboardMonitor = null; - private Thread mHostMonitorThread = null; + private final HostClipboardMonitor mHostClipboardMonitor; @GuardedBy("mLock") private final SparseArray<PerUserClipboard> mClipboards = new SparseArray<>(); @@ -217,13 +216,15 @@ public class ClipboardService extends SystemService { new String[]{"text/plain"}, new ClipData.Item(contents)); synchronized (mLock) { - setPrimaryClipInternal(getClipboard(0), clip, + setPrimaryClipInternalLocked(getClipboardLocked(0), clip, android.os.Process.SYSTEM_UID, null); } } }); - mHostMonitorThread = new Thread(mHostClipboardMonitor); - mHostMonitorThread.start(); + Thread hostMonitorThread = new Thread(mHostClipboardMonitor); + hostMonitorThread.start(); + } else { + mHostClipboardMonitor = null; } updateConfig(); @@ -378,47 +379,60 @@ public class ClipboardService extends SystemService { @Override public void setPrimaryClip(ClipData clip, String callingPackage, @UserIdInt int userId) { - synchronized (this) { - if (clip == null || clip.getItemCount() <= 0) { - throw new IllegalArgumentException("No items"); - } - final int intendingUid = getIntendingUid(callingPackage, userId); - final int intendingUserId = UserHandle.getUserId(intendingUid); - if (!clipboardAccessAllowed(AppOpsManager.OP_WRITE_CLIPBOARD, callingPackage, - intendingUid, intendingUserId)) { - return; - } - checkDataOwnerLocked(clip, intendingUid); - setPrimaryClipInternal(clip, intendingUid, callingPackage); + checkAndSetPrimaryClip(clip, callingPackage, userId, callingPackage); + } + + @Override + public void setPrimaryClipAsPackage( + ClipData clip, String callingPackage, @UserIdInt int userId, String sourcePackage) { + getContext().enforceCallingOrSelfPermission(Manifest.permission.SET_CLIP_SOURCE, + "Requires SET_CLIP_SOURCE permission"); + checkAndSetPrimaryClip(clip, callingPackage, userId, sourcePackage); + } + + private void checkAndSetPrimaryClip( + ClipData clip, String callingPackage, @UserIdInt int userId, String sourcePackage) { + if (clip == null || clip.getItemCount() <= 0) { + throw new IllegalArgumentException("No items"); + } + final int intendingUid = getIntendingUid(callingPackage, userId); + final int intendingUserId = UserHandle.getUserId(intendingUid); + if (!clipboardAccessAllowed(AppOpsManager.OP_WRITE_CLIPBOARD, callingPackage, + intendingUid, intendingUserId)) { + return; + } + checkDataOwner(clip, intendingUid); + synchronized (mLock) { + setPrimaryClipInternalLocked(clip, intendingUid, sourcePackage); } } @Override public void clearPrimaryClip(String callingPackage, @UserIdInt int userId) { - synchronized (this) { - final int intendingUid = getIntendingUid(callingPackage, userId); - final int intendingUserId = UserHandle.getUserId(intendingUid); - if (!clipboardAccessAllowed(AppOpsManager.OP_WRITE_CLIPBOARD, callingPackage, - intendingUid, intendingUserId)) { - return; - } - setPrimaryClipInternal(null, intendingUid, callingPackage); + final int intendingUid = getIntendingUid(callingPackage, userId); + final int intendingUserId = UserHandle.getUserId(intendingUid); + if (!clipboardAccessAllowed(AppOpsManager.OP_WRITE_CLIPBOARD, callingPackage, + intendingUid, intendingUserId)) { + return; + } + synchronized (mLock) { + setPrimaryClipInternalLocked(null, intendingUid, callingPackage); } } @Override public ClipData getPrimaryClip(String pkg, @UserIdInt int userId) { - synchronized (this) { - final int intendingUid = getIntendingUid(pkg, userId); - final int intendingUserId = UserHandle.getUserId(intendingUid); - if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, pkg, - intendingUid, intendingUserId) - || isDeviceLocked(intendingUserId)) { - return null; - } + final int intendingUid = getIntendingUid(pkg, userId); + final int intendingUserId = UserHandle.getUserId(intendingUid); + if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, pkg, + intendingUid, intendingUserId) + || isDeviceLocked(intendingUserId)) { + return null; + } + synchronized (mLock) { addActiveOwnerLocked(intendingUid, pkg); - PerUserClipboard clipboard = getClipboard(intendingUserId); - maybeNotify(pkg, intendingUid, intendingUserId, clipboard); + PerUserClipboard clipboard = getClipboardLocked(intendingUserId); + maybeNotifyLocked(pkg, intendingUid, intendingUserId, clipboard); return clipboard.primaryClip; } } @@ -426,15 +440,15 @@ public class ClipboardService extends SystemService { @Override public ClipDescription getPrimaryClipDescription(String callingPackage, @UserIdInt int userId) { - synchronized (this) { - final int intendingUid = getIntendingUid(callingPackage, userId); - final int intendingUserId = UserHandle.getUserId(intendingUid); - if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage, - intendingUid, intendingUserId, false) - || isDeviceLocked(intendingUserId)) { - return null; - } - PerUserClipboard clipboard = getClipboard(intendingUserId); + final int intendingUid = getIntendingUid(callingPackage, userId); + final int intendingUserId = UserHandle.getUserId(intendingUid); + if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage, + intendingUid, intendingUserId, false) + || isDeviceLocked(intendingUserId)) { + return null; + } + synchronized (mLock) { + PerUserClipboard clipboard = getClipboardLocked(intendingUserId); return clipboard.primaryClip != null ? clipboard.primaryClip.getDescription() : null; } @@ -442,25 +456,25 @@ public class ClipboardService extends SystemService { @Override public boolean hasPrimaryClip(String callingPackage, @UserIdInt int userId) { - synchronized (this) { - final int intendingUid = getIntendingUid(callingPackage, userId); - final int intendingUserId = UserHandle.getUserId(intendingUid); - if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage, - intendingUid, intendingUserId, false) - || isDeviceLocked(intendingUserId)) { - return false; - } - return getClipboard(intendingUserId).primaryClip != null; + final int intendingUid = getIntendingUid(callingPackage, userId); + final int intendingUserId = UserHandle.getUserId(intendingUid); + if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage, + intendingUid, intendingUserId, false) + || isDeviceLocked(intendingUserId)) { + return false; + } + synchronized (mLock) { + return getClipboardLocked(intendingUserId).primaryClip != null; } } @Override public void addPrimaryClipChangedListener(IOnPrimaryClipChangedListener listener, String callingPackage, @UserIdInt int userId) { - synchronized (this) { - final int intendingUid = getIntendingUid(callingPackage, userId); - final int intendingUserId = UserHandle.getUserId(intendingUid); - getClipboard(intendingUserId).primaryClipListeners.register(listener, + final int intendingUid = getIntendingUid(callingPackage, userId); + final int intendingUserId = UserHandle.getUserId(intendingUid); + synchronized (mLock) { + getClipboardLocked(intendingUserId).primaryClipListeners.register(listener, new ListenerInfo(intendingUid, callingPackage)); } } @@ -468,23 +482,23 @@ public class ClipboardService extends SystemService { @Override public void removePrimaryClipChangedListener(IOnPrimaryClipChangedListener listener, String callingPackage, @UserIdInt int userId) { - synchronized (this) { - final int intendingUserId = getIntendingUserId(callingPackage, userId); - getClipboard(intendingUserId).primaryClipListeners.unregister(listener); + final int intendingUserId = getIntendingUserId(callingPackage, userId); + synchronized (mLock) { + getClipboardLocked(intendingUserId).primaryClipListeners.unregister(listener); } } @Override public boolean hasClipboardText(String callingPackage, int userId) { - synchronized (this) { - final int intendingUid = getIntendingUid(callingPackage, userId); - final int intendingUserId = UserHandle.getUserId(intendingUid); - if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage, - intendingUid, intendingUserId, false) - || isDeviceLocked(intendingUserId)) { - return false; - } - PerUserClipboard clipboard = getClipboard(intendingUserId); + final int intendingUid = getIntendingUid(callingPackage, userId); + final int intendingUserId = UserHandle.getUserId(intendingUid); + if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage, + intendingUid, intendingUserId, false) + || isDeviceLocked(intendingUserId)) { + return false; + } + synchronized (mLock) { + PerUserClipboard clipboard = getClipboardLocked(intendingUserId); if (clipboard.primaryClip != null) { CharSequence text = clipboard.primaryClip.getItemAt(0).getText(); return text != null && text.length() > 0; @@ -492,17 +506,36 @@ public class ClipboardService extends SystemService { return false; } } - }; - private PerUserClipboard getClipboard(@UserIdInt int userId) { - synchronized (mLock) { - PerUserClipboard puc = mClipboards.get(userId); - if (puc == null) { - puc = new PerUserClipboard(userId); - mClipboards.put(userId, puc); + @Override + public String getPrimaryClipSource(String callingPackage, int userId) { + getContext().enforceCallingOrSelfPermission(Manifest.permission.SET_CLIP_SOURCE, + "Requires SET_CLIP_SOURCE permission"); + final int intendingUid = getIntendingUid(callingPackage, userId); + final int intendingUserId = UserHandle.getUserId(intendingUid); + if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage, + intendingUid, intendingUserId, false) + || isDeviceLocked(intendingUserId)) { + return null; } - return puc; + synchronized (mLock) { + PerUserClipboard clipboard = getClipboardLocked(intendingUserId); + if (clipboard.primaryClip != null) { + return clipboard.mPrimaryClipPackage; + } + return null; + } + } + }; + + @GuardedBy("mLock") + private PerUserClipboard getClipboardLocked(@UserIdInt int userId) { + PerUserClipboard puc = mClipboards.get(userId); + if (puc == null) { + puc = new PerUserClipboard(userId); + mClipboards.put(userId, puc); } + return puc; } List<UserInfo> getRelatedProfiles(@UserIdInt int userId) { @@ -533,10 +566,13 @@ public class ClipboardService extends SystemService { } void setPrimaryClipInternal(@Nullable ClipData clip, int uid) { - setPrimaryClipInternal(clip, uid, null); + synchronized (mLock) { + setPrimaryClipInternalLocked(clip, uid, null); + } } - private void setPrimaryClipInternal( + @GuardedBy("mLock") + private void setPrimaryClipInternalLocked( @Nullable ClipData clip, int uid, @Nullable String sourcePackage) { // Push clipboard to host, if any if (mHostClipboardMonitor != null) { @@ -553,7 +589,7 @@ public class ClipboardService extends SystemService { // Update this user final int userId = UserHandle.getUserId(uid); - setPrimaryClipInternal(getClipboard(userId), clip, uid, sourcePackage); + setPrimaryClipInternalLocked(getClipboardLocked(userId), clip, uid, sourcePackage); // Update related users List<UserInfo> related = getRelatedProfiles(userId); @@ -587,8 +623,8 @@ public class ClipboardService extends SystemService { final boolean canCopyIntoProfile = !hasRestriction( UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, id); if (canCopyIntoProfile) { - setPrimaryClipInternal( - getClipboard(id), clip, uid, sourcePackage); + setPrimaryClipInternalLocked( + getClipboardLocked(id), clip, uid, sourcePackage); } } } @@ -598,10 +634,13 @@ public class ClipboardService extends SystemService { void setPrimaryClipInternal(PerUserClipboard clipboard, @Nullable ClipData clip, int uid) { - setPrimaryClipInternal(clipboard, clip, uid, null); + synchronized ("mLock") { + setPrimaryClipInternalLocked(clipboard, clip, uid, null); + } } - private void setPrimaryClipInternal(PerUserClipboard clipboard, @Nullable ClipData clip, + @GuardedBy("mLock") + private void setPrimaryClipInternalLocked(PerUserClipboard clipboard, @Nullable ClipData clip, int uid, @Nullable String sourcePackage) { revokeUris(clipboard); clipboard.activePermissionOwners.clear(); @@ -657,7 +696,7 @@ public class ClipboardService extends SystemService { } } - private final void checkUriOwnerLocked(Uri uri, int sourceUid) { + private void checkUriOwner(Uri uri, int sourceUid) { if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return; final long ident = Binder.clearCallingIdentity(); @@ -672,24 +711,24 @@ public class ClipboardService extends SystemService { } } - private final void checkItemOwnerLocked(ClipData.Item item, int uid) { + private void checkItemOwner(ClipData.Item item, int uid) { if (item.getUri() != null) { - checkUriOwnerLocked(item.getUri(), uid); + checkUriOwner(item.getUri(), uid); } Intent intent = item.getIntent(); if (intent != null && intent.getData() != null) { - checkUriOwnerLocked(intent.getData(), uid); + checkUriOwner(intent.getData(), uid); } } - private final void checkDataOwnerLocked(ClipData data, int uid) { + private void checkDataOwner(ClipData data, int uid) { final int N = data.getItemCount(); for (int i=0; i<N; i++) { - checkItemOwnerLocked(data.getItemAt(i), uid); + checkItemOwner(data.getItemAt(i), uid); } } - private final void grantUriLocked(Uri uri, int sourceUid, String targetPkg, + private void grantUriPermission(Uri uri, int sourceUid, String targetPkg, int targetUserId) { if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return; @@ -707,18 +746,19 @@ public class ClipboardService extends SystemService { } } - private final void grantItemLocked(ClipData.Item item, int sourceUid, String targetPkg, + private void grantItemPermission(ClipData.Item item, int sourceUid, String targetPkg, int targetUserId) { if (item.getUri() != null) { - grantUriLocked(item.getUri(), sourceUid, targetPkg, targetUserId); + grantUriPermission(item.getUri(), sourceUid, targetPkg, targetUserId); } Intent intent = item.getIntent(); if (intent != null && intent.getData() != null) { - grantUriLocked(intent.getData(), sourceUid, targetPkg, targetUserId); + grantUriPermission(intent.getData(), sourceUid, targetPkg, targetUserId); } } - private final void addActiveOwnerLocked(int uid, String pkg) { + @GuardedBy("mLock") + private void addActiveOwnerLocked(int uid, String pkg) { final IPackageManager pm = AppGlobals.getPackageManager(); final int targetUserHandle = UserHandle.getCallingUserId(); final long oldIdentity = Binder.clearCallingIdentity(); @@ -736,18 +776,18 @@ public class ClipboardService extends SystemService { } finally { Binder.restoreCallingIdentity(oldIdentity); } - PerUserClipboard clipboard = getClipboard(UserHandle.getUserId(uid)); + PerUserClipboard clipboard = getClipboardLocked(UserHandle.getUserId(uid)); if (clipboard.primaryClip != null && !clipboard.activePermissionOwners.contains(pkg)) { final int N = clipboard.primaryClip.getItemCount(); for (int i=0; i<N; i++) { - grantItemLocked(clipboard.primaryClip.getItemAt(i), clipboard.primaryClipUid, pkg, - UserHandle.getUserId(uid)); + grantItemPermission(clipboard.primaryClip.getItemAt(i), clipboard.primaryClipUid, + pkg, UserHandle.getUserId(uid)); } clipboard.activePermissionOwners.add(pkg); } } - private final void revokeUriLocked(Uri uri, int sourceUid) { + private void revokeUriPermission(Uri uri, int sourceUid) { if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return; final long ident = Binder.clearCallingIdentity(); @@ -761,23 +801,23 @@ public class ClipboardService extends SystemService { } } - private final void revokeItemLocked(ClipData.Item item, int sourceUid) { + private void revokeItemPermission(ClipData.Item item, int sourceUid) { if (item.getUri() != null) { - revokeUriLocked(item.getUri(), sourceUid); + revokeUriPermission(item.getUri(), sourceUid); } Intent intent = item.getIntent(); if (intent != null && intent.getData() != null) { - revokeUriLocked(intent.getData(), sourceUid); + revokeUriPermission(intent.getData(), sourceUid); } } - private final void revokeUris(PerUserClipboard clipboard) { + private void revokeUris(PerUserClipboard clipboard) { if (clipboard.primaryClip == null) { return; } final int N = clipboard.primaryClip.getItemCount(); for (int i=0; i<N; i++) { - revokeItemLocked(clipboard.primaryClip.getItemAt(i), clipboard.primaryClipUid); + revokeItemPermission(clipboard.primaryClip.getItemAt(i), clipboard.primaryClipUid); } } @@ -867,15 +907,14 @@ public class ClipboardService extends SystemService { * Potentially notifies the user (via a toast) about an app accessing the clipboard. * TODO(b/167676460): STOPSHIP as we don't want this code as-is to launch. Just an experiment. */ - private void maybeNotify(String callingPackage, int uid, @UserIdInt int userId, + @GuardedBy("mLock") + private void maybeNotifyLocked(String callingPackage, int uid, @UserIdInt int userId, PerUserClipboard clipboard) { if (clipboard.primaryClip == null) { return; } - synchronized (mLock) { - if (!mShowAccessNotifications) { - return; - } + if (!mShowAccessNotifications) { + return; } // Don't notify if the app accessing the clipboard is the same as the current owner. if (UserHandle.isSameApp(uid, clipboard.primaryClipUid)) { diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index cac6cab7074e..1d0e11569c80 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.NetworkCapabilities; 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 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { 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/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index ae0e001e8417..df870125e253 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -17,6 +17,7 @@ package com.android.server.content; import static android.os.PowerWhitelistManager.REASON_SYNC_MANAGER; +import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED; import static com.android.server.content.SyncLogger.logSafe; @@ -1672,6 +1673,7 @@ public class SyncManager { dic.addPowerSaveTempWhitelistApp(Process.SYSTEM_UID, syncOperation.owningPackage, mConstants.getKeyExemptionTempWhitelistDurationInSeconds() * 1000, + TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED, UserHandle.getUserId(syncOperation.owningUid), /* sync=*/ false, REASON_SYNC_MANAGER, "sync by top app"); } diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java index 658d27f43313..217f1cd56598 100644 --- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java +++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java @@ -78,9 +78,6 @@ import java.util.Optional; public final class DeviceStateManagerService extends SystemService { private static final String TAG = "DeviceStateManagerService"; private static final boolean DEBUG = false; - // The device state to use as a placeholder before callback from the DeviceStateProvider occurs. - private static final DeviceState UNSPECIFIED_DEVICE_STATE = - new DeviceState(MINIMUM_DEVICE_STATE, "UNSPECIFIED"); private final Object mLock = new Object(); @NonNull @@ -92,11 +89,11 @@ public final class DeviceStateManagerService extends SystemService { @GuardedBy("mLock") private SparseArray<DeviceState> mDeviceStates = new SparseArray<>(); - // The current committed device state. The default of UNSPECIFIED_DEVICE_STATE will be replaced - // by the current state after the initial callback from the DeviceStateProvider. + // The current committed device state. Will be empty until the first device state provided by + // the DeviceStateProvider is committed. @GuardedBy("mLock") @NonNull - private DeviceState mCommittedState = UNSPECIFIED_DEVICE_STATE; + private Optional<DeviceState> mCommittedState = Optional.empty(); // The device state that is currently awaiting callback from the policy to be committed. @GuardedBy("mLock") @NonNull @@ -105,10 +102,11 @@ public final class DeviceStateManagerService extends SystemService { @GuardedBy("mLock") private boolean mIsPolicyWaitingForState = false; - // The device state that is set by the device state provider. + // The device state that is set by the DeviceStateProvider. Will be empty until the first + // callback from the provider and then will always contain the most recent value. @GuardedBy("mLock") @NonNull - private DeviceState mBaseState = UNSPECIFIED_DEVICE_STATE; + private Optional<DeviceState> mBaseState = Optional.empty(); // List of processes registered to receive notifications about changes to device state and // request status indexed by process id. @@ -142,11 +140,14 @@ public final class DeviceStateManagerService extends SystemService { /** * Returns the current state the system is in. Note that the system may be in the process of * configuring a different state. + * <p> + * Note: This method will return {@link Optional#empty()} if called before the first state has + * been committed, otherwise it will return the last committed state. * * @see #getPendingState() */ @NonNull - DeviceState getCommittedState() { + Optional<DeviceState> getCommittedState() { synchronized (mLock) { return mCommittedState; } @@ -167,11 +168,15 @@ public final class DeviceStateManagerService extends SystemService { /** * Returns the base state. The service will configure the device to match the base state when * there is no active request to override the base state. + * <p> + * Note: This method will return {@link Optional#empty()} if called before a base state is + * provided to the service by the {@link DeviceStateProvider}, otherwise it will return the + * most recent provided value. * * @see #getOverrideState() */ @NonNull - DeviceState getBaseState() { + Optional<DeviceState> getBaseState() { synchronized (mLock) { return mBaseState; } @@ -223,9 +228,14 @@ public final class DeviceStateManagerService extends SystemService { @NonNull private DeviceStateInfo getDeviceStateInfoLocked() { + if (!mBaseState.isPresent() || !mCommittedState.isPresent()) { + throw new IllegalStateException("Trying to get the current DeviceStateInfo before the" + + " initial state has been committed."); + } + final int[] supportedStates = getSupportedStateIdentifiersLocked(); - final int baseState = mBaseState.getIdentifier(); - final int currentState = mCommittedState.getIdentifier(); + final int baseState = mBaseState.get().getIdentifier(); + final int currentState = mCommittedState.get().getIdentifier(); return new DeviceStateInfo(supportedStates, baseState, currentState); } @@ -237,6 +247,7 @@ public final class DeviceStateManagerService extends SystemService { private void updateSupportedStates(DeviceState[] supportedDeviceStates) { boolean updatedPendingState; + boolean hasBaseState; synchronized (mLock) { final int[] oldStateIdentifiers = getSupportedStateIdentifiersLocked(); @@ -260,9 +271,10 @@ public final class DeviceStateManagerService extends SystemService { } updatedPendingState = updatePendingStateLocked(); + hasBaseState = mBaseState.isPresent(); } - if (!updatedPendingState) { + if (hasBaseState && !updatedPendingState) { // If the change in the supported states didn't result in a change of the pending state // commitPendingState() will never be called and the callbacks will never be notified // of the change. @@ -306,11 +318,11 @@ public final class DeviceStateManagerService extends SystemService { } final DeviceState baseState = baseStateOptional.get(); - if (mBaseState.equals(baseState)) { + if (mBaseState.isPresent() && mBaseState.get().equals(baseState)) { // Base state hasn't changed. Nothing to do. return; } - mBaseState = baseState; + mBaseState = Optional.of(baseState); final int requestSize = mRequestRecords.size(); for (int i = 0; i < requestSize; i++) { @@ -351,9 +363,10 @@ public final class DeviceStateManagerService extends SystemService { final DeviceState stateToConfigure; if (!mRequestRecords.isEmpty()) { stateToConfigure = mRequestRecords.get(mRequestRecords.size() - 1).mRequestedState; - } else if (isSupportedStateLocked(mBaseState.getIdentifier())) { + } else if (mBaseState.isPresent() + && isSupportedStateLocked(mBaseState.get().getIdentifier())) { // Base state could have recently become unsupported after a change in supported states. - stateToConfigure = mBaseState; + stateToConfigure = mBaseState.get(); } else { stateToConfigure = null; } @@ -363,7 +376,7 @@ public final class DeviceStateManagerService extends SystemService { return false; } - if (stateToConfigure.equals(mCommittedState)) { + if (mCommittedState.isPresent() && stateToConfigure.equals(mCommittedState.get())) { // The state requesting to be committed already matches the current committed state. return false; } @@ -417,15 +430,15 @@ public final class DeviceStateManagerService extends SystemService { private void commitPendingState() { // Update the current state. synchronized (mLock) { + final DeviceState newState = mPendingState.get(); if (DEBUG) { - Slog.d(TAG, "Committing state: " + mPendingState); + Slog.d(TAG, "Committing state: " + newState); } - mCommittedState = mPendingState.get(); if (!mRequestRecords.isEmpty()) { final OverrideRequestRecord topRequest = mRequestRecords.get(mRequestRecords.size() - 1); - if (topRequest.mRequestedState.getIdentifier() == mCommittedState.getIdentifier()) { + if (topRequest.mRequestedState.getIdentifier() == newState.getIdentifier()) { // The top request could have come in while the service was awaiting callback // from the policy. In that case we only set it to active if it matches the // current committed state, otherwise it will be set to active when its @@ -434,6 +447,7 @@ public final class DeviceStateManagerService extends SystemService { } } + mCommittedState = Optional.of(newState); mPendingState = Optional.empty(); updatePendingStateLocked(); } @@ -503,19 +517,30 @@ public final class DeviceStateManagerService extends SystemService { } private void registerProcess(int pid, IDeviceStateManagerCallback callback) { + DeviceStateInfo currentInfo; + ProcessRecord record; + // Grab the lock to register the callback and get the current state. synchronized (mLock) { if (mProcessRecords.contains(pid)) { throw new SecurityException("The calling process has already registered an" + " IDeviceStateManagerCallback."); } - ProcessRecord record = new ProcessRecord(callback, pid); + record = new ProcessRecord(callback, pid); try { callback.asBinder().linkToDeath(record, 0); } catch (RemoteException ex) { throw new RuntimeException(ex); } mProcessRecords.put(pid, record); + + currentInfo = mCommittedState.isPresent() ? getDeviceStateInfoLocked() : null; + } + + if (currentInfo != null) { + // If there is not a committed state we'll wait to notify the process of the initial + // value. + record.notifyDeviceStateInfoAsync(currentInfo); } } diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java index f3466006bd30..56b68b73cb57 100644 --- a/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java +++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java @@ -18,6 +18,7 @@ package com.android.server.devicestate; import static android.Manifest.permission.CONTROL_DEVICE_STATE; +import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.hardware.devicestate.DeviceStateManager; @@ -63,14 +64,14 @@ public class DeviceStateManagerShellCommand extends ShellCommand { } private void printState(PrintWriter pw) { - DeviceState committedState = mService.getCommittedState(); - DeviceState baseState = mService.getBaseState(); + Optional<DeviceState> committedState = mService.getCommittedState(); + Optional<DeviceState> baseState = mService.getBaseState(); Optional<DeviceState> overrideState = mService.getOverrideState(); - pw.println("Committed state: " + committedState); + pw.println("Committed state: " + toString(committedState)); if (overrideState.isPresent()) { pw.println("----------------------"); - pw.println("Base state: " + baseState); + pw.println("Base state: " + toString(baseState)); pw.println("Override state: " + overrideState.get()); } } @@ -143,4 +144,8 @@ public class DeviceStateManagerShellCommand extends ShellCommand { pw.println(" print-states"); pw.println(" Return list of currently supported device states."); } + + private static String toString(@NonNull Optional<DeviceState> state) { + return state.isPresent() ? state.get().toString() : "(none)"; + } } diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index 3709963b7caa..d88896c01e4b 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -683,12 +683,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { setDisplayState(Display.STATE_ON); currentState = Display.STATE_ON; } else { - if (oldState == Display.STATE_UNKNOWN) { - // There's no guarantee about what the initial state is - // at startup, so we have to set it if previous was UNKNOWN. - setDisplayState(state); - } - return; + return; // old state and new state is off } } @@ -767,6 +762,12 @@ final class LocalDisplayAdapter extends DisplayAdapter { } 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/DevicePowerStatusAction.java b/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java index 7b646b36124b..e01c37901563 100644 --- a/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java +++ b/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java @@ -22,11 +22,8 @@ import android.hardware.hdmi.HdmiPlaybackClient; import android.hardware.hdmi.HdmiPlaybackClient.DisplayStatusCallback; import android.hardware.hdmi.IHdmiControlCallback; import android.hardware.tv.cec.V1_0.SendMessageResult; -import android.os.RemoteException; import android.util.Slog; -import java.util.ArrayList; -import java.util.List; /** * Feature action that queries the power status of other device. This action is initiated via @@ -42,7 +39,6 @@ final class DevicePowerStatusAction extends HdmiCecFeatureAction { private static final int STATE_WAITING_FOR_REPORT_POWER_STATUS = 1; private final int mTargetAddress; - private final List<IHdmiControlCallback> mCallbacks = new ArrayList<>(); // Retry the power status query as it might happen when the target device is waking up. In // that case a device may be quite busy and can fail to respond within the 2s timeout. @@ -59,9 +55,8 @@ final class DevicePowerStatusAction extends HdmiCecFeatureAction { private DevicePowerStatusAction(HdmiCecLocalDevice localDevice, int targetAddress, IHdmiControlCallback callback) { - super(localDevice); + super(localDevice, callback); mTargetAddress = targetAddress; - addCallback(callback); } @Override @@ -74,8 +69,7 @@ final class DevicePowerStatusAction extends HdmiCecFeatureAction { && deviceInfo.getCecVersion() >= HdmiControlManager.HDMI_CEC_VERSION_2_0) { int powerStatus = deviceInfo.getDevicePowerStatus(); if (powerStatus != HdmiControlManager.POWER_STATUS_UNKNOWN) { - invokeCallback(powerStatus); - finish(); + finishWithCallback(powerStatus); return true; } } @@ -93,8 +87,7 @@ final class DevicePowerStatusAction extends HdmiCecFeatureAction { // the device is not present or not capable of CEC. if (error == SendMessageResult.NACK) { // Got no response from TV. Report status 'unknown'. - invokeCallback(HdmiControlManager.POWER_STATUS_UNKNOWN); - finish(); + finishWithCallback(HdmiControlManager.POWER_STATUS_UNKNOWN); } }); } @@ -107,8 +100,7 @@ final class DevicePowerStatusAction extends HdmiCecFeatureAction { } if (cmd.getOpcode() == Constants.MESSAGE_REPORT_POWER_STATUS) { int status = cmd.getParams()[0]; - invokeCallback(status); - finish(); + finishWithCallback(status); return true; } return false; @@ -127,22 +119,7 @@ final class DevicePowerStatusAction extends HdmiCecFeatureAction { } // Got no response from TV. Report status 'unknown'. - invokeCallback(HdmiControlManager.POWER_STATUS_UNKNOWN); - finish(); - } - } - - public void addCallback(IHdmiControlCallback callback) { - mCallbacks.add(callback); - } - - private void invokeCallback(int result) { - try { - for (IHdmiControlCallback callback : mCallbacks) { - callback.onComplete(result); - } - } catch (RemoteException e) { - Slog.e(TAG, "Callback failed:" + e); + finishWithCallback(HdmiControlManager.POWER_STATUS_UNKNOWN); } } } diff --git a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java index 983b6b5bceb4..c23e2e691b55 100644 --- a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java +++ b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java @@ -21,7 +21,6 @@ import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.hdmi.HdmiTvClient; import android.hardware.hdmi.IHdmiControlCallback; import android.hardware.tv.cec.V1_0.SendMessageResult; -import android.os.RemoteException; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; @@ -63,7 +62,6 @@ final class DeviceSelectAction extends HdmiCecFeatureAction { static final int STATE_WAIT_FOR_DEVICE_POWER_ON = 3; private final HdmiDeviceInfo mTarget; - private final IHdmiControlCallback mCallback; private final HdmiCecMessage mGivePowerStatus; private final boolean mIsCec20; @@ -86,8 +84,7 @@ final class DeviceSelectAction extends HdmiCecFeatureAction { @VisibleForTesting DeviceSelectAction(HdmiCecLocalDeviceTv source, HdmiDeviceInfo target, IHdmiControlCallback callback, boolean isCec20) { - super(source); - mCallback = callback; + super(source, callback); mTarget = target; mGivePowerStatus = HdmiCecMessageBuilder.buildGiveDevicePowerStatus( getSourceAddress(), getTargetAddress()); @@ -108,7 +105,7 @@ final class DeviceSelectAction extends HdmiCecFeatureAction { if (!mIsCec20 || targetPowerStatus == HdmiControlManager.POWER_STATUS_UNKNOWN) { queryDevicePowerStatus(); } else if (targetPowerStatus == HdmiControlManager.POWER_STATUS_ON) { - invokeCallbackAndFinish(HdmiControlManager.RESULT_SUCCESS); + finishWithCallback(HdmiControlManager.RESULT_SUCCESS); return true; } mState = STATE_WAIT_FOR_REPORT_POWER_STATUS; @@ -117,14 +114,17 @@ final class DeviceSelectAction extends HdmiCecFeatureAction { } private void queryDevicePowerStatus() { - sendCommand(mGivePowerStatus, new SendMessageCallback() { - @Override - public void onSendCompleted(int error) { - if (error != SendMessageResult.SUCCESS) { - invokeCallbackAndFinish(HdmiControlManager.RESULT_COMMUNICATION_FAILED); - } - } - }); + sendCommand( + mGivePowerStatus, + new SendMessageCallback() { + @Override + public void onSendCompleted(int error) { + if (error != SendMessageResult.SUCCESS) { + finishWithCallback(HdmiControlManager.RESULT_COMMUNICATION_FAILED); + return; + } + } + }); } @Override @@ -189,7 +189,7 @@ final class DeviceSelectAction extends HdmiCecFeatureAction { switch (mState) { case STATE_WAIT_FOR_REPORT_POWER_STATUS: if (tv().isPowerStandbyOrTransient()) { - invokeCallbackAndFinish(HdmiControlManager.RESULT_INCORRECT_MODE); + finishWithCallback(HdmiControlManager.RESULT_INCORRECT_MODE); return; } selectDevice(); @@ -217,7 +217,7 @@ final class DeviceSelectAction extends HdmiCecFeatureAction { if (!mIsCec20) { sendSetStreamPath(); } - invokeCallbackAndFinish(HdmiControlManager.RESULT_SUCCESS); + finishWithCallback(HdmiControlManager.RESULT_SUCCESS); } private void sendSetStreamPath() { @@ -228,15 +228,4 @@ final class DeviceSelectAction extends HdmiCecFeatureAction { sendCommand(HdmiCecMessageBuilder.buildSetStreamPath( getSourceAddress(), mTarget.getPhysicalAddress())); } - - private void invokeCallbackAndFinish(int result) { - if (mCallback != null) { - try { - mCallback.onComplete(result); - } catch (RemoteException e) { - Slog.e(TAG, "Callback failed:" + e); - } - } - finish(); - } } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java b/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java index 2da698be56be..2e1ff038931d 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java @@ -15,9 +15,11 @@ */ package com.android.server.hdmi; +import android.hardware.hdmi.IHdmiControlCallback; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.RemoteException; import android.util.Pair; import android.util.Slog; @@ -25,6 +27,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.server.hdmi.HdmiControlService.DevicePollingCallback; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -61,7 +64,20 @@ abstract class HdmiCecFeatureAction { private ArrayList<Pair<HdmiCecFeatureAction, Runnable>> mOnFinishedCallbacks; + final List<IHdmiControlCallback> mCallbacks = new ArrayList<>(); + HdmiCecFeatureAction(HdmiCecLocalDevice source) { + this(source, new ArrayList<>()); + } + + HdmiCecFeatureAction(HdmiCecLocalDevice source, IHdmiControlCallback callback) { + this(source, Arrays.asList(callback)); + } + + HdmiCecFeatureAction(HdmiCecLocalDevice source, List<IHdmiControlCallback> callbacks) { + for (IHdmiControlCallback callback : callbacks) { + addCallback(callback); + } mSource = source; mService = mSource.getService(); mActionTimer = createActionTimer(mService.getServiceLooper()); @@ -282,4 +298,26 @@ abstract class HdmiCecFeatureAction { } mOnFinishedCallbacks.add(Pair.create(action, runnable)); } + + protected void finishWithCallback(int returnCode) { + invokeCallback(returnCode); + finish(); + } + + public void addCallback(IHdmiControlCallback callback) { + mCallbacks.add(callback); + } + + private void invokeCallback(int result) { + try { + for (IHdmiControlCallback callback : mCallbacks) { + if (callback == null) { + continue; + } + callback.onComplete(result); + } + } catch (RemoteException e) { + Slog.e(TAG, "Callback failed:" + e); + } + } } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index 18f7a068657f..7235a921254d 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -1073,7 +1073,21 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { // 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/HdmiControlShellCommand.java b/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java index a1e613635116..7226cc22f95f 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java @@ -35,9 +35,23 @@ final class HdmiControlShellCommand extends ShellCommand { private final IHdmiControlService.Stub mBinderService; + final CountDownLatch mLatch; + AtomicInteger mCecResult; + IHdmiControlCallback.Stub mHdmiControlCallback; HdmiControlShellCommand(IHdmiControlService.Stub binderService) { mBinderService = binderService; + mLatch = new CountDownLatch(1); + mCecResult = new AtomicInteger(); + mHdmiControlCallback = + new IHdmiControlCallback.Stub() { + @Override + public void onComplete(int result) { + getOutPrintWriter().println(" done (" + getResultString(result) + ")"); + mCecResult.set(result); + mLatch.countDown(); + } + }; } @Override @@ -74,6 +88,8 @@ final class HdmiControlShellCommand extends ShellCommand { pw.println(" Get the current value of a CEC setting"); pw.println(" cec_setting set <setting name> <value>"); pw.println(" Set the value of a CEC setting"); + pw.println(" setsystemaudiomode, setsam [on|off]"); + pw.println(" Sets the System Audio Mode feature on or off on TV devices"); } private int handleShellCommand(String cmd) throws RemoteException { @@ -87,6 +103,9 @@ final class HdmiControlShellCommand extends ShellCommand { return vendorCommand(pw); case "cec_setting": return cecSetting(pw); + case "setsystemaudiomode": + case "setsam": + return setSystemAudioMode(pw); } getErrPrintWriter().println("Unhandled command: " + cmd); @@ -94,28 +113,14 @@ final class HdmiControlShellCommand extends ShellCommand { } private int oneTouchPlay(PrintWriter pw) throws RemoteException { - final CountDownLatch latch = new CountDownLatch(1); - AtomicInteger cecResult = new AtomicInteger(); pw.print("Sending One Touch Play..."); - mBinderService.oneTouchPlay(new IHdmiControlCallback.Stub() { - @Override - public void onComplete(int result) { - pw.println(" done (" + result + ")"); - latch.countDown(); - cecResult.set(result); - } - }); + mBinderService.oneTouchPlay(mHdmiControlCallback); - try { - if (!latch.await(HdmiConfig.TIMEOUT_MS, TimeUnit.MILLISECONDS)) { - getErrPrintWriter().println("One Touch Play timed out."); - return 1; - } - } catch (InterruptedException e) { - getErrPrintWriter().println("Caught InterruptedException"); - Thread.currentThread().interrupt(); + if (!receiveCallback("One Touch Play")) { + return 1; } - return cecResult.get() == HdmiControlManager.RESULT_SUCCESS ? 0 : 1; + + return mCecResult.get() == HdmiControlManager.RESULT_SUCCESS ? 0 : 1; } private int vendorCommand(PrintWriter pw) throws RemoteException { @@ -198,4 +203,62 @@ final class HdmiControlShellCommand extends ShellCommand { throw new IllegalArgumentException("Unknown operation: " + operation); } } + + private int setSystemAudioMode(PrintWriter pw) throws RemoteException { + if (1 > getRemainingArgsCount()) { + throw new IllegalArgumentException( + "Please indicate if System Audio Mode should be turned \"on\" or \"off\"."); + } + + String arg = getNextArg(); + if (arg.equals("on")) { + pw.println("Setting System Audio Mode on"); + mBinderService.setSystemAudioMode(true, mHdmiControlCallback); + } else if (arg.equals("off")) { + pw.println("Setting System Audio Mode off"); + mBinderService.setSystemAudioMode(false, mHdmiControlCallback); + } else { + throw new IllegalArgumentException( + "Please indicate if System Audio Mode should be turned \"on\" or \"off\"."); + } + + if (!receiveCallback("Set System Audio Mode")) { + return 1; + } + + return mCecResult.get() == HdmiControlManager.RESULT_SUCCESS ? 0 : 1; + } + + private boolean receiveCallback(String command) { + try { + if (!mLatch.await(HdmiConfig.TIMEOUT_MS, TimeUnit.MILLISECONDS)) { + getErrPrintWriter().println(command + " timed out."); + return false; + } + } catch (InterruptedException e) { + getErrPrintWriter().println("Caught InterruptedException"); + Thread.currentThread().interrupt(); + } + return true; + } + + private String getResultString(int result) { + switch (result) { + case HdmiControlManager.RESULT_SUCCESS: + return "Success"; + case HdmiControlManager.RESULT_TIMEOUT: + return "Timeout"; + case HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE: + return "Source not available"; + case HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE: + return "Target not available"; + case HdmiControlManager.RESULT_EXCEPTION: + return "Exception"; + case HdmiControlManager.RESULT_INCORRECT_MODE: + return "Incorrect mode"; + case HdmiControlManager.RESULT_COMMUNICATION_FAILED: + return "Communication Failed"; + } + return Integer.toString(result); + } } diff --git a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java index ea6e61582ea0..02b09b15b464 100644 --- a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java +++ b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java @@ -18,11 +18,8 @@ package com.android.server.hdmi; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback; import android.hardware.hdmi.IHdmiControlCallback; -import android.os.RemoteException; import android.util.Slog; -import java.util.ArrayList; -import java.util.List; /** * Feature action that performs one touch play against TV/Display device. This action is initiated @@ -50,7 +47,6 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction { private static final int LOOP_COUNTER_MAX = 10; private final int mTargetAddress; - private final List<IHdmiControlCallback> mCallbacks = new ArrayList<>(); private int mPowerStatusCounter = 0; @@ -69,9 +65,8 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction { private OneTouchPlayAction(HdmiCecLocalDevice localDevice, int targetAddress, IHdmiControlCallback callback) { - super(localDevice); + super(localDevice, callback); mTargetAddress = targetAddress; - addCallback(callback); } @Override @@ -121,8 +116,7 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction { int status = cmd.getParams()[0]; if (status == HdmiControlManager.POWER_STATUS_ON) { broadcastActiveSource(); - invokeCallback(HdmiControlManager.RESULT_SUCCESS); - finish(); + finishWithCallback(HdmiControlManager.RESULT_SUCCESS); } return true; } @@ -140,26 +134,11 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction { addTimer(mState, HdmiConfig.TIMEOUT_MS); } else { // Couldn't wake up the TV for whatever reason. Report failure. - invokeCallback(HdmiControlManager.RESULT_TIMEOUT); - finish(); + finishWithCallback(HdmiControlManager.RESULT_TIMEOUT); } } } - public void addCallback(IHdmiControlCallback callback) { - mCallbacks.add(callback); - } - - private void invokeCallback(int result) { - try { - for (IHdmiControlCallback callback : mCallbacks) { - callback.onComplete(result); - } - } catch (RemoteException e) { - Slog.e(TAG, "Callback failed:" + e); - } - } - private boolean shouldTurnOnConnectedAudioSystem() { HdmiControlService service = mSource.mService; if (service.isAudioSystemDevice()) { @@ -170,4 +149,5 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction { HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE); return sendStandbyOnSleep.equals(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST); } + } diff --git a/services/core/java/com/android/server/hdmi/RoutingControlAction.java b/services/core/java/com/android/server/hdmi/RoutingControlAction.java index 6c147ed5e6d6..b9404e407b88 100644 --- a/services/core/java/com/android/server/hdmi/RoutingControlAction.java +++ b/services/core/java/com/android/server/hdmi/RoutingControlAction.java @@ -16,11 +16,9 @@ package com.android.server.hdmi; -import android.annotation.Nullable; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.hdmi.IHdmiControlCallback; -import android.os.RemoteException; import android.util.Slog; import com.android.server.hdmi.HdmiControlService.SendMessageCallback; @@ -66,15 +64,12 @@ final class RoutingControlAction extends HdmiCecFeatureAction { // <Inactive Source> command. private final boolean mNotifyInputChange; - @Nullable private final IHdmiControlCallback mCallback; - // The latest routing path. Updated by each <Routing Information> from CEC switches. private int mCurrentRoutingPath; RoutingControlAction(HdmiCecLocalDevice localDevice, int path, boolean queryDevicePowerStatus, IHdmiControlCallback callback) { - super(localDevice); - mCallback = callback; + super(localDevice, callback); mCurrentRoutingPath = path; mQueryDevicePowerStatus = queryDevicePowerStatus; // Callback is non-null when routing control action is brought up by binder API. Use @@ -147,11 +142,6 @@ final class RoutingControlAction extends HdmiCecFeatureAction { mCurrentRoutingPath)); } - private void finishWithCallback(int result) { - invokeCallback(result); - finish(); - } - @Override public void handleTimerEvent(int timeoutState) { if (mState != timeoutState || mState == STATE_NONE) { @@ -202,15 +192,4 @@ final class RoutingControlAction extends HdmiCecFeatureAction { finishWithCallback(HdmiControlManager.RESULT_SUCCESS); } } - - private void invokeCallback(int result) { - if (mCallback == null) { - return; - } - try { - mCallback.onComplete(result); - } catch (RemoteException e) { - // Do nothing. - } - } } diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAction.java index a5477e865c40..978c25d0a8c6 100644 --- a/services/core/java/com/android/server/hdmi/SystemAudioAction.java +++ b/services/core/java/com/android/server/hdmi/SystemAudioAction.java @@ -16,13 +16,11 @@ package com.android.server.hdmi; -import android.annotation.Nullable; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.hdmi.IHdmiControlCallback; import android.hardware.tv.cec.V1_0.SendMessageResult; -import android.os.RemoteException; -import android.util.Slog; + import java.util.List; /** @@ -49,8 +47,6 @@ abstract class SystemAudioAction extends HdmiCecFeatureAction { // The target audio status of the action, whether to enable the system audio mode or not. protected boolean mTargetAudioStatus; - @Nullable private final IHdmiControlCallback mCallback; - private int mSendRetryCount = 0; /** @@ -64,11 +60,10 @@ abstract class SystemAudioAction extends HdmiCecFeatureAction { */ SystemAudioAction(HdmiCecLocalDevice source, int avrAddress, boolean targetStatus, IHdmiControlCallback callback) { - super(source); + super(source, callback); HdmiUtils.verifyAddressType(avrAddress, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); mAvrLogicalAddress = avrAddress; mTargetAudioStatus = targetStatus; - mCallback = callback; } // Seq #27 @@ -174,7 +169,7 @@ abstract class SystemAudioAction extends HdmiCecFeatureAction { } protected void startAudioStatusAction() { - addAndStartAction(new SystemAudioStatusAction(tv(), mAvrLogicalAddress, mCallback)); + addAndStartAction(new SystemAudioStatusAction(tv(), mAvrLogicalAddress, mCallbacks)); finish(); } @@ -194,17 +189,4 @@ abstract class SystemAudioAction extends HdmiCecFeatureAction { return; } } - - // TODO: if IHdmiControlCallback is general to other FeatureAction, - // move it into FeatureAction. - protected void finishWithCallback(int returnCode) { - if (mCallback != null) { - try { - mCallback.onComplete(returnCode); - } catch (RemoteException e) { - Slog.e(TAG, "Failed to invoke callback.", e); - } - } - finish(); - } } diff --git a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java index 5d913d12b79f..b4af540b96f5 100644 --- a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java +++ b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java @@ -16,14 +16,14 @@ package com.android.server.hdmi; -import android.annotation.Nullable; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.IHdmiControlCallback; import android.hardware.tv.cec.V1_0.SendMessageResult; -import android.os.RemoteException; -import android.util.Slog; + import com.android.server.hdmi.HdmiControlService.SendMessageCallback; +import java.util.List; + /** * Action to update audio status (volume or mute) of audio amplifier */ @@ -34,13 +34,17 @@ final class SystemAudioStatusAction extends HdmiCecFeatureAction { private static final int STATE_WAIT_FOR_REPORT_AUDIO_STATUS = 1; private final int mAvrAddress; - @Nullable private final IHdmiControlCallback mCallback; + + SystemAudioStatusAction( + HdmiCecLocalDevice source, int avrAddress, List<IHdmiControlCallback> callbacks) { + super(source, callbacks); + mAvrAddress = avrAddress; + } SystemAudioStatusAction(HdmiCecLocalDevice source, int avrAddress, IHdmiControlCallback callback) { - super(source); + super(source, callback); mAvrAddress = avrAddress; - mCallback = callback; } @Override @@ -97,17 +101,6 @@ final class SystemAudioStatusAction extends HdmiCecFeatureAction { finishWithCallback(HdmiControlManager.RESULT_SUCCESS); } - private void finishWithCallback(int returnCode) { - if (mCallback != null) { - try { - mCallback.onComplete(returnCode); - } catch (RemoteException e) { - Slog.e(TAG, "Failed to invoke callback.", e); - } - } - finish(); - } - @Override void handleTimerEvent(int state) { if (mState != state) { diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index c0d577cd590d..8285e32ed8db 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.compat.IPlatformCompat; 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; @@ -1625,6 +1626,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } mHandler.removeCallbacks(mUserSwitchHandlerTask); } + // Hide soft input before user switch task since switch task may block main handler a while + // and delayed the MSG_HIDE_SOFT_INPUT. + hideCurrentInputLocked( + mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_SWITCH_USER); final UserSwitchHandlerTask task = new UserSwitchHandlerTask(this, userId, clientToBeReset); mUserSwitchHandlerTask = task; @@ -1750,20 +1755,16 @@ public class InputMethodManagerService extends IInputMethodManager.Stub final boolean initialUserSwitch = TextUtils.isEmpty(defaultImiId); mLastSystemLocales = mRes.getConfiguration().getLocales(); - // TODO: Is it really possible that switchUserLocked() happens before system ready? - if (mSystemReady) { - hideCurrentInputLocked( - mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_SWITCH_USER); - - resetCurrentMethodAndClient(UnbindReason.SWITCH_USER); - buildInputMethodListLocked(initialUserSwitch); - if (TextUtils.isEmpty(mSettings.getSelectedInputMethod())) { - // This is the first time of the user switch and - // set the current ime to the proper one. - resetDefaultImeLocked(mContext); - } - updateFromSettingsLocked(true); + // The mSystemReady flag is set during boot phase, + // and user switch would not happen at that time. + resetCurrentMethodAndClient(UnbindReason.SWITCH_USER); + buildInputMethodListLocked(initialUserSwitch); + if (TextUtils.isEmpty(mSettings.getSelectedInputMethod())) { + // This is the first time of the user switch and + // set the current ime to the proper one. + resetDefaultImeLocked(mContext); } + updateFromSettingsLocked(true); if (initialUserSwitch) { InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager, @@ -5883,87 +5884,102 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @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 60b7447e9f6c..7db234a29942 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 @@ public class GnssConfiguration { 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 @@ public class GnssConfiguration { 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 @@ public class GnssConfiguration { 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 @@ public class GnssConfiguration { } } - 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 1df29ab5791f..1e5a15e134e9 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 @@ public class GnssLocationProvider extends AbstractLocationProvider implements 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 05d0aefe7c89..dbd8dd9eff3b 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.Context; 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 @@ public class SystemEmergencyHelper extends EmergencyHelper { // 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 @@ public class SystemEmergencyHelper extends EmergencyHelper { || 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 7e00fd69a148..364aa2cb41ae 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 @@ class RebootEscrowManager { 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 @@ class RebootEscrowManager { 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 9c471b85eb76..ec80521be2e5 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 @@ public class ResumeOnRebootServiceProvider { } /** 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 @@ public class ResumeOnRebootServiceProvider { 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 7ab8b27075b7..a5763aee6336 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.security.Scrypt; 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 @@ public class SyntheticPasswordManager { 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 639dda6f8981..23195bbe5d7e 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 @@ public final class MediaMetricsManagerService extends SystemService { 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 @@ public final class MediaMetricsManagerService extends SystemService { } @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 067c5c0e7620..da62aca70cd3 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.NetworkIdentity; 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private final CarrierConfigManager mCarrierConfigManager; private final MultipathPolicyTracker mMultipathPolicyTracker; - private IConnectivityManager mConnManager; + private ConnectivityManager mConnManager; private PowerManagerInternal mPowerManagerInternal; private PowerWhitelistManager mPowerWhitelistManager; @@ -711,8 +710,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } /** - * 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } /** - * 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { .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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } - @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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } - 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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 e0f534602dde..7b376847fd44 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_UID_REMOVED; 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.isNetworkTypeMobile; import static android.net.NetworkIdentity.SUBTYPE_COMBINED; import static android.net.NetworkStack.checkNetworkStackPermission; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; @@ -71,6 +70,7 @@ import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static android.text.format.DateUtils.SECOND_IN_MILLIS; +import static com.android.net.module.util.NetworkCapabilitiesUtils.getDisplayTransport; import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats; import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet; @@ -1291,7 +1291,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final boolean combineSubtypeEnabled = mSettings.getCombineSubtypeEnabled(); final ArraySet<String> mobileIfaces = new ArraySet<>(); for (NetworkStateSnapshot snapshot : snapshots) { - final boolean isMobile = isNetworkTypeMobile(snapshot.legacyType); + final int displayTransport = + getDisplayTransport(snapshot.networkCapabilities.getTransportTypes()); + final boolean isMobile = (NetworkCapabilities.TRANSPORT_CELLULAR == displayTransport); final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, snapshot.network); final int subType = combineSubtypeEnabled ? SUBTYPE_COMBINED : getSubTypeForStateSnapshot(snapshot); diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java index afb47e831bdb..02f9ceb2d11d 100644 --- a/services/core/java/com/android/server/notification/NotificationDelegate.java +++ b/services/core/java/com/android/server/notification/NotificationDelegate.java @@ -55,9 +55,10 @@ public interface NotificationDelegate { void onNotificationBubbleChanged(String key, boolean isBubble, int flags); /** * Called when the state of {@link Notification.BubbleMetadata#FLAG_SUPPRESS_NOTIFICATION} - * changes. + * or {@link Notification.BubbleMetadata#FLAG_SUPPRESS_BUBBLE} changes. */ - void onBubbleNotificationSuppressionChanged(String key, boolean isSuppressed); + void onBubbleNotificationSuppressionChanged(String key, boolean isNotifSuppressed, + boolean isBubbleSuppressed); /** * Grant permission to read the specified URI to the package associated with the diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 73db7054cec5..6f39fea5dd95 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -1269,7 +1269,7 @@ public class NotificationManagerService extends SystemService { } @Override - public void onNotificationBubbleChanged(String key, boolean isBubble, int flags) { + public void onNotificationBubbleChanged(String key, boolean isBubble, int bubbleFlags) { synchronized (mNotificationLock) { NotificationRecord r = mNotificationsByKey.get(key); if (r != null) { @@ -1287,7 +1287,7 @@ public class NotificationManagerService extends SystemService { r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE; r.setFlagBubbleRemoved(false); if (r.getNotification().getBubbleMetadata() != null) { - r.getNotification().getBubbleMetadata().setFlags(flags); + r.getNotification().getBubbleMetadata().setFlags(bubbleFlags); } // Force isAppForeground true here, because for sysui's purposes we // want to adjust the flag behaviour. @@ -1299,7 +1299,8 @@ public class NotificationManagerService extends SystemService { } @Override - public void onBubbleNotificationSuppressionChanged(String key, boolean isSuppressed) { + public void onBubbleNotificationSuppressionChanged(String key, boolean isNotifSuppressed, + boolean isBubbleSuppressed) { synchronized (mNotificationLock) { NotificationRecord r = mNotificationsByKey.get(key); if (r != null) { @@ -1308,26 +1309,36 @@ public class NotificationManagerService extends SystemService { // No data, do nothing return; } - boolean currentlySuppressed = data.isNotificationSuppressed(); - if (currentlySuppressed == isSuppressed) { - // No changes, do nothing - return; - } + int flags = data.getFlags(); - if (isSuppressed) { - flags |= Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION; - } else { - flags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION; + boolean flagChanged = false; + if (data.isNotificationSuppressed() != isNotifSuppressed) { + flagChanged = true; + if (isNotifSuppressed) { + flags |= Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION; + } else { + flags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION; + } + } + if (data.isBubbleSuppressed() != isBubbleSuppressed) { + flagChanged = true; + if (isBubbleSuppressed) { + flags |= Notification.BubbleMetadata.FLAG_SUPPRESS_BUBBLE; + } else { + flags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_BUBBLE; + } + } + if (flagChanged) { + data.setFlags(flags); + r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE; + mHandler.post( + new EnqueueNotificationRunnable(r.getUser().getIdentifier(), r, + true /* isAppForeground */)); } - data.setFlags(flags); - r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE; - mHandler.post(new EnqueueNotificationRunnable(r.getUser().getIdentifier(), r, - true /* isAppForeground */)); } } } - @Override /** * Grant permission to read the specified URI to the package specified in the * NotificationRecord associated with the given key. The callingUid represents the UID of @@ -1337,6 +1348,7 @@ public class NotificationManagerService extends SystemService { * user associated with the NotificationRecord, and this grant will fail when trying * to grant URI permissions across users. */ + @Override public void grantInlineReplyUriPermission(String key, Uri uri, UserHandle user, String packageName, int callingUid) { synchronized (mNotificationLock) { @@ -6117,18 +6129,27 @@ public class NotificationManagerService extends SystemService { } /** - * Some bubble specific flags only work if the app is foreground, this will strip those flags - * if the app wasn't foreground. + * Strips any flags from BubbleMetadata that wouldn't apply (e.g. app not foreground). */ private void updateNotificationBubbleFlags(NotificationRecord r, boolean isAppForeground) { - // Remove any bubble specific flags that only work when foregrounded Notification notification = r.getNotification(); Notification.BubbleMetadata metadata = notification.getBubbleMetadata(); - if (!isAppForeground && metadata != null) { + if (metadata == null) { + // Nothing to update + return; + } + if (!isAppForeground) { + // Auto expand only works if foreground int flags = metadata.getFlags(); flags &= ~Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE; metadata.setFlags(flags); } + if (!metadata.isBubbleSuppressable()) { + // If it's not suppressable remove the suppress flag + int flags = metadata.getFlags(); + flags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_BUBBLE; + metadata.setFlags(flags); + } } private ShortcutHelper.ShortcutListener mShortcutListener = @@ -6504,9 +6525,11 @@ public class NotificationManagerService extends SystemService { } if (mReason == REASON_LISTENER_CANCEL - && (r.getNotification().flags & FLAG_BUBBLE) != 0) { + && r.getNotification().isBubbleNotification()) { + boolean isBubbleSuppressed = r.getNotification().getBubbleMetadata() != null + && r.getNotification().getBubbleMetadata().isBubbleSuppressed(); mNotificationDelegate.onBubbleNotificationSuppressionChanged( - r.getKey(), /* suppressed */ true); + r.getKey(), true /* suppressed */, isBubbleSuppressed); return; } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 7da53b50d927..bc991634fb07 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -351,6 +351,7 @@ import com.android.internal.os.SomeArgs; import com.android.internal.policy.AttributeCache; import com.android.internal.telephony.CarrierAppUtils; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.CollectionUtils; import com.android.internal.util.ConcurrentUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.FrameworkStatsLog; @@ -367,6 +368,7 @@ import com.android.server.ServiceThread; import com.android.server.SystemConfig; import com.android.server.SystemServerInitThreadPool; import com.android.server.Watchdog; +import com.android.server.apphibernation.AppHibernationManagerInternal; import com.android.server.compat.CompatChange; import com.android.server.compat.PlatformCompat; import com.android.server.net.NetworkPolicyManagerInternal; @@ -1385,7 +1387,6 @@ public class PackageManagerService extends IPackageManager.Stub public @Nullable String systemTextClassifierPackage; public @Nullable String overlayConfigSignaturePackage; public ViewCompiler viewCompiler; - public @Nullable String wellbeingPackage; public @Nullable String retailDemoPackage; public @Nullable String recentsPackage; public ComponentName resolveComponentName; @@ -1676,7 +1677,6 @@ public class PackageManagerService extends IPackageManager.Stub final @Nullable String mStorageManagerPackage; final @Nullable String mDefaultTextClassifierPackage; final @Nullable String mSystemTextClassifierPackageName; - final @Nullable String mWellbeingPackage; final @Nullable String mDocumenterPackage; final @Nullable String mConfiguratorPackage; final @Nullable String mAppPredictionServicePackage; @@ -2654,13 +2654,10 @@ public class PackageManagerService extends IPackageManager.Stub // If no apps are approved for the domain, resolve only to browsers if (approvedInfos.isEmpty()) { - // If the other profile has a result, include that and delegate to - // ResolveActivity + includeBrowser = true; if (xpDomainInfo != null && xpDomainInfo.highestApprovalLevel > DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE) { result.add(xpDomainInfo.resolveInfo); - } else { - includeBrowser = true; } } else { result.addAll(approvedInfos); @@ -2822,7 +2819,7 @@ public class PackageManagerService extends IPackageManager.Stub result.highestApprovalLevel = Math.max(mDomainVerificationManager .approvalLevelForDomain(ps, intent, resultTargetUser, flags, - riTargetUser.targetUserId), result.highestApprovalLevel); + parentUserId), result.highestApprovalLevel); } if (result != null && result.highestApprovalLevel <= DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE) { @@ -6216,7 +6213,6 @@ public class PackageManagerService extends IPackageManager.Stub mStorageManagerPackage = testParams.storageManagerPackage; mDefaultTextClassifierPackage = testParams.defaultTextClassifierPackage; mSystemTextClassifierPackageName = testParams.systemTextClassifierPackage; - mWellbeingPackage = testParams.wellbeingPackage; mRetailDemoPackage = testParams.retailDemoPackage; mRecentsPackage = testParams.recentsPackage; mDocumenterPackage = testParams.documenterPackage; @@ -6817,7 +6813,6 @@ public class PackageManagerService extends IPackageManager.Stub mDefaultTextClassifierPackage = getDefaultTextClassifierPackageName(); mSystemTextClassifierPackageName = getSystemTextClassifierPackageName(); - mWellbeingPackage = getWellbeingPackageName(); mDocumenterPackage = getDocumenterPackageName(); mConfiguratorPackage = getDeviceConfiguratorPackageName(); mAppPredictionServicePackage = getAppPredictionServicePackageName(); @@ -9991,6 +9986,7 @@ public class PackageManagerService extends IPackageManager.Stub false /*includeInstantApps*/, isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, parent.id, resolvedType, 0)); + flags |= PackageManager.MATCH_DEFAULT_ONLY; CrossProfileDomainInfo xpDomainInfo = getCrossProfileDomainPreferredLpr( intent, resolvedType, flags, sourceUserId, parent.id); return xpDomainInfo != null; @@ -20368,6 +20364,11 @@ public class PackageManagerService extends IPackageManager.Stub 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) { @@ -22840,7 +22841,9 @@ public class PackageManagerService extends IPackageManager.Stub @Override public String getWellbeingPackageName() { - return ensureSystemPackageName(mContext.getString(R.string.config_defaultWellbeingPackage)); + return CollectionUtils.firstOrNull( + mContext.getSystemService(RoleManager.class).getRoleHolders( + RoleManager.ROLE_SYSTEM_WELLBEING)); } @Override @@ -23400,15 +23403,25 @@ public class PackageManagerService extends IPackageManager.Stub final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED); enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */, true /* checkShell */, "stop package"); + boolean shouldUnhibernate = false; // writer synchronized (mLock) { final PackageSetting ps = mSettings.getPackageLPr(packageName); + if (ps.getStopped(userId) && !stopped) { + shouldUnhibernate = true; + } if (!shouldFilterApplicationLocked(ps, callingUid, userId) && mSettings.setPackageStoppedStateLPw(this, packageName, stopped, allowedByPermission, callingUid, userId)) { scheduleWritePackageRestrictionsLocked(userId); } } + if (shouldUnhibernate) { + AppHibernationManagerInternal ah = + mInjector.getLocalService(AppHibernationManagerInternal.class); + ah.setHibernatingForUser(packageName, userId, false); + ah.setHibernatingGlobally(packageName, false); + } } @Override @@ -26358,8 +26371,6 @@ public class PackageManagerService extends IPackageManager.Stub mDefaultTextClassifierPackage, mSystemTextClassifierPackageName); case PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER: return filterOnlySystemPackages(mRequiredPermissionControllerPackage); - case PackageManagerInternal.PACKAGE_WELLBEING: - return filterOnlySystemPackages(mWellbeingPackage); case PackageManagerInternal.PACKAGE_DOCUMENTER: return filterOnlySystemPackages(mDocumenterPackage); case PackageManagerInternal.PACKAGE_CONFIGURATOR: diff --git a/services/core/java/com/android/server/pm/SettingsXml.java b/services/core/java/com/android/server/pm/SettingsXml.java index ec643f598041..c53fef72db9c 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 @@ public class SettingsXml { @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 a377f1c72375..d1cf55de7254 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 android.view.IWindowManager; 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.Arrays; 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 @@ public class ShortcutService extends IShortcutService.Stub { // === 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 @@ public class ShortcutService extends IShortcutService.Stub { // Throttling. if (!ps.tryApiCall(unlimited)) { - return false; + callback.complete(false); } // Initialize the implicit ranks for ShortcutPackage.adjustRanks(). @@ -1949,12 +1951,12 @@ public class ShortcutService extends IShortcutService.Stub { 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 @@ public class ShortcutService extends IShortcutService.Stub { // Throttling. if (!ps.tryApiCall(unlimited)) { - return false; + callback.complete(false); + return; } // Initialize the implicit ranks for ShortcutPackage.adjustRanks(). @@ -2046,12 +2049,12 @@ public class ShortcutService extends IShortcutService.Stub { 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 @@ public class ShortcutService extends IShortcutService.Stub { // 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 @@ public class ShortcutService extends IShortcutService.Stub { verifyStates(); - return true; + callback.complete(true); } @Override @@ -2174,15 +2178,17 @@ public class ShortcutService extends IShortcutService.Stub { } @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 @@ public class ShortcutService extends IShortcutService.Stub { } verifyStates(); - return ret; + callback.complete(ret); } /** @@ -2455,8 +2461,9 @@ public class ShortcutService extends IShortcutService.Stub { } @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 @@ public class ShortcutService extends IShortcutService.Stub { | (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 @@ public class ShortcutService extends IShortcutService.Stub { 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 @@ public class ShortcutService extends IShortcutService.Stub { @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 871576e7c795..8283ac668d5e 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 class UserManagerService extends IUserManager.Stub { 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/permission/Permission.java b/services/core/java/com/android/server/pm/permission/Permission.java index ac50f29fbf32..b421cfc95295 100644 --- a/services/core/java/com/android/server/pm/permission/Permission.java +++ b/services/core/java/com/android/server/pm/permission/Permission.java @@ -304,10 +304,6 @@ public final class Permission { & PermissionInfo.PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER) != 0; } - public boolean isWellbeing() { - return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_WELLBEING) != 0; - } - public boolean isDocumenter() { return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_DOCUMENTER) != 0; } diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 2dfb6ff3e9a8..616058fc2562 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -3471,13 +3471,6 @@ public class PermissionManagerService extends IPermissionManager.Stub { // Special permissions for the device configurator. allowed = true; } - if (!allowed && bp.isWellbeing() - && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames( - PackageManagerInternal.PACKAGE_WELLBEING, UserHandle.USER_SYSTEM), - pkg.getPackageName())) { - // Special permission granted only to the OEM specified wellbeing app - allowed = true; - } if (!allowed && bp.isDocumenter() && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames( PackageManagerInternal.PACKAGE_DOCUMENTER, UserHandle.USER_SYSTEM), 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 c787356f342c..4bad1020e945 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 com.android.server.pm.SettingsXml; 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/policy/DeviceStateProviderImpl.java b/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java index 4e1065a9d3af..cd7f6854a37d 100644 --- a/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java +++ b/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java @@ -161,7 +161,7 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider, private int mLastReportedState = INVALID_DEVICE_STATE; @GuardedBy("mLock") - private boolean mIsLidOpen; + private Boolean mIsLidOpen; @GuardedBy("mLock") private final Map<Sensor, SensorEvent> mLatestSensorEvent = new ArrayMap<>(); @@ -299,7 +299,17 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider, int newState = mOrderedStates[0].getIdentifier(); for (int i = 0; i < mOrderedStates.length; i++) { int state = mOrderedStates[i].getIdentifier(); - if (mStateConditions.get(state).getAsBoolean()) { + boolean conditionSatisfied; + try { + conditionSatisfied = mStateConditions.get(state).getAsBoolean(); + } catch (IllegalStateException e) { + // Failed to compute the current state based on current available data. Return + // with the expectation that notifyDeviceStateChangedIfNeeded() will be called + // when a callback with the missing data is triggered. + return; + } + + if (conditionSatisfied) { newState = state; break; } @@ -351,6 +361,10 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider, @Override public boolean getAsBoolean() { synchronized (mLock) { + if (mIsLidOpen == null) { + throw new IllegalStateException("Have not received lid switch value."); + } + return mIsLidOpen == mExpectedOpen; } } @@ -377,13 +391,11 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider, synchronized (mLock) { SensorEvent latestEvent = mLatestSensorEvent.get(mSensor); if (latestEvent == null) { - // Default to returning false if we have not yet received a sensor event for the - // sensor. - return false; + throw new IllegalStateException("Have not received sensor event."); } if (latestEvent.values.length != mExpectedValues.size()) { - throw new IllegalStateException("Number of supplied numeric range(s) does not " + throw new RuntimeException("Number of supplied numeric range(s) does not " + "match the number of values in the latest sensor event for sensor: " + mSensor); } diff --git a/services/core/java/com/android/server/policy/KeyCombinationManager.java b/services/core/java/com/android/server/policy/KeyCombinationManager.java index 84ac12497e71..7f55723cda0b 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 @@ public class KeyCombinationManager { } /** - * 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 @@ public class KeyCombinationManager { // 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 @@ public class KeyCombinationManager { mDownTimes.put(keyCode, eventTime); } else { // ignore old key, maybe a repeat key. - return; + return false; } if (mDownTimes.size() == 1) { @@ -141,7 +143,7 @@ public class KeyCombinationManager { } 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 @@ public class KeyCombinationManager { mActiveRules.clear(); if (mTriggeredRule != null) { mActiveRules.add(mTriggeredRule); + return true; } } } else { @@ -168,6 +171,7 @@ public class KeyCombinationManager { } } } + 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 bce218f8a74b..047e3b362b7a 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_OKAY; 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean mHasSoftInput = false; boolean mHapticTextHandleEnabled; boolean mUseTvRouting; - int mVeryLongPressTimeout; boolean mAllowStartActivityForLongPressOnPowerDuringSetup; MetricsLogger mLogger; boolean mWakeOnDpadKeyPress; @@ -567,14 +567,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { } }; - private Runnable mPossibleVeryLongPressReboot = new Runnable() { - @Override - public void run() { - mActivityManagerInternal.prepareForPossibleShutdown(); - } - }; - private void handleRingerChordGesture() { if (mRingerToggleChord == VOLUME_HUSH_OFF) { return; @@ -810,28 +785,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } } + } 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { private void powerLongPress(long eventTime) { final int behavior = getResolvedLongPressOnPowerBehavior(); + switch (behavior) { case LONG_PRESS_POWER_NOTHING: break; @@ -1183,7 +1056,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { } }); initKeyCombinationRules(); + initSingleKeyGestureRules(); } private void initKeyCombinationRules() { @@ -1921,7 +1793,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { new TwoKeysCombinationRule(KEYCODE_VOLUME_DOWN, KEYCODE_POWER) { @Override void execute() { - cancelPendingPowerKeyAction(); + mPowerKeyHandled = true; interceptScreenshotChord(); } @Override @@ -1956,7 +1828,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override void execute() { - cancelPendingPowerKeyAction(); + mPowerKeyHandled = true; interceptRingerToggleChord(); } @Override @@ -1970,7 +1842,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { new TwoKeysCombinationRule(KEYCODE_BACK, KEYCODE_DPAD_DOWN) { @Override void execute() { - cancelPendingBackKeyAction(); + mBackKeyHandled = true; interceptAccessibilityGestureTv(); } @@ -1984,7 +1856,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { new TwoKeysCombinationRule(KEYCODE_DPAD_CENTER, KEYCODE_BACK) { @Override void execute() { - cancelPendingBackKeyAction(); + mBackKeyHandled = true; interceptBugreportGestureTv(); } @@ -1997,6 +1869,84 @@ public class PhoneWindowManager implements WindowManagerPolicy { } /** + * 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - 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 000000000000..cae209353361 --- /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 bc117094dd68..29adde37ab3b 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 @@ public final class PowerManagerService extends SystemService } @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/powerstats/PowerStatsHALWrapper.java b/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java index f382d10e0846..8ea29198b8d5 100644 --- a/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java +++ b/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java @@ -166,7 +166,7 @@ public final class PowerStatsHALWrapper { try { powerEntityHAL = sVintfPowerStats.get().getPowerEntityInfo(); } catch (RemoteException e) { - if (DEBUG) Slog.d(TAG, "Failed to get power entity info from PowerStats HAL"); + Slog.w(TAG, "Failed to get power entity info: ", e); } } @@ -183,7 +183,7 @@ public final class PowerStatsHALWrapper { stateResidencyResultHAL = sVintfPowerStats.get().getStateResidency(powerEntityIds); } catch (RemoteException e) { - if (DEBUG) Slog.d(TAG, "Failed to get state residency from PowerStats HAL"); + Slog.w(TAG, "Failed to get state residency: ", e); } } @@ -198,9 +198,7 @@ public final class PowerStatsHALWrapper { try { energyConsumerHAL = sVintfPowerStats.get().getEnergyConsumerInfo(); } catch (RemoteException e) { - if (DEBUG) { - Slog.d(TAG, "Failed to get energy consumer info from PowerStats HAL"); - } + Slog.w(TAG, "Failed to get energy consumer info: ", e); } } @@ -217,9 +215,7 @@ public final class PowerStatsHALWrapper { energyConsumedHAL = sVintfPowerStats.get().getEnergyConsumed(energyConsumerIds); } catch (RemoteException e) { - if (DEBUG) { - Slog.d(TAG, "Failed to get energy consumer results from PowerStats HAL"); - } + Slog.w(TAG, "Failed to get energy consumer results: ", e); } } @@ -234,7 +230,7 @@ public final class PowerStatsHALWrapper { try { energyMeterInfoHAL = sVintfPowerStats.get().getEnergyMeterInfo(); } catch (RemoteException e) { - if (DEBUG) Slog.d(TAG, "Failed to get energy meter info from PowerStats HAL"); + Slog.w(TAG, "Failed to get energy meter info: ", e); } } @@ -250,7 +246,7 @@ public final class PowerStatsHALWrapper { energyMeasurementHAL = sVintfPowerStats.get().readEnergyMeter(channelIds); } catch (RemoteException e) { - if (DEBUG) Slog.d(TAG, "Failed to get energy measurements from PowerStats HAL"); + Slog.w(TAG, "Failed to get energy measurements: ", e); } } @@ -367,6 +363,7 @@ public final class PowerStatsHALWrapper { @Override public synchronized void binderDied() { + Slog.w(TAG, "PowerStats HAL died"); mInstance = null; } } diff --git a/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java b/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java index 746a09882f93..688f0bf5e55f 100644 --- a/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java +++ b/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java @@ -111,6 +111,8 @@ public class ProtoStreamUtils { static class StateResidencyResultUtils { public static void adjustTimeSinceBootToEpoch(StateResidencyResult[] stateResidencyResult, long startWallTime) { + if (stateResidencyResult == null) return; + for (int i = 0; i < stateResidencyResult.length; i++) { final int stateLength = stateResidencyResult[i].stateResidencyData.length; for (int j = 0; j < stateLength; j++) { @@ -320,6 +322,8 @@ public class ProtoStreamUtils { static class EnergyMeasurementUtils { public static void adjustTimeSinceBootToEpoch(EnergyMeasurement[] energyMeasurement, long startWallTime) { + if (energyMeasurement == null) return; + for (int i = 0; i < energyMeasurement.length; i++) { energyMeasurement[i].timestampMs += startWallTime; } @@ -539,6 +543,8 @@ public class ProtoStreamUtils { static class EnergyConsumerResultUtils { public static void adjustTimeSinceBootToEpoch(EnergyConsumerResult[] energyConsumerResult, long startWallTime) { + if (energyConsumerResult == null) return; + for (int i = 0; i < energyConsumerResult.length; i++) { energyConsumerResult[i].timestampMs += startWallTime; } diff --git a/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java b/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java index b995b19c5841..cfb4c27820fa 100644 --- a/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java +++ b/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java @@ -87,6 +87,7 @@ class RemoteRotationResolverService extends ServiceConnector.Impl<IRotationResol synchronized (request.mLock) { if (!request.mIsFulfilled) { request.mCallbackInternal.onFailure(ROTATION_RESULT_FAILURE_TIMED_OUT); + Slog.d(TAG, "Trying to cancel the remote request. Reason: Timed out."); request.cancelInternal(); } } @@ -139,7 +140,6 @@ class RemoteRotationResolverService extends ServiceConnector.Impl<IRotationResol void cancelInternal() { synchronized (mLock) { if (mIsFulfilled) { - Slog.v(TAG, "Trying to cancel the request that has been already fulfilled."); return; } mIsFulfilled = true; @@ -187,6 +187,8 @@ class RemoteRotationResolverService extends ServiceConnector.Impl<IRotationResol SystemClock.elapsedRealtime() - request.mRequestStartTimeMillis; logRotationStats(request.mProposedRotation, request.mCurrentRotation, rotation, timeToCalculate); + Slog.d(TAG, "onSuccess:" + rotation); + Slog.d(TAG, "timeToCalculate:" + timeToCalculate); } } @@ -204,6 +206,8 @@ class RemoteRotationResolverService extends ServiceConnector.Impl<IRotationResol SystemClock.elapsedRealtime() - request.mRequestStartTimeMillis; logRotationStats(request.mProposedRotation, request.mCurrentRotation, RESOLUTION_FAILURE, timeToCalculate); + Slog.d(TAG, "onFailure:" + error); + Slog.d(TAG, "timeToCalculate:" + timeToCalculate); } } diff --git a/services/core/java/com/android/server/rotationresolver/RotationResolverManagerPerUserService.java b/services/core/java/com/android/server/rotationresolver/RotationResolverManagerPerUserService.java index 0cd0458c6b2b..13f8d61f74f5 100644 --- a/services/core/java/com/android/server/rotationresolver/RotationResolverManagerPerUserService.java +++ b/services/core/java/com/android/server/rotationresolver/RotationResolverManagerPerUserService.java @@ -82,6 +82,7 @@ final class RotationResolverManagerPerUserService extends if (mCurrentRequest == null) { return; } + Slog.d(TAG, "Trying to cancel the remote request. Reason: Service destroyed."); cancelLocked(); if (mRemoteService != null) { @@ -118,8 +119,10 @@ final class RotationResolverManagerPerUserService extends cancellationSignalInternal.setOnCancelListener(() -> { synchronized (mLock) { - Slog.i(TAG, "Trying to cancel current request."); - mCurrentRequest.cancelInternal(); + if (mCurrentRequest != null && !mCurrentRequest.mIsFulfilled) { + Slog.d(TAG, "Trying to cancel the remote request. Reason: Client cancelled."); + mCurrentRequest.cancelInternal(); + } } }); diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 8ffbb0a87dc0..546e420c1d59 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -1453,11 +1453,13 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D } @Override - public void onBubbleNotificationSuppressionChanged(String key, boolean isNotifSuppressed) { + public void onBubbleNotificationSuppressionChanged(String key, boolean isNotifSuppressed, + boolean isBubbleSuppressed) { enforceStatusBarService(); final long identity = Binder.clearCallingIdentity(); try { - mNotificationDelegate.onBubbleNotificationSuppressionChanged(key, isNotifSuppressed); + mNotificationDelegate.onBubbleNotificationSuppressionChanged(key, isNotifSuppressed, + isBubbleSuppressed); } finally { Binder.restoreCallingIdentity(identity); } diff --git a/services/core/java/com/android/server/storage/StorageUserConnection.java b/services/core/java/com/android/server/storage/StorageUserConnection.java index 9409eb5d1ad9..a0e2286f72e2 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.StorageManagerInternal; 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; @@ -76,8 +76,8 @@ public final class StorageUserConnection { 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) { @@ -249,7 +249,8 @@ public final class StorageUserConnection { 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); } } @@ -262,7 +263,12 @@ public final class StorageUserConnection { 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); + } } } diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java index c4c620c41918..16e8632c6e40 100644 --- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java +++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java @@ -720,6 +720,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { String logMsg = "Set system clock using time=" + newTime + " cause=" + cause + " elapsedRealtimeMillis=" + elapsedRealtimeMillis + + " (old) actualSystemClockMillis=" + actualSystemClockMillis + " newSystemClockMillis=" + newSystemClockMillis; if (DBG) { Slog.d(LOG_TAG, logMsg); diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerInternal.java b/services/core/java/com/android/server/uri/UriGrantsManagerInternal.java index 5772dea287fc..e54b40eb334c 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 @@ public interface UriGrantsManagerInternal { 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 @@ public interface UriGrantsManagerInternal { */ 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 dcc15999d882..44545ed4898a 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.ROOT_UID; 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 android.util.Xml; 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 com.google.android.collect.Maps; 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.FileNotFoundException; 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 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub { } } + /** + * 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 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub { } /** - * @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/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java index 9d39c67d27fb..c55913e2e547 100644 --- a/services/core/java/com/android/server/vcn/Vcn.java +++ b/services/core/java/com/android/server/vcn/Vcn.java @@ -128,7 +128,6 @@ public class Vcn extends Handler { * from VcnManagementService, and therefore cannot rely on guarantees of running on the VCN * Looper. */ - // TODO(b/179429339): update when exiting safemode (when a new VcnConfig is provided) private final AtomicBoolean mIsActive = new AtomicBoolean(true); public Vcn( @@ -203,7 +202,8 @@ public class Vcn extends Handler { @Override public void handleMessage(@NonNull Message msg) { - if (!isActive()) { + // Ignore if this Vcn is not active and we're not receiving new configs + if (!isActive() && msg.what != MSG_EVENT_CONFIG_UPDATED) { return; } @@ -237,7 +237,13 @@ public class Vcn extends Handler { mConfig = config; - // TODO: Reevaluate active VcnGatewayConnection(s) + // TODO(b/181815405): Reevaluate active VcnGatewayConnection(s) + + if (!mIsActive.getAndSet(true)) { + // If this VCN was not previously active, it is exiting Safe Mode. Re-register the + // request listener to get NetworkRequests again (and all cached requests). + mVcnContext.getVcnNetworkProvider().registerListener(mRequestListener); + } } private void handleTeardown() { @@ -253,6 +259,8 @@ public class Vcn extends Handler { private void handleEnterSafeMode() { handleTeardown(); + mVcnGatewayConnections.clear(); + mVcnCallback.onEnteredSafeMode(); } diff --git a/services/core/java/com/android/server/vibrator/Vibration.java b/services/core/java/com/android/server/vibrator/Vibration.java index 607da3ce6fe2..e84ee672bf0f 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 @@ final class Vibration { 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 95f6059c482e..eaba083c551c 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 @@ final class VibratorController { 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 @@ final class VibratorController { 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 @@ final class VibratorController { } /** 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 90a763c260f6..c9751bb7abe4 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 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { 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 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { 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 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { 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 ee980317c04e..5446a39fad86 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -211,7 +211,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 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; @@ -253,6 +253,7 @@ import android.app.servertransaction.TransferSplashScreenViewStateItem; import android.app.usage.UsageEvents.Event; import android.content.ComponentName; import android.content.Intent; +import android.content.LocusId; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.res.CompatibilityInfo; @@ -551,6 +552,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A TaskDescription taskDescription; // the recents information for this activity + // The locusId associated with this activity, if set. + private LocusId mLocusId; + // These configurations are collected from application's resources based on size-sensitive // qualifiers. For example, layout-w800dp will be added to mHorizontalSizeConfigurations as 800 // and drawable-sw400dp will be added to both as 400. @@ -581,9 +585,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A 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; @@ -911,7 +912,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A 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())); } @@ -999,7 +1000,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A 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) { @@ -1736,7 +1737,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A keysPaused = false; inHistory = false; nowVisible = false; - mClientVisible = true; + super.setClientVisible(true); idle = false; hasBeenLaunched = false; mTaskSupervisor = supervisor; @@ -3776,7 +3777,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A setVisibleRequested(true); mVisibleSetFromTransferredStartingWindow = true; } - setClientVisible(fromActivity.mClientVisible); + setClientVisible(fromActivity.isClientVisible()); if (fromActivity.isAnimating()) { transferAnimation(fromActivity); @@ -5877,18 +5878,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A 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(); } @@ -6120,6 +6118,17 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A getTask().updateTaskDescription(); } + void setLocusId(LocusId locusId) { + if (Objects.equals(locusId, mLocusId)) return; + mLocusId = locusId; + final Task task = getTask(); + if (task != null) getTask().dispatchTaskInfoChangedIfNeeded(false /* force */); + } + + LocusId getLocusId() { + return mLocusId; + } + void setVoiceSessionLocked(IVoiceInteractionSession session) { voiceSession = session; pendingVoiceInteractionStart = false; @@ -7000,6 +7009,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A 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; @@ -7010,16 +7026,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A 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) { @@ -8186,7 +8192,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A 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/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 6ce9048d79e2..da49fa72dc50 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -48,6 +48,7 @@ import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME; import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS; import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE; +import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE_PER_TASK; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP; import static android.content.pm.PackageManager.PERMISSION_GRANTED; @@ -2093,7 +2094,8 @@ class ActivityStarter { mAddingToTask = true; } else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0 || isDocumentLaunchesIntoExisting(mLaunchFlags) - || isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) { + || isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK, + LAUNCH_SINGLE_INSTANCE_PER_TASK)) { // In this situation we want to remove all activities from the task up to the one // being started. In most cases this means we are resetting the task to its initial // state. @@ -2261,6 +2263,12 @@ class ActivityStarter { && !isLaunchModeOneOf(LAUNCH_SINGLE_TASK, LAUNCH_SINGLE_INSTANCE) && (mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0; + if (mLaunchMode == LAUNCH_SINGLE_INSTANCE_PER_TASK) { + // Adding NEW_TASK flag for singleInstancePerTask launch mode activity, so that the + // activity won't be launched in source record's task. + mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK; + } + sendNewTaskResultRequestIfNeeded(); if ((mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) { @@ -2529,6 +2537,14 @@ class ActivityStarter { } } + if (intentActivity != null && mLaunchMode == LAUNCH_SINGLE_INSTANCE_PER_TASK + && !intentActivity.getTask().getRootActivity().mActivityComponent.equals( + mStartActivity.mActivityComponent)) { + // The task could be selected due to same task affinity. Do not reuse the task while + // starting the singleInstancePerTask activity if it is not the task root activity. + intentActivity = null; + } + if (intentActivity != null && (mStartActivity.isActivityTypeHome() || intentActivity.isActivityTypeHome()) && intentActivity.getDisplayArea() != mPreferredTaskDisplayArea) { @@ -2715,6 +2731,10 @@ class ActivityStarter { return mode1 == mLaunchMode || mode2 == mLaunchMode; } + private boolean isLaunchModeOneOf(int mode1, int mode2, int mode3) { + return mode1 == mLaunchMode || mode2 == mLaunchMode || mode3 == mLaunchMode; + } + static boolean isDocumentLaunchesIntoExisting(int flags) { return (flags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && (flags & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0; diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 0c77d9f1f724..3d2be04dac39 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -52,7 +52,7 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.FactoryTest.FACTORY_TEST_HIGH_LEVEL; import static android.os.FactoryTest.FACTORY_TEST_LOW_LEVEL; import static android.os.FactoryTest.FACTORY_TEST_OFF; -import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; +import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; import static android.os.Process.FIRST_APPLICATION_UID; import static android.os.Process.SYSTEM_UID; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; @@ -160,6 +160,7 @@ import android.content.Context; import android.content.DialogInterface; import android.content.IIntentSender; import android.content.Intent; +import android.content.LocusId; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.ConfigurationInfo; @@ -1942,6 +1943,21 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } + /** + * Sets the locusId for a particular activity. + * + * @param locusId the locusId to set. + * @param appToken the ActivityRecord's appToken. + */ + public void setLocusId(LocusId locusId, IBinder appToken) { + synchronized (mGlobalLock) { + final ActivityRecord r = ActivityRecord.isInRootTaskLocked(appToken); + if (r != null) { + r.setLocusId(locusId); + } + } + } + NeededUriGrants collectGrants(Intent intent, ActivityRecord target) { if (target != null) { return mUgmInternal.checkGrantUriPermissionFromIntent(intent, diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index bb0f1f0b6f5f..bfbc10aee7a7 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -109,6 +109,7 @@ import android.content.pm.UserInfo; import android.content.res.Configuration; import android.graphics.Rect; import android.os.Binder; +import android.os.Build; import android.os.Bundle; import android.os.Debug; import android.os.Handler; @@ -165,13 +166,13 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { static final String TAG_TASKS = TAG + POSTFIX_TASKS; /** How long we wait until giving up on the last activity telling us it is idle. */ - private static final int IDLE_TIMEOUT = 10 * 1000; + private static final int IDLE_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER; /** How long we can hold the sleep wake lock before giving up. */ - private static final int SLEEP_TIMEOUT = 5 * 1000; + private static final int SLEEP_TIMEOUT = 5 * 1000 * Build.HW_TIMEOUT_MULTIPLIER; // How long we can hold the launch wake lock before giving up. - private static final int LAUNCH_TIMEOUT = 10 * 1000; + private static final int LAUNCH_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER; /** How long we wait until giving up on the activity telling us it released the top state. */ private static final int TOP_RESUMED_STATE_LOSS_TIMEOUT = 500; @@ -1504,7 +1505,13 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { // 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/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java index a725dd34fbf6..28a509bc9276 100644 --- a/services/core/java/com/android/server/wm/CompatModePackages.java +++ b/services/core/java/com/android/server/wm/CompatModePackages.java @@ -27,16 +27,20 @@ import android.app.AppGlobals; import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.compat.annotation.Disabled; +import android.compat.annotation.EnabledSince; +import android.compat.annotation.Overridable; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; +import android.os.Build; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.os.UserHandle; import android.util.AtomicFile; +import android.util.DisplayMetrics; import android.util.Slog; import android.util.SparseArray; import android.util.TypedXmlPullParser; @@ -119,6 +123,17 @@ public final class CompatModePackages { @Disabled private static final long DOWNSCALE_50 = 176926741L; + /** + * On Android TV applications that target pre-S are not expecting to receive a Window larger + * than 1080p, so if needed we are downscaling their Windows to 1080p. + * However, applications that target S and greater release version are expected to be able to + * handle any Window size, so we should not downscale their Windows. + */ + @ChangeId + @Overridable + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S) + private static final long DO_NOT_DOWNSCALE_TO_1080P_ON_TV = 157629738L; // This is a Bug ID. + private final HashMap<String, Integer> mPackages = new HashMap<String, Integer>(); private static final int MSG_WRITE = 300; @@ -138,7 +153,7 @@ public final class CompatModePackages { break; } } - }; + } public CompatModePackages(ActivityTaskManagerService service, File systemDir, Handler handler) { mService = service; @@ -247,55 +262,53 @@ public final class CompatModePackages { mHandler.sendMessageDelayed(msg, 10000); } + public CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) { + final boolean forceCompat = getPackageCompatModeEnabledLocked(ai); + final float compatScale = getCompatScale(ai.packageName, ai.uid); + final Configuration config = mService.getGlobalConfiguration(); + return new CompatibilityInfo(ai, config.screenLayout, config.smallestScreenWidthDp, + forceCompat, compatScale); + } + float getCompatScale(String packageName, int uid) { - if (!CompatChanges.isChangeEnabled( - DOWNSCALED, packageName, UserHandle.getUserHandleForUid(uid))) { - return 1f; - } - if (CompatChanges.isChangeEnabled( - DOWNSCALE_87_5, packageName, UserHandle.getUserHandleForUid(uid))) { - // 8/7 == (1 / 0.875) ~= 1.14285714286 - return 8f / 7f; - } - if (CompatChanges.isChangeEnabled( - DOWNSCALE_75, packageName, UserHandle.getUserHandleForUid(uid))) { - // 4/3 == (1 / 0.75) ~= 1.333333333 - return 4f / 3f; - } - if (CompatChanges.isChangeEnabled( - DOWNSCALE_62_5, packageName, UserHandle.getUserHandleForUid(uid))) { - // (1 / 0.625) == 1.6 - return 1.6f; + final UserHandle userHandle = UserHandle.getUserHandleForUid(uid); + if (CompatChanges.isChangeEnabled(DOWNSCALED, packageName, userHandle)) { + if (CompatChanges.isChangeEnabled(DOWNSCALE_87_5, packageName, userHandle)) { + return 8f / 7f; // 1.14285714286 + } + if (CompatChanges.isChangeEnabled(DOWNSCALE_75, packageName, userHandle)) { + return 4f / 3f; // 1.333333333 + } + if (CompatChanges.isChangeEnabled(DOWNSCALE_62_5, packageName, userHandle)) { + return /* 1 / 0.625 */ 1.6f; + } + if (CompatChanges.isChangeEnabled(DOWNSCALE_50, packageName, userHandle)) { + return /* 1 / 0.5 */ 2f; + } } - if (CompatChanges.isChangeEnabled( - DOWNSCALE_50, packageName, UserHandle.getUserHandleForUid(uid))) { - return 2f; + + if (mService.mHasLeanbackFeature) { + final Configuration config = mService.getGlobalConfiguration(); + final float density = config.densityDpi / (float) DisplayMetrics.DENSITY_DEFAULT; + final int smallestScreenWidthPx = (int) (config.smallestScreenWidthDp * density + .5f); + if (smallestScreenWidthPx > 1080 && !CompatChanges.isChangeEnabled( + DO_NOT_DOWNSCALE_TO_1080P_ON_TV, packageName, userHandle)) { + return smallestScreenWidthPx / 1080f; + } } - return 1f; - } - public CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) { - final Configuration globalConfig = mService.getGlobalConfiguration(); - final float requestedScale = getCompatScale(ai.packageName, ai.uid); - CompatibilityInfo ci = new CompatibilityInfo(ai, globalConfig.screenLayout, - globalConfig.smallestScreenWidthDp, - (getPackageFlags(ai.packageName) & COMPAT_FLAG_ENABLED) != 0, requestedScale); - //Slog.i(TAG, "*********** COMPAT FOR PKG " + ai.packageName + ": " + ci); - return ci; + return 1f; } public int computeCompatModeLocked(ApplicationInfo ai) { - final boolean enabled = (getPackageFlags(ai.packageName)&COMPAT_FLAG_ENABLED) != 0; - final Configuration globalConfig = mService.getGlobalConfiguration(); - final CompatibilityInfo info = new CompatibilityInfo(ai, globalConfig.screenLayout, - globalConfig.smallestScreenWidthDp, enabled); + final CompatibilityInfo info = compatibilityInfoForPackageLocked(ai); if (info.alwaysSupportsScreen()) { return ActivityManager.COMPAT_MODE_NEVER; } if (info.neverSupportsScreen()) { return ActivityManager.COMPAT_MODE_ALWAYS; } - return enabled ? ActivityManager.COMPAT_MODE_ENABLED + return getPackageCompatModeEnabledLocked(ai) ? ActivityManager.COMPAT_MODE_ENABLED : ActivityManager.COMPAT_MODE_DISABLED; } @@ -307,6 +320,10 @@ public final class CompatModePackages { setPackageFlagLocked(packageName, COMPAT_FLAG_DONT_ASK, ask); } + private boolean getPackageCompatModeEnabledLocked(ApplicationInfo ai) { + return (getPackageFlags(ai.packageName) & COMPAT_FLAG_ENABLED) != 0; + } + private void setPackageFlagLocked(String packageName, int flag, boolean set) { final int curFlags = getPackageFlags(packageName); final int newFlags = set ? (curFlags & ~flag) : (curFlags | flag); @@ -443,9 +460,6 @@ public final class CompatModePackages { out.startTag(null, "compat-packages"); final IPackageManager pm = AppGlobals.getPackageManager(); - final Configuration globalConfig = mService.getGlobalConfiguration(); - final int screenLayout = globalConfig.screenLayout; - final int smallestScreenWidthDp = globalConfig.smallestScreenWidthDp; final Iterator<Map.Entry<String, Integer>> it = pkgs.entrySet().iterator(); while (it.hasNext()) { Map.Entry<String, Integer> entry = it.next(); @@ -462,8 +476,7 @@ public final class CompatModePackages { if (ai == null) { continue; } - CompatibilityInfo info = new CompatibilityInfo(ai, screenLayout, - smallestScreenWidthDp, false); + final CompatibilityInfo info = compatibilityInfoForPackageLocked(ai); if (info.alwaysSupportsScreen()) { continue; } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 84bc8538f163..1d45c6e1a371 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -3856,6 +3856,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp if (newParent != null && newParent != mInputMethodSurfaceParent) { mInputMethodSurfaceParent = newParent; getPendingTransaction().reparent(mImeWindowsContainer.mSurfaceControl, newParent); + // When surface parent is removed, the relative layer will also be removed. We need to + // do a force update to make sure there is a layer set for the new parent. + assignRelativeLayerForIme(getPendingTransaction(), true /* forceUpdate */); scheduleAnimation(); } } @@ -4537,11 +4540,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } @Override - void assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) { + void assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer, + boolean forceUpdate) { if (!mNeedsLayer) { return; } - super.assignRelativeLayer(t, relativeTo, layer); + super.assignRelativeLayer(t, relativeTo, layer, forceUpdate); mNeedsLayer = false; } } @@ -4631,6 +4635,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp @Override void assignChildLayers(SurfaceControl.Transaction t) { + assignRelativeLayerForIme(t, false /* forceUpdate */); + super.assignChildLayers(t); + } + + private void assignRelativeLayerForIme(SurfaceControl.Transaction t, boolean forceUpdate) { mImeWindowsContainer.setNeedsLayer(); final WindowState imeTarget = mImeLayeringTarget; // In the case where we have an IME target that is not in split-screen mode IME @@ -4657,14 +4666,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mImeWindowsContainer.assignRelativeLayer(t, imeTarget.getSurfaceControl(), // TODO: We need to use an extra level on the app surface to ensure // this is always above SurfaceView but always below attached window. - 1); + 1, forceUpdate); } else if (mInputMethodSurfaceParent != null) { // The IME surface parent may not be its window parent's surface // (@see #computeImeParent), so set relative layer here instead of letting the window // parent to assign layer. - mImeWindowsContainer.assignRelativeLayer(t, mInputMethodSurfaceParent, 1); + mImeWindowsContainer.assignRelativeLayer(t, mInputMethodSurfaceParent, 1, forceUpdate); } - super.assignChildLayers(t); } /** @@ -4677,7 +4685,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp * with {@link WindowState#assignLayer} */ void assignRelativeLayerForImeTargetChild(SurfaceControl.Transaction t, WindowContainer child) { - mImeWindowsContainer.setNeedsLayer(); child.assignRelativeLayer(t, mImeWindowsContainer.getSurfaceControl(), 1); } @@ -4823,7 +4830,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } mNoAnimationNotifyOnTransitionFinished.clear(); - mWallpaperController.hideDeferredWallpapersIfNeeded(); + mWallpaperController.hideDeferredWallpapersIfNeededLegacy(); onAppTransitionDone(); @@ -5262,13 +5269,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp || 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/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index af9cdeb52fe3..32152ec85493 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -69,7 +69,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL; import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE; -import static android.view.WindowManager.LayoutParams.TYPE_POINTER; import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL; @@ -243,7 +242,7 @@ public class DisplayPolicy { } } - private SystemGesturesPointerEventListener mSystemGestures; + private final SystemGesturesPointerEventListener mSystemGestures; private volatile int mLidState = LID_ABSENT; private volatile int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED; @@ -385,7 +384,7 @@ public class DisplayPolicy { private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0; private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1; - private GestureNavigationSettingsObserver mGestureNavigationSettingsObserver; + private final GestureNavigationSettingsObserver mGestureNavigationSettingsObserver; private final WindowManagerInternal.AppTransitionListener mAppTransitionListener; @@ -449,6 +448,119 @@ public class DisplayPolicy { final Looper looper = UiThread.getHandler().getLooper(); mHandler = new PolicyHandler(looper); + mSystemGestures = new SystemGesturesPointerEventListener(mContext, mHandler, + new SystemGesturesPointerEventListener.Callbacks() { + @Override + public void onSwipeFromTop() { + synchronized (mLock) { + if (mStatusBar != null) { + requestTransientBars(mStatusBar); + } + checkAltBarSwipeForTransientBars(ALT_BAR_TOP); + } + } + + @Override + public void onSwipeFromBottom() { + synchronized (mLock) { + if (mNavigationBar != null + && mNavigationBarPosition == NAV_BAR_BOTTOM) { + requestTransientBars(mNavigationBar); + } + checkAltBarSwipeForTransientBars(ALT_BAR_BOTTOM); + } + } + + @Override + public void onSwipeFromRight() { + final Region excludedRegion = Region.obtain(); + synchronized (mLock) { + mDisplayContent.calculateSystemGestureExclusion( + excludedRegion, null /* outUnrestricted */); + final boolean excluded = + mSystemGestures.currentGestureStartedInRegion(excludedRegion); + if (mNavigationBar != null && (mNavigationBarPosition == NAV_BAR_RIGHT + || !excluded && mNavigationBarAlwaysShowOnSideGesture)) { + requestTransientBars(mNavigationBar); + } + checkAltBarSwipeForTransientBars(ALT_BAR_RIGHT); + } + excludedRegion.recycle(); + } + + @Override + public void onSwipeFromLeft() { + final Region excludedRegion = Region.obtain(); + synchronized (mLock) { + mDisplayContent.calculateSystemGestureExclusion( + excludedRegion, null /* outUnrestricted */); + final boolean excluded = + mSystemGestures.currentGestureStartedInRegion(excludedRegion); + if (mNavigationBar != null && (mNavigationBarPosition == NAV_BAR_LEFT + || !excluded && mNavigationBarAlwaysShowOnSideGesture)) { + requestTransientBars(mNavigationBar); + } + checkAltBarSwipeForTransientBars(ALT_BAR_LEFT); + } + excludedRegion.recycle(); + } + + @Override + public void onFling(int duration) { + if (mService.mPowerManagerInternal != null) { + mService.mPowerManagerInternal.setPowerBoost( + Boost.INTERACTION, duration); + } + } + + @Override + public void onDebug() { + // no-op + } + + private WindowOrientationListener getOrientationListener() { + final DisplayRotation rotation = mDisplayContent.getDisplayRotation(); + return rotation != null ? rotation.getOrientationListener() : null; + } + + @Override + public void onDown() { + final WindowOrientationListener listener = getOrientationListener(); + if (listener != null) { + listener.onTouchStart(); + } + } + + @Override + public void onUpOrCancel() { + final WindowOrientationListener listener = getOrientationListener(); + if (listener != null) { + listener.onTouchEnd(); + } + } + + @Override + public void onMouseHoverAtTop() { + mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS); + Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS); + msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS; + mHandler.sendMessageDelayed(msg, 500 /* delayMillis */); + } + + @Override + public void onMouseHoverAtBottom() { + mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS); + Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS); + msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION; + mHandler.sendMessageDelayed(msg, 500 /* delayMillis */); + } + + @Override + public void onMouseLeaveFromEdge() { + mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS); + } + }); + displayContent.registerPointerEventListener(mSystemGestures); mAppTransitionListener = new WindowManagerInternal.AppTransitionListener() { private Runnable mAppTransitionPending = () -> { @@ -504,7 +616,7 @@ public class DisplayPolicy { mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext, looper, mService.mVrModeEnabled); - // TODO(b/180986447): Make it can take screenshot on external display + // TODO: Make it can take screenshot on external display mScreenshotHelper = displayContent.isDefaultDisplay ? new ScreenshotHelper(mContext) : null; @@ -528,6 +640,16 @@ public class DisplayPolicy { mRefreshRatePolicy = new RefreshRatePolicy(mService, mDisplayContent.getDisplayInfo(), mService.mHighRefreshRateDenylist); + + mGestureNavigationSettingsObserver = new GestureNavigationSettingsObserver(mHandler, + mContext, () -> { + synchronized (mLock) { + onConfigurationChanged(); + mSystemGestures.onConfigurationChanged(); + mDisplayContent.updateSystemGestureExclusion(); + } + }); + mHandler.post(mGestureNavigationSettingsObserver::register); } private void checkAltBarSwipeForTransientBars(@WindowManagerPolicy.AltBarPosition int pos) { @@ -546,154 +668,12 @@ public class DisplayPolicy { } void systemReady() { + mSystemGestures.systemReady(); if (mService.mPointerLocationEnabled) { setPointerLocationEnabled(true); } } - @NonNull - private GestureNavigationSettingsObserver getGestureNavigationSettingsObserver() { - if (mGestureNavigationSettingsObserver == null) { - mGestureNavigationSettingsObserver = new GestureNavigationSettingsObserver(mHandler, - mContext, () -> { - synchronized (mLock) { - onConfigurationChanged(); - getSystemGestures().onConfigurationChanged(); - mDisplayContent.updateSystemGestureExclusion(); - } - }); - mHandler.post(mGestureNavigationSettingsObserver::register); - } - return mGestureNavigationSettingsObserver; - } - - @NonNull - private SystemGesturesPointerEventListener getSystemGestures() { - if (mSystemGestures == null) { - final Context gestureContext = mUiContext.createWindowContext( - mDisplayContent.getDisplay(), TYPE_POINTER, null /* options */); - mSystemGestures = new SystemGesturesPointerEventListener(gestureContext, mHandler, - new SystemGesturesPointerEventListener.Callbacks() { - @Override - public void onSwipeFromTop() { - synchronized (mLock) { - if (mStatusBar != null) { - requestTransientBars(mStatusBar); - } - checkAltBarSwipeForTransientBars(ALT_BAR_TOP); - } - } - - @Override - public void onSwipeFromBottom() { - synchronized (mLock) { - if (mNavigationBar != null - && mNavigationBarPosition == NAV_BAR_BOTTOM) { - requestTransientBars(mNavigationBar); - } - checkAltBarSwipeForTransientBars(ALT_BAR_BOTTOM); - } - } - - @Override - public void onSwipeFromRight() { - final Region excludedRegion = Region.obtain(); - synchronized (mLock) { - mDisplayContent.calculateSystemGestureExclusion( - excludedRegion, null /* outUnrestricted */); - final boolean excluded = mSystemGestures - .currentGestureStartedInRegion(excludedRegion); - if (mNavigationBar != null - && (mNavigationBarPosition == NAV_BAR_RIGHT - || !excluded && mNavigationBarAlwaysShowOnSideGesture)) { - requestTransientBars(mNavigationBar); - } - checkAltBarSwipeForTransientBars(ALT_BAR_RIGHT); - } - excludedRegion.recycle(); - } - - @Override - public void onSwipeFromLeft() { - final Region excludedRegion = Region.obtain(); - synchronized (mLock) { - mDisplayContent.calculateSystemGestureExclusion( - excludedRegion, null /* outUnrestricted */); - final boolean excluded = mSystemGestures - .currentGestureStartedInRegion(excludedRegion); - if (mNavigationBar != null - && (mNavigationBarPosition == NAV_BAR_LEFT - || !excluded && mNavigationBarAlwaysShowOnSideGesture)) { - requestTransientBars(mNavigationBar); - } - checkAltBarSwipeForTransientBars(ALT_BAR_LEFT); - } - excludedRegion.recycle(); - } - - @Override - public void onFling(int duration) { - if (mService.mPowerManagerInternal != null) { - mService.mPowerManagerInternal.setPowerBoost( - Boost.INTERACTION, duration); - } - } - - @Override - public void onDebug() { - // no-op - } - - private WindowOrientationListener getOrientationListener() { - final DisplayRotation rotation = mDisplayContent.getDisplayRotation(); - return rotation != null ? rotation.getOrientationListener() : null; - } - - @Override - public void onDown() { - final WindowOrientationListener listener = getOrientationListener(); - if (listener != null) { - listener.onTouchStart(); - } - } - - @Override - public void onUpOrCancel() { - final WindowOrientationListener listener = getOrientationListener(); - if (listener != null) { - listener.onTouchEnd(); - } - } - - @Override - public void onMouseHoverAtTop() { - mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS); - Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS); - msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS; - mHandler.sendMessageDelayed(msg, 500 /* delayMillis */); - } - - @Override - public void onMouseHoverAtBottom() { - mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS); - Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS); - msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION; - mHandler.sendMessageDelayed(msg, 500 /* delayMillis */); - } - - @Override - public void onMouseLeaveFromEdge() { - mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS); - } - }); - mDisplayContent.registerPointerEventListener(getSystemGestures()); - if (mService.mSystemReady) { - mSystemGestures.systemReady(); - } - } - return mSystemGestures; - } - private int getDisplayId() { return mDisplayContent.getDisplayId(); } @@ -1475,7 +1455,8 @@ public class DisplayPolicy { } void onDisplayInfoChanged(DisplayInfo info) { - getSystemGestures().onDisplayInfoChanged(info); + mSystemGestures.screenWidth = info.logicalWidth; + mSystemGestures.screenHeight = info.logicalHeight; } private void layoutStatusBar(DisplayFrames displayFrames, Rect contentFrame) { @@ -1988,7 +1969,7 @@ public class DisplayPolicy { public void onOverlayChangedLw() { updateCurrentUserResources(); onConfigurationChanged(); - getSystemGestures().onConfigurationChanged(); + mSystemGestures.onConfigurationChanged(); } /** @@ -2059,10 +2040,10 @@ public class DisplayPolicy { } mNavBarOpacityMode = res.getInteger(R.integer.config_navBarOpacityMode); - final GestureNavigationSettingsObserver observer = getGestureNavigationSettingsObserver(); - mLeftGestureInset = observer.getLeftSensitivity(res); - mRightGestureInset = observer.getRightSensitivity(res); - mNavButtonForcedVisible = observer.areNavigationButtonForcedVisible(); + mLeftGestureInset = mGestureNavigationSettingsObserver.getLeftSensitivity(res); + mRightGestureInset = mGestureNavigationSettingsObserver.getRightSensitivity(res); + mNavButtonForcedVisible = + mGestureNavigationSettingsObserver.areNavigationButtonForcedVisible(); mNavigationBarLetsThroughTaps = res.getBoolean(R.bool.config_navBarTapThrough); mNavigationBarAlwaysShowOnSideGesture = res.getBoolean(R.bool.config_navBarAlwaysShowOnSideEdgeGesture); @@ -3075,7 +3056,7 @@ public class DisplayPolicy { } void release() { - mHandler.post(getGestureNavigationSettingsObserver()::unregister); + mHandler.post(mGestureNavigationSettingsObserver::unregister); } @VisibleForTesting diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java index 86518ea4ccc1..0b3c065e0e73 100644 --- a/services/core/java/com/android/server/wm/DragState.java +++ b/services/core/java/com/android/server/wm/DragState.java @@ -16,7 +16,7 @@ package com.android.server.wm; -import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; +import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java index 1f7e1524b702..316c20ba5c47 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 @@ class EnsureActivitiesVisibleHelper { 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/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java index 4d0c75c61aab..cbd5646968d7 100644 --- a/services/core/java/com/android/server/wm/InputConsumerImpl.java +++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java @@ -16,7 +16,7 @@ package com.android.server.wm; -import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; +import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; import android.graphics.Point; import android.graphics.Rect; diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java index 99c9e798c605..377e4989f65f 100644 --- a/services/core/java/com/android/server/wm/Letterbox.java +++ b/services/core/java/com/android/server/wm/Letterbox.java @@ -16,7 +16,7 @@ package com.android.server.wm; -import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; +import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; import static android.view.SurfaceControl.HIDDEN; import android.graphics.Color; diff --git a/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java b/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java index a98a47802914..f3859b41b6fd 100644 --- a/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java +++ b/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java @@ -126,17 +126,11 @@ class SystemGesturesPointerEventListener implements PointerEventListener { Slog.w(TAG, "Cannot create GestureDetector, display removed:" + displayId); return; } - onDisplayInfoChanged(info); mGestureDetector = new GestureDetector(mContext, new FlingGestureDetector(), mHandler) { }; }); } - void onDisplayInfoChanged(DisplayInfo info) { - screenWidth = info.logicalWidth; - screenHeight = info.logicalHeight; - } - @Override public void onPointerEvent(MotionEvent event) { if (mGestureDetector != null && event.isTouchEvent()) { diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 5efbb0956823..d992a4591a22 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_FORCED; 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 @@ class Task extends WindowContainer<WindowContainer> { @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 @@ class Task extends WindowContainer<WindowContainer> { @Override void resetSurfacePositionForAnimationLeash(SurfaceControl.Transaction t) { - if (isOrganized()) return; super.resetSurfacePositionForAnimationLeash(t); } @@ -4096,6 +4107,8 @@ class Task extends WindowContainer<WindowContainer> { : INVALID_TASK_ID; info.isFocused = isFocused(); info.isVisible = hasVisibleChildren(); + ActivityRecord topRecord = getTopNonFinishingActivity(); + info.mTopActivityLocusId = topRecord != null ? topRecord.getLocusId() : null; } @Nullable PictureInPictureParams getPictureInPictureParams() { @@ -7349,6 +7362,7 @@ class Task extends WindowContainer<WindowContainer> { 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 +7370,7 @@ class Task extends WindowContainer<WindowContainer> { 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 +7405,24 @@ class Task extends WindowContainer<WindowContainer> { 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/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index 76869e548fce..ed92fd08bef5 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -462,7 +462,7 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { mLastLeafTaskToFrontId = t.mTaskId; EventLogTags.writeWmTaskToFront(t.mUserId, t.mTaskId); - // Notifying only when a leak task moved to front. Or the listeners would be notified + // Notifying only when a leaf task moved to front. Or the listeners would be notified // couple times from the leaf task all the way up to the root task. mAtmService.getTaskChangeNotificationController().notifyTaskMovedToFront(t.getTaskInfo()); } diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java index ee5c1f014895..dff621c5871a 100644 --- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java +++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java @@ -406,6 +406,12 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { } } + if (taskDisplayArea == null && source != null) { + final TaskDisplayArea sourceDisplayArea = source.getDisplayArea(); + if (DEBUG) appendLog("display-area-from-source=" + sourceDisplayArea); + taskDisplayArea = sourceDisplayArea; + } + Task rootTask = (taskDisplayArea == null && task != null) ? task.getRootTask() : null; if (rootTask != null) { @@ -413,12 +419,6 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { taskDisplayArea = rootTask.getDisplayArea(); } - if (taskDisplayArea == null && source != null) { - final TaskDisplayArea sourceDisplayArea = source.getDisplayArea(); - if (DEBUG) appendLog("display-area-from-source=" + sourceDisplayArea); - taskDisplayArea = sourceDisplayArea; - } - if (taskDisplayArea == null && options != null) { final int callerDisplayId = options.getCallerDisplayId(); final DisplayContent dc = diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java index 6f7f113d100d..364246e1134e 100644 --- a/services/core/java/com/android/server/wm/TaskPositioner.java +++ b/services/core/java/com/android/server/wm/TaskPositioner.java @@ -18,7 +18,7 @@ package com.android.server.wm; import static android.app.ActivityTaskManager.RESIZE_MODE_USER; import static android.app.ActivityTaskManager.RESIZE_MODE_USER_FORCED; -import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; +import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_BOTTOM; diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 98eb11f8a970..aadb2722a313 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 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe 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 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe 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 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe // 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 */); + } + 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 */); } - ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, - " Commit activity becoming invisible: %s", ar); - ar.commitVisibility(false /* visible */, false /* performLayout */); } } @@ -455,8 +467,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe 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 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe } } + /** 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 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe 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 5f46ffe604a6..6338f39e2e67 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 @@ class TransitionController { * 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 @@ class TransitionController { } /** + * @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 @@ class TransitionController { /** @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 1a3138d492c8..7c5afa8282ee 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 @@ class WallpaperController { } 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 @@ class WallpaperController { } 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 @@ class WallpaperController { } } - 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 @@ class WallpaperController { } 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 @@ class WallpaperController { && (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 @@ class WallpaperController { // 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 43303d4a5d7e..717775605c94 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 @@ package com.android.server.wm; 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.ViewGroup; 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 @@ class WallpaperWindowToken extends WindowToken { 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 @@ class WallpaperWindowToken extends WindowToken { } @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 @@ class WallpaperWindowToken extends WindowToken { } } - 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 @@ class WallpaperWindowToken extends WindowToken { } 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 WindowState wallpaperTarget = wallpaperController.getWallpaperTarget(); if (visible && wallpaperTarget != null) { @@ -153,19 +137,52 @@ class WallpaperWindowToken extends WindowToken { } } - 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); + /** + * 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 (DEBUG_LAYERS || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "adjustWallpaper win " - + wallpaper); + // 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 @@ -186,9 +203,10 @@ class WallpaperWindowToken extends WindowToken { } 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 @@ class WallpaperWindowToken extends WindowToken { 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 000889a16d4c..8d859584d5f5 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -2241,15 +2241,20 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< } } - void assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) { + void assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer, + boolean forceUpdate) { final boolean changed = layer != mLastLayer || mLastRelativeToLayer != relativeTo; - if (mSurfaceControl != null && changed) { + if (mSurfaceControl != null && (changed || forceUpdate)) { setRelativeLayer(t, relativeTo, layer); mLastLayer = layer; mLastRelativeToLayer = relativeTo; } } + void assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) { + assignRelativeLayer(t, relativeTo, layer, false /* forceUpdate */); + } + protected void setLayer(Transaction t, int layer) { // Route through surface animator to accommodate that our surface control might be @@ -3060,6 +3065,11 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< } /** 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 c9e1605f7f0d..6f853c795525 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -33,7 +33,7 @@ import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT; import static android.content.pm.PackageManager.FEATURE_PC; import static android.content.pm.PackageManager.PERMISSION_GRANTED; -import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; +import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; import static android.os.Process.SYSTEM_UID; import static android.os.Process.myPid; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; @@ -463,12 +463,12 @@ public class WindowManagerService extends IWindowManager.Stub 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 @@ public class WindowManagerService extends IWindowManager.Stub 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 @@ public class WindowManagerService extends IWindowManager.Stub 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 @@ public class WindowManagerService extends IWindowManager.Stub } /** - * 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; } /** diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java index 645786c02fc0..a46a8d56e226 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 @@ public class WindowManagerShellCommand extends ShellCommand { 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 @@ public class WindowManagerShellCommand extends ShellCommand { 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 @@ public class WindowManagerShellCommand extends ShellCommand { 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 @@ public class WindowManagerShellCommand extends ShellCommand { // 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 @@ public class WindowManagerShellCommand extends ShellCommand { 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/WindowManagerThreadPriorityBooster.java b/services/core/java/com/android/server/wm/WindowManagerThreadPriorityBooster.java index dd89b3b29b9d..6f2930c46b12 100644 --- a/services/core/java/com/android/server/wm/WindowManagerThreadPriorityBooster.java +++ b/services/core/java/com/android/server/wm/WindowManagerThreadPriorityBooster.java @@ -17,11 +17,11 @@ package com.android.server.wm; import static android.os.Process.THREAD_PRIORITY_DISPLAY; +import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST; import static android.os.Process.myTid; import static android.os.Process.setThreadPriority; -import static com.android.server.LockGuard.INDEX_WINDOW; -import static com.android.server.am.ActivityManagerService.TOP_APP_PRIORITY_BOOST; +import static com.android.server.LockGuard.INDEX_WINDOW;; import com.android.internal.annotations.GuardedBy; import com.android.server.AnimationThread; @@ -93,7 +93,7 @@ class WindowManagerThreadPriorityBooster extends ThreadPriorityBooster { @GuardedBy("mLock") private void updatePriorityLocked() { int priority = (mAppTransitionRunning || mBoundsAnimationRunning) - ? TOP_APP_PRIORITY_BOOST : THREAD_PRIORITY_DISPLAY; + ? THREAD_PRIORITY_TOP_APP_BOOST : THREAD_PRIORITY_DISPLAY; setBoostToPriority(priority); setThreadPriority(mAnimationThreadId, priority); setThreadPriority(mSurfaceAnimationThreadId, priority); diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index c3620235d3df..c5e24a9df3a7 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -19,7 +19,7 @@ package com.android.server.wm; import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.os.Build.VERSION_CODES.Q; -import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; +import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION; import static com.android.internal.util.Preconditions.checkArgument; diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index fec715ec7f79..d9b879fdf8dc 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -26,7 +26,7 @@ import static android.app.WindowConfiguration.isSplitScreenWindowingMode; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.graphics.GraphicsProtos.dumpPointProto; import static android.hardware.input.InputManager.BLOCK_UNTRUSTED_TOUCHES; -import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; +import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; import static android.os.PowerManager.DRAW_WAKE_LOCK; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.InsetsState.ITYPE_IME; @@ -141,11 +141,9 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; 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 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP 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 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP @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 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP * {@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 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP 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 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // 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 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP 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 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP 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 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP 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 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP 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 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP 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 ece256e8c591..ebbebbb702d8 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.content.Context; 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 @@ class WindowStateAnimator { 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 @@ class WindowStateAnimator { 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 066cc1e105ab..8867aa747379 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_DOCK_DIVIDER; 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 @@ class WindowToken extends WindowContainer<WindowState> { */ 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 @@ class WindowToken extends WindowContainer<WindowState> { 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_am_CachedAppOptimizer.cpp b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp index 8c6d084fba99..a4a74af8a1d9 100644 --- a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp +++ b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp @@ -135,7 +135,7 @@ static int getAnyPageAdvice(const Vma& vma) { static int compactProcess(int pid, VmaToAdviseFunc vmaToAdviseFunc) { ProcMemInfo meminfo(pid); std::vector<Vma> pageoutVmas, coldVmas; - auto vmaCollectorCb = [&](Vma vma) { + auto vmaCollectorCb = [&coldVmas,&pageoutVmas,&vmaToAdviseFunc](const Vma& vma) { int advice = vmaToAdviseFunc(vma); switch (advice) { case MADV_COLD: @@ -146,7 +146,7 @@ static int compactProcess(int pid, VmaToAdviseFunc vmaToAdviseFunc) { break; } }; - meminfo.ForEachVma(vmaCollectorCb); + meminfo.ForEachVmaFromMaps(vmaCollectorCb); int err = compactMemory(pageoutVmas, pid, MADV_PAGEOUT); if (!err) { diff --git a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp index 7b78b8d23b4b..f0210eeb80e8 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,64 @@ private: }; 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 < 0 ? pageReads[0].serialNo : 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 { + 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) { + traceMissingReads(expectedSerialNo, read.serialNo); } + + 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 +720,17 @@ private: ATRACE_END(); } + void traceMissingReads(int64_t expectedSerialNo, int64_t readSerialNo) { + const auto readsMissing = readSerialNo - expectedSerialNo; + const auto trace = + android::base::StringPrintf("missing_page_reads: count=%lld, range [%lld,%lld)", + static_cast<long long>(readsMissing), + static_cast<long long>(expectedSerialNo), + static_cast<long long>(readSerialNo)); + 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 +877,7 @@ private: 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 89b931d35c40..ef2d0baff031 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 @@ static jlong vibratorPerformEffect(JNIEnv* env, jclass /* clazz */, jlong ptr, j 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 @@ static void vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jlong 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 @@ static const JNINativeMethod method_table[] = { {"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/core/jni/gnss/GnssMeasurementCallback.cpp b/services/core/jni/gnss/GnssMeasurementCallback.cpp index 757381dff80a..945694649f92 100644 --- a/services/core/jni/gnss/GnssMeasurementCallback.cpp +++ b/services/core/jni/gnss/GnssMeasurementCallback.cpp @@ -131,7 +131,7 @@ void GnssMeasurement_class_init_once(JNIEnv* env, jclass& clazz) { "([I)Landroid/location/CorrelationVector$Builder;"); method_correlationVectorBuilderSetFrequencyOffsetMetersPerSecond = env->GetMethodID(class_correlationVectorBuilder, "setFrequencyOffsetMetersPerSecond", - "(I)Landroid/location/CorrelationVector$Builder;"); + "(D)Landroid/location/CorrelationVector$Builder;"); method_correlationVectorBuilderSetSamplingStartMeters = env->GetMethodID(class_correlationVectorBuilder, "setSamplingStartMeters", "(D)Landroid/location/CorrelationVector$Builder;"); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java index ef7afc8d1894..cdd5a92bec7a 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 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub { 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/DevicePolicyData.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java index ba3ae45e99f8..c0b2ed4cc955 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java @@ -399,7 +399,7 @@ class DevicePolicyData { * @param adminInfoSupplier function that queries DeviceAdminInfo from PackageManager * @param ownerComponent device or profile owner component if any. */ - static boolean load(DevicePolicyData policy, boolean isFdeDevice, JournaledFile journaledFile, + static void load(DevicePolicyData policy, boolean isFdeDevice, JournaledFile journaledFile, Function<ComponentName, DeviceAdminInfo> adminInfoSupplier, ComponentName ownerComponent) { FileInputStream stream = null; @@ -407,7 +407,7 @@ class DevicePolicyData { if (VERBOSE_LOG) { Slog.v(TAG, "Loading data for user " + policy.mUserId + " from " + file); } - boolean needsRewrite = false; + try { stream = new FileInputStream(file); TypedXmlPullParser parser = Xml.resolvePullParser(stream); @@ -541,10 +541,6 @@ class DevicePolicyData { policy.mAdminBroadcastPending = Boolean.toString(true).equals(pending); } else if (TAG_INITIALIZATION_BUNDLE.equals(tag)) { policy.mInitBundle = PersistableBundle.restoreFromXml(parser); - } else if ("active-password".equals(tag)) { - // Remove password metrics from saved settings, as we no longer wish to store - // these on disk - needsRewrite = true; } else if (TAG_PASSWORD_VALIDITY.equals(tag)) { if (isFdeDevice) { // This flag is only used for FDE devices @@ -584,7 +580,6 @@ class DevicePolicyData { // Generate a list of admins from the admin map policy.mAdminList.addAll(policy.mAdminMap.values()); - return needsRewrite; } void validatePasswordOwner() { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 28e9acf8d883..2c1c9a957d85 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -371,9 +371,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { protected static final String LOG_TAG = "DevicePolicyManager"; - private static final boolean VERBOSE_LOG = false; // DO NOT SUBMIT WITH TRUE + static final boolean VERBOSE_LOG = false; // DO NOT SUBMIT WITH TRUE - private static final String DEVICE_POLICIES_XML = "device_policies.xml"; + static final String DEVICE_POLICIES_XML = "device_policies.xml"; + + static final String POLICIES_VERSION_XML = "device_policies_version"; private static final String TRANSFER_OWNERSHIP_PARAMETERS_XML = "transfer-ownership-parameters.xml"; @@ -466,8 +468,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private static final Set<String> GLOBAL_SETTINGS_DEPRECATED; private static final Set<String> SYSTEM_SETTINGS_ALLOWLIST; private static final Set<Integer> DA_DISALLOWED_POLICIES; - // A collection of user restrictions that are deprecated and should simply be ignored. private static final String AB_DEVICE_KEY = "ro.build.ab_update"; + // The version of the current DevicePolicyManagerService data. This version is used + // to decide whether an existing policy in the {@link #DEVICE_POLICIES_XML} needs to + // be upgraded. See {@link PolicyVersionUpgrader} on instructions how to add an upgrade + // step. + static final int DPMS_VERSION = 1; static { SECURE_SETTINGS_ALLOWLIST = new ArraySet<>(); @@ -1583,8 +1589,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } public String[] getPersonalAppsForSuspension(int userId) { - return new PersonalAppsSuspensionHelper( - mContext.createContextAsUser(UserHandle.of(userId), 0 /* flags */)) + return PersonalAppsSuspensionHelper.forUser(mContext, userId) .getPersonalAppsForSuspension(); } @@ -1599,6 +1604,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { void setDevicePolicySafetyChecker(DevicePolicySafetyChecker safetyChecker) { mSafetyChecker = safetyChecker; } + + void dumpPerUserData(IndentingPrintWriter pw, @UserIdInt int userId) { + PersonalAppsSuspensionHelper.forUser(mContext, userId).dump(pw); + } } /** @@ -2760,8 +2769,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { : mInjector.environmentGetUserSystemDirectory(userId); } - private JournaledFile makeJournaledFile(@UserIdInt int userId) { - final String base = new File(getPolicyFileDirectory(userId), DEVICE_POLICIES_XML) + private JournaledFile makeJournaledFile(@UserIdInt int userId, String fileName) { + final String base = new File(getPolicyFileDirectory(userId), fileName) .getAbsolutePath(); if (VERBOSE_LOG) { Log.v(LOG_TAG, "Opening " + base); @@ -2769,6 +2778,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return new JournaledFile(new File(base), new File(base + ".tmp")); } + private JournaledFile makeJournaledFile(@UserIdInt int userId) { + return makeJournaledFile(userId, DEVICE_POLICIES_XML); + } + /** * Persist modified values to disk by calling {@link #saveSettingsLocked} for each * affected user ID. @@ -2797,18 +2810,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } private void loadSettingsLocked(DevicePolicyData policy, int userHandle) { - boolean needsRewrite = DevicePolicyData.load(policy, + DevicePolicyData.load(policy, !mInjector.storageManagerIsFileBasedEncryptionEnabled(), makeJournaledFile(userHandle), component -> findAdmin( component, userHandle, /* throwForMissingPermission= */ false), getOwnerComponent(userHandle)); - // Might need to upgrade the file by rewriting it - if (needsRewrite) { - saveSettingsLocked(userHandle); - } - policy.validatePasswordOwner(); updateMaximumTimeToLockLocked(userHandle); updateLockTaskPackagesLocked(policy.mLockTaskPackages, userHandle); @@ -2922,6 +2930,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private void onLockSettingsReady() { synchronized (getLockObject()) { migrateUserRestrictionsIfNecessaryLocked(); + performPolicyVersionUpgrade(); } getUserData(UserHandle.USER_SYSTEM); cleanUpOldUsers(); @@ -2962,6 +2971,47 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { updateUsbDataSignal(); } + private class DpmsUpgradeDataProvider implements PolicyUpgraderDataProvider { + @Override + public boolean isUserDeviceOwner(int userId) { + return mOwners.isDeviceOwnerUserId(userId); + } + + @Override + public boolean storageManagerIsFileBasedEncryptionEnabled() { + return mInjector.storageManagerIsFileBasedEncryptionEnabled(); + } + + @Override + public JournaledFile makeDevicePoliciesJournaledFile(int userId) { + return DevicePolicyManagerService.this.makeJournaledFile(userId, DEVICE_POLICIES_XML); + } + + @Override + public JournaledFile makePoliciesVersionJournaledFile(int userId) { + return DevicePolicyManagerService.this.makeJournaledFile(userId, POLICIES_VERSION_XML); + } + + @Override + public ComponentName getOwnerComponent(int userId) { + return DevicePolicyManagerService.this.getOwnerComponent(userId); + } + + @Override + public Function<ComponentName, DeviceAdminInfo> getAdminInfoSupplier(int userId) { + return component -> findAdmin(component, userId, /* throwForMissingPermission= */ + false); + } + } + + private void performPolicyVersionUpgrade() { + List<UserInfo> allUsers = mUserManager.getUsers(); + PolicyVersionUpgrader upgrader = new PolicyVersionUpgrader( + new DpmsUpgradeDataProvider()); + + upgrader.upgradePolicy(allUsers.stream().mapToInt(u -> u.id).toArray(), DPMS_VERSION); + } + private void revertTransferOwnershipIfNecessaryLocked() { if (!mTransferOwnershipMetadataManager.metadataFileExists()) { return; @@ -5458,6 +5508,42 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @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 +5565,21 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { 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); @@ -5686,6 +5774,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (generationResult != KeyChain.KEY_GEN_SUCCESS) { Log.e(LOG_TAG, String.format( "KeyChain failed to generate a keypair, error %d.", generationResult)); + logGenerateKeyPairFailure(caller, isCredentialManagementApp); switch (generationResult) { case KeyChain.KEY_GEN_STRONGBOX_UNAVAILABLE: throw new ServiceSpecificException( @@ -5695,7 +5784,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { throw new UnsupportedOperationException( "Device does not support Device ID attestation."); default: - logGenerateKeyPairFailure(caller, isCredentialManagementApp); return false; } } @@ -7591,15 +7679,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private void sendActiveAdminCommand(String action, Bundle extras, @UserIdInt int userId, ComponentName receiverComponent) { - if (VERBOSE_LOG) { - Slog.v(LOG_TAG, "sending intent " + action + " to " - + receiverComponent.flattenToShortString() + " on user " + userId); - } final Intent intent = new Intent(action); intent.setComponent(receiverComponent); if (extras != null) { intent.putExtras(extras); } + if (VERBOSE_LOG) { + Slog.v(LOG_TAG, "sendActiveAdminCommand(): broadcasting " + action + " to " + + receiverComponent.flattenToShortString() + " on user " + userId); + } mContext.sendBroadcastAsUser(intent, UserHandle.of(userId)); } @@ -9161,11 +9249,17 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - 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 +9277,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { pw.println(); mDeviceAdminServiceController.dump(pw); pw.println(); - dumpDevicePolicyData(pw); + dumpPerUserData(pw); pw.println(); mConstants.dump(pw); pw.println(); @@ -9229,20 +9323,30 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { 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(); } @@ -12437,10 +12541,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { extras.putBoolean(DeviceAdminReceiver.EXTRA_OPERATION_SAFETY_STATE, isSafe); if (mOwners.hasDeviceOwner()) { + if (VERBOSE_LOG) Slog.v(LOG_TAG, "Notifying DO"); sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_OPERATION_SAFETY_STATE_CHANGED, extras); } for (int profileOwnerId : mOwners.getProfileOwnerKeys()) { + if (VERBOSE_LOG) Slog.v(LOG_TAG, "Notifying PO for user " + profileOwnerId); sendProfileOwnerCommand(DeviceAdminReceiver.ACTION_OPERATION_SAFETY_STATE_CHANGED, extras, profileOwnerId); } @@ -13620,6 +13726,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { mInjector.binderWithCleanCallingIdentity(() -> { // Clear restriction as user. final UserHandle parentUser = mUserManager.getProfileParent(UserHandle.of(userId)); + if (parentUser == null) { + throw new IllegalStateException(String.format("User %d is not a profile", userId)); + } if (!parentUser.isSystem()) { throw new IllegalStateException( String.format("Only the profile owner of a managed profile on the" diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java b/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java index 257fc640f93c..86437a27a64d 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java @@ -60,7 +60,7 @@ final class OneTimeSafetyChecker implements DevicePolicySafetyChecker { mOperation = operation; mReason = reason; mRealSafetyChecker = service.getDevicePolicySafetyChecker(); - Slog.i(TAG, "OneTimeSafetyChecker constructor: operation= " + operationToString(operation) + Slog.i(TAG, "OneTimeSafetyChecker constructor: operation=" + operationToString(operation) + ", reason=" + operationSafetyReasonToString(reason) + ", realChecker=" + mRealSafetyChecker + ", maxDuration=" + SELF_DESTRUCT_TIMEOUT_MS + "ms"); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java b/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java index c687184265c1..37dbfc170aff 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 static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL 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.PackageManager; 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 @@ import java.util.Set; /** * 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 @@ public class PersonalAppsSuspensionHelper { 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 @@ public class PersonalAppsSuspensionHelper { 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/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java new file mode 100644 index 000000000000..b6420f8ff4bc --- /dev/null +++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java @@ -0,0 +1,63 @@ +/* + * 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.devicepolicy; + +import android.annotation.Nullable; +import android.app.admin.DeviceAdminInfo; +import android.content.ComponentName; + +import com.android.internal.util.JournaledFile; + +import java.util.function.Function; + +/** + * An interface for providing the {@code PolicyVersionUpgrader} with all the data necessary + * to go through the upgrade process. + */ +public interface PolicyUpgraderDataProvider { + /** + * Returns true if the provided {@code userId} is a device owner. May affect some policy + * defaults. + */ + boolean isUserDeviceOwner(int userId); + + /** + * Returns true if the storage manager indicates file-based encryption is enabled. + */ + boolean storageManagerIsFileBasedEncryptionEnabled(); + + /** + * Returns the journaled policies file for a given user. + */ + JournaledFile makeDevicePoliciesJournaledFile(int userId); + + /** + * Returns the journaled policy version file for a given user. + */ + JournaledFile makePoliciesVersionJournaledFile(int userId); + + /** + * Returns the {@code ComponentName} of the owner component for a user. + */ + @Nullable ComponentName getOwnerComponent(int userId); + + /** + * Returns a function which provides the component name and device admin info for a given + * user. + */ + Function<ComponentName, DeviceAdminInfo> getAdminInfoSupplier(int userId); +} diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java new file mode 100644 index 000000000000..cea08634910c --- /dev/null +++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java @@ -0,0 +1,168 @@ +/* + * 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.devicepolicy; + +import android.os.UserHandle; +import android.util.Slog; +import android.util.SparseArray; + +import com.android.internal.util.JournaledFile; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.file.Files; + +/** + * Class for dealing with Device Policy Manager Service version upgrades. + * Initially, this class is responsible for upgrading the "device_policies.xml" file upon + * platform version upgrade. + * + * It is useful for policies which have a different default for an upgrading device than a + * newly-configured device (for example, the admin can grant sensors-related permissions by + * default on existing fully-managed devices that upgrade to Android S, but on devices set up + * with Android S the value of the policy is set explicitly during set-up). + * + * Practically, it's useful for changes to the data model of the {@code DevicePolicyData} and + * {@code ActiveAdmin} classes. + * + * To add a new upgrade step: + * (1) Increase the {@code DPMS_VERSION} constant in {@code DevicePolicyManagerService} by one. + * (2) Add an if statement in {@code upgradePolicy} comparing the version, performing the upgrade + * step and setting the value of {@code currentVersion} to the newly-incremented version. + * (3) Add a test in {@code PolicyVersionUpgraderTest}. + */ +public class PolicyVersionUpgrader { + private static final String LOG_TAG = "DevicePolicyManager"; + private static final boolean VERBOSE_LOG = DevicePolicyManagerService.VERBOSE_LOG; + private final PolicyUpgraderDataProvider mProvider; + + public PolicyVersionUpgrader(PolicyUpgraderDataProvider provider) { + mProvider = provider; + } + + /** + * Performs the upgrade steps for all users on the system. + * + * @param allUsers List of all user IDs on the system, including disabled users, as well as + * managed profile user IDs. + * @param dpmsVersion The version to upgrade to. + */ + public void upgradePolicy(int[] allUsers, int dpmsVersion) { + int oldVersion = readVersion(); + if (oldVersion >= dpmsVersion) { + Slog.i(LOG_TAG, String.format("Current version %d, latest version %d, not upgrading.", + oldVersion, dpmsVersion)); + return; + } + + //NOTE: The current version is provided in case the XML file format changes in a + // non-backwards-compatible way, so that DeviceAdminData could load it with + // old tags, for example. + final SparseArray<DevicePolicyData> allUsersData = loadAllUsersData(allUsers, oldVersion); + + int currentVersion = oldVersion; + if (currentVersion == 0) { + Slog.i(LOG_TAG, String.format("Upgrading from version %d", currentVersion)); + // The first upgrade (from no version to version 1) is to overwrite + // the "active-password" tag in case it was left around. + currentVersion = 1; + } + + writePoliciesAndVersion(allUsers, allUsersData, currentVersion); + } + + private void writePoliciesAndVersion(int[] allUsers, SparseArray<DevicePolicyData> allUsersData, + int currentVersion) { + boolean allWritesSuccessful = true; + for (int user : allUsers) { + allWritesSuccessful = allWritesSuccessful && writeDataForUser(user, + allUsersData.get(user)); + } + + if (allWritesSuccessful) { + writeVersion(currentVersion); + } else { + Slog.e(LOG_TAG, String.format("Error: Failed upgrading policies to version %d", + currentVersion)); + } + } + + private SparseArray<DevicePolicyData> loadAllUsersData(int[] allUsers, int loadVersion) { + final SparseArray<DevicePolicyData> allUsersData = new SparseArray<>(); + for (int user: allUsers) { + allUsersData.append(user, loadDataForUser(user, loadVersion)); + } + return allUsersData; + } + + private DevicePolicyData loadDataForUser(int userId, int loadVersion) { + DevicePolicyData policy = new DevicePolicyData(userId); + DevicePolicyData.load(policy, + !mProvider.storageManagerIsFileBasedEncryptionEnabled(), + mProvider.makeDevicePoliciesJournaledFile(userId), + mProvider.getAdminInfoSupplier(userId), + mProvider.getOwnerComponent(userId)); + return policy; + } + + private boolean writeDataForUser(int userId, DevicePolicyData policy) { + return DevicePolicyData.store( + policy, + mProvider.makeDevicePoliciesJournaledFile(userId), + !mProvider.storageManagerIsFileBasedEncryptionEnabled()); + } + + private JournaledFile getVersionFile() { + return mProvider.makePoliciesVersionJournaledFile(UserHandle.USER_SYSTEM); + } + + private int readVersion() { + JournaledFile versionFile = getVersionFile(); + + File file = versionFile.chooseForRead(); + if (VERBOSE_LOG) { + Slog.v(LOG_TAG, "Loading version from " + file); + } + try { + String versionString = Files.readAllLines( + file.toPath(), Charset.defaultCharset()).get(0); + return Integer.parseInt(versionString); + } catch (IOException | NumberFormatException | IndexOutOfBoundsException e) { + Slog.e(LOG_TAG, "Error reading version", e); + return 0; + } + } + + private void writeVersion(int version) { + JournaledFile versionFile = getVersionFile(); + + File file = versionFile.chooseForWrite(); + if (VERBOSE_LOG) { + Slog.v(LOG_TAG, String.format("Writing new version to: %s", file)); + } + + try { + byte[] versionBytes = String.format("%d", version).getBytes(); + Files.write(file.toPath(), versionBytes); + versionFile.commit(); + } catch (IOException e) { + Slog.e(LOG_TAG, String.format("Writing version %d failed: %s", version), e); + versionFile.rollback(); + } + } +} diff --git a/services/incremental/OWNERS b/services/incremental/OWNERS index d825dfd7cf00..ad5eca7f6daf 100644 --- a/services/incremental/OWNERS +++ b/services/incremental/OWNERS @@ -1 +1,7 @@ +# Bug component: 554432 include /services/core/java/com/android/server/pm/OWNERS + +alexbuy@google.com +schfan@google.com +toddke@google.com +zyy@google.com diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index a3d335340e9f..5fbf1c4e1f40 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -53,7 +53,6 @@ import android.graphics.Typeface; 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 @@ public final class SystemServer implements Dumpable { 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 @@ public final class SystemServer implements Dumpable { // 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/DomainVerificationPersistenceTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPersistenceTest.kt index ad9aa7b6e3ae..6597577cf14f 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 @@ -30,6 +30,7 @@ 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 @@ class DomainVerificationPersistenceTest { 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") + } } } 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 f7f592886473..3870b02ba37c 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 @@ public class ConnectivityControllerTest { 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 91b3cb7dbdd9..7925b69852ba 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 @@ public class JobStatusTest { 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/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt index 6e27b3a8166c..e853fd341ae5 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt +++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt @@ -287,6 +287,7 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) { whenever(mocks.settings.internalVersion).thenReturn(DEFAULT_VERSION_INFO) whenever(mocks.settings.keySetManagerService).thenReturn(mocks.keySetManagerService) whenever(mocks.settings.keySetManagerService).thenReturn(mocks.keySetManagerService) + whenever(mocks.settings.snapshot()).thenReturn(mocks.settings) whenever(mocks.packageAbiHelper.derivePackageAbi( any(AndroidPackage::class.java), anyBoolean(), nullable(), any(File::class.java))) { android.util.Pair(PackageAbiHelper.Abis("", ""), diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt new file mode 100644 index 000000000000..a0e208f662e3 --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt @@ -0,0 +1,81 @@ +/* + * 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.pm + +import android.os.Build +import com.android.server.apphibernation.AppHibernationManagerInternal +import com.android.server.testutils.whenever +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@RunWith(JUnit4::class) +class PackageManagerServiceHibernationTests { + + companion object { + val TEST_PACKAGE_NAME = "test.package" + val TEST_USER_ID = 0 + } + + @Rule + @JvmField + val rule = MockSystemRule() + + @Mock + lateinit var appHibernationManager: AppHibernationManagerInternal + + @Before + @Throws(Exception::class) + fun setup() { + MockitoAnnotations.initMocks(this) + rule.system().stageNominalSystemState() + whenever(rule.mocks().injector.getLocalService(AppHibernationManagerInternal::class.java)) + .thenReturn(appHibernationManager) + } + + @Test + fun testExitForceStopExitsHibernation() { + rule.system().stageScanExistingPackage( + TEST_PACKAGE_NAME, + 1L, + rule.system().dataAppDirectory) + val pm = createPackageManagerService() + rule.system().validateFinalState() + val ps = pm.getPackageSetting(TEST_PACKAGE_NAME) + ps!!.setStopped(true, TEST_USER_ID) + + pm.setPackageStoppedState(TEST_PACKAGE_NAME, false, TEST_USER_ID) + verify(appHibernationManager).setHibernatingForUser(TEST_PACKAGE_NAME, TEST_USER_ID, false) + verify(appHibernationManager).setHibernatingGlobally(TEST_PACKAGE_NAME, false) + } + + private fun createPackageManagerService(): PackageManagerService { + return PackageManagerService(rule.mocks().injector, + false /*coreOnly*/, + false /*factoryTest*/, + MockSystem.DEFAULT_VERSION_INFO.fingerprint, + false /*isEngBuild*/, + false /*isUserDebugBuild*/, + Build.VERSION_CODES.CUR_DEVELOPMENT, + Build.VERSION.INCREMENTAL) + } +} diff --git a/services/tests/servicestests/assets/PolicyVersionUpgraderTest/device_policies.xml b/services/tests/servicestests/assets/PolicyVersionUpgraderTest/device_policies.xml new file mode 100644 index 000000000000..d6ad99d7965d --- /dev/null +++ b/services/tests/servicestests/assets/PolicyVersionUpgraderTest/device_policies.xml @@ -0,0 +1,9 @@ +<?xml version='1.0' encoding='utf-8' standalone='yes' ?> +<policies setup-complete="true" provisioning-state="3"> +<admin name="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin1"> + <policies flags="991" /> + <strong-auth-unlock-timeout value="0" /> + <organization-color value="-16738680" /> + <active-password value="0" /> +</admin> +</policies> 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 000000000000..489e2f769a3d --- /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 f897d5ca3cc8..d6c11a549dfa 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 @@ public class AbstractAccessibilityServiceConnectionTest { 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/KeyEventDispatcherTest.java b/services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java index 85b8fcbbcc61..ebb73e877db4 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.Looper; 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 @@ public class KeyEventDispatcherTest { 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 @@ public class KeyEventDispatcherTest { 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 @@ public class KeyEventDispatcherTest { 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 @@ public class KeyEventDispatcherTest { 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 @@ public class KeyEventDispatcherTest { 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 @@ public class KeyEventDispatcherTest { 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/am/MeasuredEnergySnapshotTest.java b/services/tests/servicestests/src/com/android/server/am/MeasuredEnergySnapshotTest.java index 1efce39e00fa..3231f6204a12 100644 --- a/services/tests/servicestests/src/com/android/server/am/MeasuredEnergySnapshotTest.java +++ b/services/tests/servicestests/src/com/android/server/am/MeasuredEnergySnapshotTest.java @@ -57,45 +57,58 @@ public final class MeasuredEnergySnapshotTest { private static final SparseArray<EnergyConsumer> SOME_ID_CONSUMER_MAP = createIdToConsumerMap( CONSUMER_DISPLAY); + private static final int VOLTAGE_0 = 4_000; + private static final int VOLTAGE_1 = 3_500; + private static final int VOLTAGE_2 = 3_100; + private static final int VOLTAGE_3 = 3_000; + private static final int VOLTAGE_4 = 2_800; + // Elements in each results are purposefully out of order. - private static final EnergyConsumerResult[] RESULTS_0 = new EnergyConsumerResult[] { - createEnergyConsumerResult(CONSUMER_OTHER_0.id, 90, new int[] {47, 3}, new long[] {14, 13}), - createEnergyConsumerResult(CONSUMER_DISPLAY.id, 14, null, null), - createEnergyConsumerResult(CONSUMER_OTHER_1.id, 0, null, null), - // No CONSUMER_OTHER_2 + private static final EnergyConsumerResult[] RESULTS_0 = new EnergyConsumerResult[]{ + createEnergyConsumerResult(CONSUMER_OTHER_0.id, 90_000, new int[]{47, 3}, + new long[]{14_000, 13_000}), + createEnergyConsumerResult(CONSUMER_DISPLAY.id, 14_000, null, null), + createEnergyConsumerResult(CONSUMER_OTHER_1.id, 0, null, null), + // No CONSUMER_OTHER_2 }; - private static final EnergyConsumerResult[] RESULTS_1 = new EnergyConsumerResult[] { - createEnergyConsumerResult(CONSUMER_DISPLAY.id, 24, null, null), - createEnergyConsumerResult(CONSUMER_OTHER_0.id, 90, new int[] {47, 3}, new long[] {14, 13}), - createEnergyConsumerResult(CONSUMER_OTHER_2.id, 12, new int[] {6}, new long[] {10}), - createEnergyConsumerResult(CONSUMER_OTHER_1.id, 12_000, null, null), + private static final EnergyConsumerResult[] RESULTS_1 = new EnergyConsumerResult[]{ + createEnergyConsumerResult(CONSUMER_DISPLAY.id, 24_000, null, null), + createEnergyConsumerResult(CONSUMER_OTHER_0.id, 90_000, new int[]{47, 3}, + new long[]{14_000, 13_000}), + createEnergyConsumerResult(CONSUMER_OTHER_2.id, 12_000, new int[]{6}, + new long[]{10_000}), + createEnergyConsumerResult(CONSUMER_OTHER_1.id, 12_000_000, null, null), }; - private static final EnergyConsumerResult[] RESULTS_2 = new EnergyConsumerResult[] { - createEnergyConsumerResult(CONSUMER_DISPLAY.id, 36, null, null), - // No CONSUMER_OTHER_0 - // No CONSUMER_OTHER_1 - // No CONSUMER_OTHER_2 + private static final EnergyConsumerResult[] RESULTS_2 = new EnergyConsumerResult[]{ + createEnergyConsumerResult(CONSUMER_DISPLAY.id, 36_000, null, null), + // No CONSUMER_OTHER_0 + // No CONSUMER_OTHER_1 + // No CONSUMER_OTHER_2 }; - private static final EnergyConsumerResult[] RESULTS_3 = new EnergyConsumerResult[] { - // No CONSUMER_DISPLAY - createEnergyConsumerResult(CONSUMER_OTHER_2.id, 13, new int[] {6}, new long[] {10}), - createEnergyConsumerResult( - CONSUMER_OTHER_0.id, 190, new int[] {2, 3, 47, 7}, new long[] {9, 18, 14, 6}), - createEnergyConsumerResult(CONSUMER_OTHER_1.id, 12_000, null, null), + private static final EnergyConsumerResult[] RESULTS_3 = new EnergyConsumerResult[]{ + // No CONSUMER_DISPLAY + createEnergyConsumerResult(CONSUMER_OTHER_2.id, 13_000, new int[]{6}, + new long[]{10_000}), + createEnergyConsumerResult( + CONSUMER_OTHER_0.id, 190_000, new int[]{2, 3, 47, 7}, + new long[]{9_000, 18_000, 14_000, 6_000}), + createEnergyConsumerResult(CONSUMER_OTHER_1.id, 12_000_000, null, null), }; - private static final EnergyConsumerResult[] RESULTS_4 = new EnergyConsumerResult[] { - createEnergyConsumerResult(CONSUMER_DISPLAY.id, 43, null, null), - createEnergyConsumerResult( - CONSUMER_OTHER_0.id, 290, new int[] {7, 47, 3, 2}, new long[] {6, 14, 18, 11}), - // No CONSUMER_OTHER_1 - createEnergyConsumerResult(CONSUMER_OTHER_2.id, 165, new int[] {6, 47}, new long[] {10, 8}), + private static final EnergyConsumerResult[] RESULTS_4 = new EnergyConsumerResult[]{ + createEnergyConsumerResult(CONSUMER_DISPLAY.id, 43_000, null, null), + createEnergyConsumerResult( + CONSUMER_OTHER_0.id, 290_000, new int[]{7, 47, 3, 2}, + new long[]{6_000, 14_000, 18_000, 11_000}), + // No CONSUMER_OTHER_1 + createEnergyConsumerResult(CONSUMER_OTHER_2.id, 165_000, new int[]{6, 47}, + new long[]{10_000, 8_000}), }; @Test public void testUpdateAndGetDelta_empty() { final MeasuredEnergySnapshot snapshot = new MeasuredEnergySnapshot(ALL_ID_CONSUMER_MAP); - assertNull(snapshot.updateAndGetDelta(null)); - assertNull(snapshot.updateAndGetDelta(new EnergyConsumerResult[0])); + assertNull(snapshot.updateAndGetDelta(null, VOLTAGE_0)); + assertNull(snapshot.updateAndGetDelta(new EnergyConsumerResult[0], VOLTAGE_0)); } @Test @@ -103,69 +116,88 @@ public final class MeasuredEnergySnapshotTest { final MeasuredEnergySnapshot snapshot = new MeasuredEnergySnapshot(ALL_ID_CONSUMER_MAP); // results0 - MeasuredEnergyDeltaData delta = snapshot.updateAndGetDelta(RESULTS_0); + MeasuredEnergyDeltaData delta = snapshot.updateAndGetDelta(RESULTS_0, VOLTAGE_0); if (delta != null) { // null is fine here. If non-null, it better be uninteresting though. - assertEquals(UNAVAILABLE, delta.displayEnergyUJ); - assertNull(delta.otherTotalEnergyUJ); - assertNull(delta.otherUidEnergiesUJ); + assertEquals(UNAVAILABLE, delta.displayChargeUC); + assertNull(delta.otherTotalChargeUC); + assertNull(delta.otherUidChargesUC); } // results1 - delta = snapshot.updateAndGetDelta(RESULTS_1); + delta = snapshot.updateAndGetDelta(RESULTS_1, VOLTAGE_1); assertNotNull(delta); - assertEquals(24 - 14, delta.displayEnergyUJ); + long expectedChargeUC; + expectedChargeUC = calculateChargeConsumedUC(14_000, VOLTAGE_0, 24_000, VOLTAGE_1); + assertEquals(expectedChargeUC, delta.displayChargeUC); + + assertNotNull(delta.otherTotalChargeUC); - assertNotNull(delta.otherTotalEnergyUJ); - assertEquals(90 - 90, delta.otherTotalEnergyUJ[0]); - assertEquals(12_000 - 0, delta.otherTotalEnergyUJ[1]); - assertEquals(0, delta.otherTotalEnergyUJ[2]); // First good pull. Treat delta as 0. + expectedChargeUC = calculateChargeConsumedUC(90_000, VOLTAGE_0, 90_000, VOLTAGE_1); + assertEquals(expectedChargeUC, delta.otherTotalChargeUC[0]); + expectedChargeUC = calculateChargeConsumedUC(0, VOLTAGE_0, 12_000_000, VOLTAGE_1); + assertEquals(expectedChargeUC, delta.otherTotalChargeUC[1]); + assertEquals(0, delta.otherTotalChargeUC[2]); // First good pull. Treat delta as 0. - assertNotNull(delta.otherUidEnergiesUJ); - assertNullOrEmpty(delta.otherUidEnergiesUJ[0]); // No change in uid energies - assertNullOrEmpty(delta.otherUidEnergiesUJ[1]); - assertNullOrEmpty(delta.otherUidEnergiesUJ[2]); + assertNotNull(delta.otherUidChargesUC); + assertNullOrEmpty(delta.otherUidChargesUC[0]); // No change in uid energies + assertNullOrEmpty(delta.otherUidChargesUC[1]); + assertNullOrEmpty(delta.otherUidChargesUC[2]); // results2 - delta = snapshot.updateAndGetDelta(RESULTS_2); + delta = snapshot.updateAndGetDelta(RESULTS_2, VOLTAGE_2); assertNotNull(delta); - assertEquals(36 - 24, delta.displayEnergyUJ); - assertNull(delta.otherUidEnergiesUJ); - assertNull(delta.otherTotalEnergyUJ); + expectedChargeUC = calculateChargeConsumedUC(24_000, VOLTAGE_1, 36_000, VOLTAGE_2); + assertEquals(expectedChargeUC, delta.displayChargeUC); + assertNull(delta.otherUidChargesUC); + assertNull(delta.otherTotalChargeUC); // results3 - delta = snapshot.updateAndGetDelta(RESULTS_3); + delta = snapshot.updateAndGetDelta(RESULTS_3, VOLTAGE_3); assertNotNull(delta); - assertEquals(UNAVAILABLE, delta.displayEnergyUJ); + assertEquals(UNAVAILABLE, delta.displayChargeUC); + + assertNotNull(delta.otherTotalChargeUC); + + expectedChargeUC = calculateChargeConsumedUC(90_000, VOLTAGE_1, 190_000, VOLTAGE_3); + assertEquals(expectedChargeUC, delta.otherTotalChargeUC[0]); + expectedChargeUC = calculateChargeConsumedUC(12_000_000, VOLTAGE_1, 12_000_000, VOLTAGE_3); + assertEquals(expectedChargeUC, delta.otherTotalChargeUC[1]); + expectedChargeUC = calculateChargeConsumedUC(12_000, VOLTAGE_1, 13_000, VOLTAGE_3); + assertEquals(expectedChargeUC, delta.otherTotalChargeUC[2]); - assertNotNull(delta.otherTotalEnergyUJ); - assertEquals(190 - 90, delta.otherTotalEnergyUJ[0]); - assertEquals(12_000 - 12_000, delta.otherTotalEnergyUJ[1]); - assertEquals(13 - 12, delta.otherTotalEnergyUJ[2]); + assertNotNull(delta.otherUidChargesUC); - assertNotNull(delta.otherUidEnergiesUJ); - assertEquals(3, delta.otherUidEnergiesUJ[0].size()); - assertEquals(9 - 0, delta.otherUidEnergiesUJ[0].get(2)); - assertEquals(18 - 13, delta.otherUidEnergiesUJ[0].get(3)); - assertEquals(6 - 0, delta.otherUidEnergiesUJ[0].get(7)); - assertNullOrEmpty(delta.otherUidEnergiesUJ[1]); - assertNullOrEmpty(delta.otherUidEnergiesUJ[2]); + assertEquals(3, delta.otherUidChargesUC[0].size()); + expectedChargeUC = calculateChargeConsumedUC(0, VOLTAGE_1, 9_000, VOLTAGE_3); + assertEquals(expectedChargeUC, delta.otherUidChargesUC[0].get(2)); + expectedChargeUC = calculateChargeConsumedUC(13_000, VOLTAGE_1, 18_000, VOLTAGE_3); + assertEquals(expectedChargeUC, delta.otherUidChargesUC[0].get(3)); + expectedChargeUC = calculateChargeConsumedUC(0, VOLTAGE_1, 6_000, VOLTAGE_3); + assertEquals(expectedChargeUC, delta.otherUidChargesUC[0].get(7)); + assertNullOrEmpty(delta.otherUidChargesUC[1]); + assertNullOrEmpty(delta.otherUidChargesUC[2]); // results4 - delta = snapshot.updateAndGetDelta(RESULTS_4); + delta = snapshot.updateAndGetDelta(RESULTS_4, VOLTAGE_4); assertNotNull(delta); - assertEquals(43 - 36, delta.displayEnergyUJ); - - assertNotNull(delta.otherTotalEnergyUJ); - assertEquals(290 - 190, delta.otherTotalEnergyUJ[0]); - assertEquals(0, delta.otherTotalEnergyUJ[1]); // Not present (e.g. missing data) - assertEquals(165 - 13, delta.otherTotalEnergyUJ[2]); - - assertNotNull(delta.otherUidEnergiesUJ); - assertEquals(1, delta.otherUidEnergiesUJ[0].size()); - assertEquals(11 - 9, delta.otherUidEnergiesUJ[0].get(2)); - assertNullOrEmpty(delta.otherUidEnergiesUJ[1]); // Not present - assertEquals(1, delta.otherUidEnergiesUJ[2].size()); - assertEquals(8, delta.otherUidEnergiesUJ[2].get(47)); + expectedChargeUC = calculateChargeConsumedUC(36_000, VOLTAGE_2, 43_000, VOLTAGE_4); + assertEquals(expectedChargeUC, delta.displayChargeUC); + + assertNotNull(delta.otherTotalChargeUC); + expectedChargeUC = calculateChargeConsumedUC(190_000, VOLTAGE_3, 290_000, VOLTAGE_4); + assertEquals(expectedChargeUC, delta.otherTotalChargeUC[0]); + assertEquals(0, delta.otherTotalChargeUC[1]); // Not present (e.g. missing data) + expectedChargeUC = calculateChargeConsumedUC(13_000, VOLTAGE_3, 165_000, VOLTAGE_4); + assertEquals(expectedChargeUC, delta.otherTotalChargeUC[2]); + + assertNotNull(delta.otherUidChargesUC); + assertEquals(1, delta.otherUidChargesUC[0].size()); + expectedChargeUC = calculateChargeConsumedUC(9_000, VOLTAGE_3, 11_000, VOLTAGE_4); + assertEquals(expectedChargeUC, delta.otherUidChargesUC[0].get(2)); + assertNullOrEmpty(delta.otherUidChargesUC[1]); // Not present + assertEquals(1, delta.otherUidChargesUC[2].size()); + expectedChargeUC = calculateChargeConsumedUC(0, VOLTAGE_3, 8_000, VOLTAGE_4); + assertEquals(expectedChargeUC, delta.otherUidChargesUC[2].get(47)); } /** Test updateAndGetDelta() when the results have consumers absent from idToConsumerMap. */ @@ -174,19 +206,21 @@ public final class MeasuredEnergySnapshotTest { final MeasuredEnergySnapshot snapshot = new MeasuredEnergySnapshot(SOME_ID_CONSUMER_MAP); // results0 - MeasuredEnergyDeltaData delta = snapshot.updateAndGetDelta(RESULTS_0); + MeasuredEnergyDeltaData delta = snapshot.updateAndGetDelta(RESULTS_0, VOLTAGE_0); if (delta != null) { // null is fine here. If non-null, it better be uninteresting though. - assertEquals(UNAVAILABLE, delta.displayEnergyUJ); - assertNull(delta.otherTotalEnergyUJ); - assertNull(delta.otherUidEnergiesUJ); + assertEquals(UNAVAILABLE, delta.displayChargeUC); + assertNull(delta.otherTotalChargeUC); + assertNull(delta.otherUidChargesUC); } // results1 - delta = snapshot.updateAndGetDelta(RESULTS_1); + delta = snapshot.updateAndGetDelta(RESULTS_1, VOLTAGE_1); assertNotNull(delta); - assertEquals(24 - 14, delta.displayEnergyUJ); - assertNull(delta.otherTotalEnergyUJ); // Although in the results, they're not in the idMap - assertNull(delta.otherUidEnergiesUJ); + final long expectedChargeUC = + calculateChargeConsumedUC(14_000, VOLTAGE_0, 24_000, VOLTAGE_1); + assertEquals(expectedChargeUC, delta.displayChargeUC); + assertNull(delta.otherTotalChargeUC); // Although in the results, they're not in the idMap + assertNull(delta.otherUidChargesUC); } @Test @@ -234,6 +268,15 @@ public final class MeasuredEnergySnapshotTest { return ecr; } + private static long calculateChargeConsumedUC(long energyUWs0, long voltageMv0, long energyUWs1, + long voltageMv1) { + final long deltaEnergyUWs = energyUWs1 - energyUWs0; + final long avgVoltageMv = (voltageMv1 + voltageMv0 + 1) / 2; + + // Charge uC = Energy uWs * (1000 mV/V) / (voltage mV) + 0.5 (for rounding) + return (deltaEnergyUWs * 1000 + (avgVoltageMv / 2)) / avgVoltageMv; + } + private void assertNullOrEmpty(SparseLongArray a) { if (a != null) assertEquals("Array should be null or empty", 0, a.size()); } 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 6d4189eb4168..5be05d8aa55a 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.hamcrest.CoreMatchers.is; 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 @@ import java.io.IOException; @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 d039a9d6bfe1..3d0895dab7a8 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 @@ import java.util.function.Supplier; @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 @@ public class GameManagerServiceTests { * * <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 @@ public class GameManagerServiceTests { @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 @@ public class GameManagerServiceTests { mockModifyGameModeGranted(); assertEquals(GameManager.GAME_MODE_UNSUPPORTED, - gameManagerService.getGameMode(PACKAGE_NAME_0, USER_ID_1)); + gameManagerService.getGameMode(mPackageName, USER_ID_1)); } /** @@ -142,9 +148,9 @@ public class GameManagerServiceTests { 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 @@ public class GameManagerServiceTests { */ @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 @@ public class GameManagerServiceTests { */ @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 97daea3011ea..0b1c120d8a1e 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 @@ public class SnippetTest { .setPropertyName(propertyKeyString) .addSnippetMatches( SnippetMatchProto.newBuilder() - .setValuesIndex(0) .setExactMatchPosition(29) .setExactMatchBytes(3) .setWindowPosition(26) @@ -174,7 +173,6 @@ public class SnippetTest { .setPropertyName("sender.name") .addSnippetMatches( SnippetMatchProto.newBuilder() - .setValuesIndex(0) .setExactMatchPosition(0) .setExactMatchBytes(4) .setWindowPosition(0) @@ -186,7 +184,6 @@ public class SnippetTest { .setPropertyName("sender.email") .addSnippetMatches( SnippetMatchProto.newBuilder() - .setValuesIndex(0) .setExactMatchPosition(0) .setExactMatchBytes(20) .setWindowPosition(0) diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/AcquisitionClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/AcquisitionClientTest.java new file mode 100644 index 000000000000..46f96364ff9e --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/AcquisitionClientTest.java @@ -0,0 +1,118 @@ +/* + * 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.biometrics.sensors; + +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.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import android.content.Context; +import android.hardware.biometrics.BiometricConstants; +import android.os.IBinder; +import android.platform.test.annotations.Presubmit; + +import androidx.annotation.NonNull; +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@Presubmit +@SmallTest +public class AcquisitionClientTest { + + private static final int TEST_SENSOR_ID = 100; + + @Mock + private Context mContext; + @Mock + private IBinder mToken; + @Mock + private ClientMonitorCallbackConverter mClientCallback; + @Mock + private BaseClientMonitor.Callback mSchedulerCallback; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void testUserCanceled() throws Exception { + // Start an AcquisitionClient + final TestAcquisitionClient client = new TestAcquisitionClient(mContext, Object::new, + mToken, mClientCallback); + client.start(mSchedulerCallback); + assertTrue(client.mHalOperationRunning); + verify(mSchedulerCallback).onClientStarted(eq(client)); + + // Pretend that it got canceled by the user. + client.onUserCanceled(); + verify(mSchedulerCallback, never()).onClientFinished(any(), anyBoolean()); + verify(mClientCallback).onError(eq(TEST_SENSOR_ID), + anyInt(), + eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED), + eq(0) /* vendorCode */); + assertFalse(client.mHalOperationRunning); + + // Pretend that the HAL responded with ERROR_CANCELED + client.onError(BiometricConstants.BIOMETRIC_ERROR_CANCELED, 0 /* vendorCode */); + verifyNoMoreInteractions(mClientCallback); + verify(mSchedulerCallback).onClientFinished(eq(client), anyBoolean()); + } + + private static class TestAcquisitionClient extends AcquisitionClient<Object> { + boolean mHalOperationRunning; + + public TestAcquisitionClient(@NonNull Context context, + @NonNull LazyDaemon<Object> lazyDaemon, @NonNull IBinder token, + @NonNull ClientMonitorCallbackConverter callback) { + super(context, lazyDaemon, token, callback, 0 /* userId */, "Test", 0 /* cookie */, + TEST_SENSOR_ID /* sensorId */, 0 /* statsModality */, 0 /* statsAction */, + 0 /* statsClient */); + } + + @Override + public void start(@NonNull Callback callback) { + super.start(callback); + startHalOperation(); + } + + @Override + protected void stopHalOperation() { + mHalOperationRunning = false; + } + + @Override + protected void startHalOperation() { + mHalOperationRunning = true; + } + + @Override + public int getProtoEnum() { + return 0; + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java new file mode 100644 index 000000000000..f94b800afbef --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java @@ -0,0 +1,174 @@ +/* + * 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.devicepolicy; + +import static com.google.common.truth.Truth.assertThat; + +import android.app.admin.DeviceAdminInfo; +import android.content.ComponentName; +import android.content.Context; + +import androidx.test.InstrumentationRegistry; + +import com.android.internal.util.JournaledFile; + +import com.google.common.io.Files; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +@RunWith(JUnit4.class) +public class PolicyVersionUpgraderTest { + // NOTE: Only change this value if the corresponding CL also adds a test to test the upgrade + // to the new version. + private static final int LATEST_TESTED_VERSION = 1; + + private static class FakePolicyUpgraderDataProvider implements PolicyUpgraderDataProvider { + int mDeviceOwnerUserId; + boolean mIsFileBasedEncryptionEnabled; + Map<Integer, ComponentName> mUserToComponent = new HashMap<>(); + Map<ComponentName, DeviceAdminInfo> mComponentToDeviceAdminInfo; + File mDataDir; + + @Override + public boolean isUserDeviceOwner(int userId) { + return userId == mDeviceOwnerUserId; + } + + @Override + public boolean storageManagerIsFileBasedEncryptionEnabled() { + return mIsFileBasedEncryptionEnabled; + } + + private JournaledFile makeJournaledFile(int userId, String fileName) { + File parentDir = new File(mDataDir, String.format("user%d", userId)); + if (!parentDir.exists()) { + parentDir.mkdirs(); + } + + final String base = new File(parentDir, fileName).getAbsolutePath(); + return new JournaledFile(new File(base), new File(base + ".tmp")); + } + + @Override + public JournaledFile makeDevicePoliciesJournaledFile(int userId) { + return makeJournaledFile(userId, DevicePolicyManagerService.DEVICE_POLICIES_XML); + } + + @Override + public JournaledFile makePoliciesVersionJournaledFile(int userId) { + return makeJournaledFile(userId, DevicePolicyManagerService.POLICIES_VERSION_XML); + } + + @Override + public ComponentName getOwnerComponent(int userId) { + return mUserToComponent.get(userId); + } + + @Override + public Function<ComponentName, DeviceAdminInfo> getAdminInfoSupplier(int userId) { + return componentName -> mComponentToDeviceAdminInfo.get(componentName); + } + } + + private final Context mRealTestContext = InstrumentationRegistry.getTargetContext(); + private FakePolicyUpgraderDataProvider mProvider; + private PolicyVersionUpgrader mUpgrader; + private File mDataDir; + + @Before + public void setUp() { + mProvider = new FakePolicyUpgraderDataProvider(); + mUpgrader = new PolicyVersionUpgrader(mProvider); + mDataDir = new File(mRealTestContext.getCacheDir(), "test-data"); + mDataDir.getParentFile().mkdirs(); + mProvider.mDataDir = mDataDir; + } + + @Test + public void testSameVersionDoesNothing() throws IOException { + int[] users = new int[] {0}; + writeVersionToXml(DevicePolicyManagerService.DPMS_VERSION); + preparePoliciesFile(users[0]); + String oldContents = readPoliciesFile(0); + + mUpgrader.upgradePolicy(users, DevicePolicyManagerService.DPMS_VERSION); + + String newContents = readPoliciesFile(0); + assertThat(newContents).isEqualTo(oldContents); + } + + @Test + public void testUpgrade0To1RemovesPasswordMetrics() throws IOException { + int[] users = new int[] {0, 10}; + writeVersionToXml(0); + for (int userId : users) { + preparePoliciesFile(userId); + } + + String oldContents = readPoliciesFile(0); + assertThat(oldContents).contains("active-password"); + + mUpgrader.upgradePolicy(users, 1); + + assertThat(readVersionFromXml()).isEqualTo(1); + assertThat(readPoliciesFile(users[0])).doesNotContain("active-password"); + assertThat(readPoliciesFile(users[1])).doesNotContain("active-password"); + } + + @Test + public void isLatestVersionTested() { + assertThat(DevicePolicyManagerService.DPMS_VERSION).isEqualTo(LATEST_TESTED_VERSION); + } + + private void writeVersionToXml(int dpmsVersion) throws IOException { + JournaledFile versionFile = mProvider.makePoliciesVersionJournaledFile(0); + Files.asCharSink(versionFile.chooseForWrite(), Charset.defaultCharset()).write( + String.format("%d\n", dpmsVersion)); + versionFile.commit(); + } + + private int readVersionFromXml() throws IOException { + File versionFile = mProvider.makePoliciesVersionJournaledFile(0).chooseForRead(); + String versionString = Files.asCharSource(versionFile, + Charset.defaultCharset()).readFirstLine(); + return Integer.parseInt(versionString); + } + + private void preparePoliciesFile(int userId) throws IOException { + JournaledFile policiesFile = mProvider.makeDevicePoliciesJournaledFile(userId); + DpmTestUtils.writeToFile( + policiesFile.chooseForWrite(), + DpmTestUtils.readAsset(mRealTestContext, + "PolicyVersionUpgraderTest/device_policies.xml")); + policiesFile.commit(); + } + + private String readPoliciesFile(int userId) throws IOException { + File policiesFile = mProvider.makeDevicePoliciesJournaledFile(userId).chooseForRead(); + return new String(Files.asByteSource(policiesFile).read()); + } +} diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java index a97ea268b1c8..ff8fbda6c83e 100644 --- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java @@ -73,16 +73,16 @@ public final class DeviceStateManagerServiceTest { @Test public void baseStateChanged() { - assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mService.getPendingState(), Optional.empty()); - assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), DEFAULT_DEVICE_STATE.getIdentifier()); mProvider.setState(OTHER_DEVICE_STATE.getIdentifier()); - assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE); + assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE)); assertEquals(mService.getPendingState(), Optional.empty()); - assertEquals(mService.getBaseState(), OTHER_DEVICE_STATE); + assertEquals(mService.getBaseState(), Optional.of(OTHER_DEVICE_STATE)); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), OTHER_DEVICE_STATE.getIdentifier()); } @@ -92,23 +92,23 @@ public final class DeviceStateManagerServiceTest { mPolicy.blockConfigure(); mProvider.setState(OTHER_DEVICE_STATE.getIdentifier()); - assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE); - assertEquals(mService.getPendingState().get(), OTHER_DEVICE_STATE); - assertEquals(mService.getBaseState(), OTHER_DEVICE_STATE); + assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE)); + assertEquals(mService.getPendingState(), Optional.of(OTHER_DEVICE_STATE)); + assertEquals(mService.getBaseState(), Optional.of(OTHER_DEVICE_STATE)); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), OTHER_DEVICE_STATE.getIdentifier()); mProvider.setState(DEFAULT_DEVICE_STATE.getIdentifier()); - assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE); - assertEquals(mService.getPendingState().get(), OTHER_DEVICE_STATE); - assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE)); + assertEquals(mService.getPendingState(), Optional.of(OTHER_DEVICE_STATE)); + assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), OTHER_DEVICE_STATE.getIdentifier()); mPolicy.resumeConfigure(); - assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mService.getPendingState(), Optional.empty()); - assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), DEFAULT_DEVICE_STATE.getIdentifier()); } @@ -119,9 +119,9 @@ public final class DeviceStateManagerServiceTest { mProvider.setState(UNSUPPORTED_DEVICE_STATE.getIdentifier()); }); - assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mService.getPendingState(), Optional.empty()); - assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), DEFAULT_DEVICE_STATE.getIdentifier()); } @@ -132,9 +132,9 @@ public final class DeviceStateManagerServiceTest { mProvider.setState(INVALID_DEVICE_STATE); }); - assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mService.getPendingState(), Optional.empty()); - assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), DEFAULT_DEVICE_STATE.getIdentifier()); } @@ -144,17 +144,17 @@ public final class DeviceStateManagerServiceTest { TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback(); mService.getBinderService().registerCallback(callback); - assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mService.getPendingState(), Optional.empty()); - assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); mProvider.notifySupportedDeviceStates(new DeviceState[]{ DEFAULT_DEVICE_STATE }); // The current committed and requests states do not change because the current state remains // supported. - assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mService.getPendingState(), Optional.empty()); - assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertArrayEquals(callback.getLastNotifiedInfo().supportedStates, new int[] { DEFAULT_DEVICE_STATE.getIdentifier() }); @@ -165,18 +165,21 @@ public final class DeviceStateManagerServiceTest { TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback(); mService.getBinderService().registerCallback(callback); - assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE); + // An initial callback will be triggered on registration, so we clear it here. + callback.clearLastNotifiedInfo(); + + assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mService.getPendingState(), Optional.empty()); - assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); mProvider.notifySupportedDeviceStates(new DeviceState[]{ DEFAULT_DEVICE_STATE, OTHER_DEVICE_STATE }); // The current committed and requests states do not change because the current state remains // supported. - assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mService.getPendingState(), Optional.empty()); - assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); // The callback wasn't notified about a change in supported states as the states have not // changed. @@ -230,6 +233,17 @@ public final class DeviceStateManagerServiceTest { } @Test + public void registerCallback_emitsInitialValue() throws RemoteException { + TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback(); + mService.getBinderService().registerCallback(callback); + assertNotNull(callback.getLastNotifiedInfo()); + assertEquals(callback.getLastNotifiedInfo().baseState, + DEFAULT_DEVICE_STATE.getIdentifier()); + assertEquals(callback.getLastNotifiedInfo().currentState, + DEFAULT_DEVICE_STATE.getIdentifier()); + } + + @Test public void requestState() throws RemoteException { TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback(); mService.getBinderService().registerCallback(callback); @@ -244,8 +258,8 @@ public final class DeviceStateManagerServiceTest { assertEquals(callback.getLastNotifiedStatus(token), TestDeviceStateManagerCallback.STATUS_ACTIVE); // Committed state changes as there is a requested override. - assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE); - assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE)); + assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), OTHER_DEVICE_STATE.getIdentifier()); @@ -261,8 +275,8 @@ public final class DeviceStateManagerServiceTest { assertEquals(callback.getLastNotifiedStatus(token), TestDeviceStateManagerCallback.STATUS_CANCELED); // Committed state is set back to the requested state once the override is cleared. - assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE); - assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE)); + assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertFalse(mService.getOverrideState().isPresent()); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), DEFAULT_DEVICE_STATE.getIdentifier()); @@ -290,9 +304,9 @@ public final class DeviceStateManagerServiceTest { mService.getBinderService().requestState(firstRequestToken, OTHER_DEVICE_STATE.getIdentifier(), 0 /* flags */); - assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE); - assertEquals(mService.getPendingState().get(), OTHER_DEVICE_STATE); - assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE)); + assertEquals(mService.getPendingState(), Optional.of(OTHER_DEVICE_STATE)); + assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), OTHER_DEVICE_STATE.getIdentifier()); @@ -309,17 +323,17 @@ public final class DeviceStateManagerServiceTest { assertEquals(callback.getLastNotifiedStatus(secondRequestToken), TestDeviceStateManagerCallback.STATUS_UNKNOWN); - assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE); - assertEquals(mService.getPendingState().get(), DEFAULT_DEVICE_STATE); - assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE)); + assertEquals(mService.getPendingState(), Optional.of(DEFAULT_DEVICE_STATE)); + assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), DEFAULT_DEVICE_STATE.getIdentifier()); mPolicy.resumeConfigure(); - assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mService.getPendingState(), Optional.empty()); - assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), DEFAULT_DEVICE_STATE.getIdentifier()); @@ -331,9 +345,9 @@ public final class DeviceStateManagerServiceTest { assertEquals(callback.getLastNotifiedStatus(secondRequestToken), TestDeviceStateManagerCallback.STATUS_CANCELED); - assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE); + assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE)); assertEquals(mService.getPendingState(), Optional.empty()); - assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), OTHER_DEVICE_STATE.getIdentifier()); } @@ -370,8 +384,8 @@ public final class DeviceStateManagerServiceTest { TestDeviceStateManagerCallback.STATUS_ACTIVE); // Committed state changes as there is a requested override. - assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE); - assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE)); + assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), OTHER_DEVICE_STATE.getIdentifier()); @@ -382,8 +396,8 @@ public final class DeviceStateManagerServiceTest { assertEquals(callback.getLastNotifiedStatus(token), TestDeviceStateManagerCallback.STATUS_CANCELED); // Committed state is set back to the requested state once the override is cleared. - assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE); - assertEquals(mService.getBaseState(), OTHER_DEVICE_STATE); + assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE)); + assertEquals(mService.getBaseState(), Optional.of(OTHER_DEVICE_STATE)); assertFalse(mService.getOverrideState().isPresent()); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), OTHER_DEVICE_STATE.getIdentifier()); @@ -404,8 +418,8 @@ public final class DeviceStateManagerServiceTest { assertEquals(callback.getLastNotifiedStatus(token), TestDeviceStateManagerCallback.STATUS_ACTIVE); // Committed state changes as there is a requested override. - assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE); - assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getCommittedState(), Optional.of(OTHER_DEVICE_STATE)); + assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), OTHER_DEVICE_STATE.getIdentifier()); @@ -417,8 +431,8 @@ public final class DeviceStateManagerServiceTest { TestDeviceStateManagerCallback.STATUS_CANCELED); // Committed state is set back to the requested state as the override state is no longer // supported. - assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE); - assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE); + assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE)); + assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE)); assertFalse(mService.getOverrideState().isPresent()); assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), DEFAULT_DEVICE_STATE.getIdentifier()); @@ -551,7 +565,6 @@ public final class DeviceStateManagerServiceTest { @Nullable private DeviceStateInfo mLastNotifiedInfo; - private boolean mNotifiedOfChangeInSupportedStates; private final HashMap<IBinder, Integer> mLastNotifiedStatus = new HashMap<>(); @Override @@ -579,6 +592,10 @@ public final class DeviceStateManagerServiceTest { return mLastNotifiedInfo; } + void clearLastNotifiedInfo() { + mLastNotifiedInfo = null; + } + int getLastNotifiedStatus(IBinder requestToken) { return mLastNotifiedStatus.getOrDefault(requestToken, STATUS_UNKNOWN); } 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 deaeb46c4074..8b35af80e47f 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 @@ public class JobStoreTest { 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 7d9ab3772733..dd9ae6592f5c 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 @@ package com.android.server.job; 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.assertThat; 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 @@ import java.util.Random; @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 @@ public class WorkCountTrackerTest { @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 @@ public class WorkCountTrackerTest { } 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 @@ public class WorkCountTrackerTest { 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 @@ public class WorkCountTrackerTest { 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 @@ public class WorkCountTrackerTest { 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 @@ public class WorkCountTrackerTest { 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 @@ public class WorkCountTrackerTest { 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 @@ public class WorkCountTrackerTest { 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 @@ public class WorkCountTrackerTest { 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 @@ public class WorkCountTrackerTest { 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 @@ public class WorkCountTrackerTest { 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 @@ public class WorkCountTrackerTest { 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 @@ public class WorkCountTrackerTest { 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 @@ public class WorkCountTrackerTest { 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 @@ public class WorkCountTrackerTest { 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 @@ public class WorkCountTrackerTest { 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 @@ public class WorkCountTrackerTest { 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 @@ public class WorkCountTrackerTest { /* 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 @@ public class WorkCountTrackerTest { /* 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 cc18317d0529..a5fedef23e00 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 @@ package com.android.server.job; 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 @@ public class WorkTypeConfigTest { 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 @@ public class WorkTypeConfigTest { 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 @@ public class WorkTypeConfigTest { .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 a896f1b0d60f..b51f4df43259 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.ContextWrapper; 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.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import java.io.File; +import java.io.IOException; import java.util.ArrayList; import javax.crypto.SecretKey; @@ -181,6 +183,18 @@ public class RebootEscrowManagerTests { } @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 @@ public class RebootEscrowManagerTests { } @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 2d6605ae222f..c0a38b874914 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 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { 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 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { 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 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { 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 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { } @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 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { 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 13c3919cefc5..fb01ff6e16c6 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.PackageManager; 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 @@ public class NetworkPolicyManagerServiceTest { 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 @@ public class NetworkPolicyManagerServiceTest { 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 @@ public class NetworkPolicyManagerServiceTest { 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 @@ public class NetworkPolicyManagerServiceTest { 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 @@ public class NetworkPolicyManagerServiceTest { @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 @@ public class NetworkPolicyManagerServiceTest { // 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 @@ public class NetworkPolicyManagerServiceTest { // 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 @@ public class NetworkPolicyManagerServiceTest { @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 @@ public class NetworkPolicyManagerServiceTest { 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 @@ public class NetworkPolicyManagerServiceTest { } 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 @@ public class NetworkPolicyManagerServiceTest { @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 @@ public class NetworkPolicyManagerServiceTest { reset(mTelephonyManager, mNetworkManager, mNotifManager); expectMobileDefaults(); - expectNetworkState(true /* roaming */); + expectNetworkStateSnapshot(true /* roaming */); mService.updateNetworks(); @@ -1749,7 +1749,7 @@ public class NetworkPolicyManagerServiceTest { // 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 @@ public class NetworkPolicyManagerServiceTest { 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 @@ public class NetworkPolicyManagerServiceTest { 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 @@ public class NetworkPolicyManagerServiceTest { 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/policy/DeviceStateProviderImplTest.java b/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java index 4f36c8ae99ae..d13687ce3254 100644 --- a/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java +++ b/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java @@ -150,8 +150,8 @@ public final class DeviceStateProviderImplTest { provider.setListener(listener); verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture()); - final DeviceState[] expectedStates = new DeviceState[]{ new DeviceState(1, null), - new DeviceState(2, null) }; + final DeviceState[] expectedStates = new DeviceState[]{ new DeviceState(1, ""), + new DeviceState(2, "") }; assertArrayEquals(expectedStates, mDeviceStateArrayCaptor.getValue()); verify(listener).onStateChanged(mIntegerCaptor.capture()); @@ -187,16 +187,22 @@ public final class DeviceStateProviderImplTest { provider.setListener(listener); verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture()); - final DeviceState[] expectedStates = new DeviceState[]{ new DeviceState(1, null), + final DeviceState[] expectedStates = new DeviceState[]{ new DeviceState(1, ""), new DeviceState(2, "CLOSED") }; assertArrayEquals(expectedStates, mDeviceStateArrayCaptor.getValue()); + // onStateChanged() should not be called because the provider has not yet been notified of + // the initial lid switch state. + verify(listener, never()).onStateChanged(mIntegerCaptor.capture()); + + provider.notifyLidSwitchChanged(0, false /* lidOpen */); + verify(listener).onStateChanged(mIntegerCaptor.capture()); assertEquals(2, mIntegerCaptor.getValue().intValue()); Mockito.clearInvocations(listener); - provider.notifyLidSwitchChanged(0, true /* lidOpen */); + provider.notifyLidSwitchChanged(1, true /* lidOpen */); verify(listener, never()).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture()); verify(listener).onStateChanged(mIntegerCaptor.capture()); assertEquals(1, mIntegerCaptor.getValue().intValue()); @@ -260,9 +266,9 @@ public final class DeviceStateProviderImplTest { assertArrayEquals( new DeviceState[]{ new DeviceState(1, "CLOSED"), new DeviceState(2, "HALF_OPENED"), new DeviceState(3, "OPENED") }, mDeviceStateArrayCaptor.getValue()); - - verify(listener).onStateChanged(mIntegerCaptor.capture()); - assertEquals(1, mIntegerCaptor.getValue().intValue()); + // onStateChanged() should not be called because the provider has not yet been notified of + // the initial sensor state. + verify(listener, never()).onStateChanged(mIntegerCaptor.capture()); Mockito.clearInvocations(listener); 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 ea27331ac4ca..6e5fbd0b6ed0 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 @@ public class PowerManagerServiceTest { 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 @@ public class PowerManagerServiceTest { 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 4634e12f1530..2a3c2c46ce4e 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 @@ final class FakeVibratorControllerProvider { 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 815aa8ee66ae..bad3e4c2ed92 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 @@ package com.android.server.vibrator; 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 @@ public class VibratorControllerTest { 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 @@ public class VibratorControllerTest { @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/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index cebdbbef2329..1905e2ff8461 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -6207,7 +6207,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { reset(mListeners); // Test: update suppression to true - mService.mNotificationDelegate.onBubbleNotificationSuppressionChanged(nr.getKey(), true); + mService.mNotificationDelegate.onBubbleNotificationSuppressionChanged(nr.getKey(), true, + false); waitForIdle(); // Check @@ -6218,7 +6219,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { reset(mListeners); // Test: update suppression to false - mService.mNotificationDelegate.onBubbleNotificationSuppressionChanged(nr.getKey(), false); + mService.mNotificationDelegate.onBubbleNotificationSuppressionChanged(nr.getKey(), false, + false); waitForIdle(); // Check 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 000000000000..3025a95be98c --- /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 137cf6523caf..f5d831bbe73e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -342,6 +342,25 @@ public class DisplayContentTests extends WindowTestsBase { verify(imeTarget.getRootDisplayArea()).placeImeContainer(imeContainer); } + @Test + public void testUpdateImeParent_forceUpdateRelativeLayer() { + final DisplayArea.Tokens imeContainer = mDisplayContent.getImeContainer(); + final ActivityRecord activity = createActivityRecord(mDisplayContent); + + final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, activity, + "startingWin"); + startingWin.setHasSurface(true); + assertTrue(startingWin.canBeImeTarget()); + final SurfaceControl imeSurfaceParent = mock(SurfaceControl.class); + doReturn(imeSurfaceParent).when(mDisplayContent).computeImeParent(); + spyOn(imeContainer); + + mDisplayContent.updateImeParent(); + + // Force reassign the relative layer when the IME surface parent is changed. + verify(imeContainer).assignRelativeLayer(any(), eq(imeSurfaceParent), anyInt(), eq(true)); + } + /** * This tests stack movement between displays and proper stack's, task's and app token's display * container references updates. @@ -518,6 +537,7 @@ public class DisplayContentTests extends WindowTestsBase { 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/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java index 074ef3667857..47cf53b621d3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java @@ -323,16 +323,4 @@ public class DisplayPolicyTests extends WindowTestsBase { assertFalse(navBarSource.getFrame().isEmpty()); assertTrue(imeSource.getFrame().contains(navBarSource.getFrame())); } - - @UseTestDisplay - @Test - public void testDisplayPolicyNotCrash() { - final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy(); - - // Verify if modules initialized after DisplayContent ctr throws NPE. - displayPolicy.onDisplayInfoChanged(mDisplayInfo); - displayPolicy.onConfigurationChanged(); - displayPolicy.onOverlayChangedLw(); - displayPolicy.release(); - } } 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 b73c66407874..2f1d7eb404ad 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 @@ public class SizeCompatTests extends WindowTestsBase { 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 @@ public class SizeCompatTests extends WindowTestsBase { } @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/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java index 5239462a1ec0..ed5729400a39 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java @@ -195,7 +195,7 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase { } @Test - public void testUsesTasksDisplayAreaIdPriorToSourceIfSet() { + public void testUsesSourcesDisplayAreaIdPriorToTaskIfSet() { final TestDisplayContent freeformDisplay = createNewDisplayContent( WINDOWING_MODE_FREEFORM); final TestDisplayContent fullscreenDisplay = createNewDisplayContent( @@ -211,7 +211,7 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase { .setSource(source) .calculate()); - assertEquals(fullscreenDisplay.getDefaultTaskDisplayArea(), + assertEquals(freeformDisplay.getDefaultTaskDisplayArea(), mResult.mPreferredTaskDisplayArea); } 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 c3eb5c49cea0..ecb8b607a106 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 @@ public class TaskTests extends WindowTestsBase { 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 401ace03c554..79ef8680dfec 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_OPEN; 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 @@ public class TransitionTests extends WindowTestsBase { 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 @@ public class TransitionTests extends WindowTestsBase { 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 d1d0ac68017a..8b4e94724e6c 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.FLAG_SHOW_WALLPAPER; 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.Gravity; 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 @@ public class WallpaperControllerTests extends WindowTestsBase { 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 @@ public class WallpaperControllerTests extends WindowTestsBase { 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/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java index bbb885eb0dd0..b88173d5c1f0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java @@ -54,6 +54,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.clearInvocations; import android.content.pm.ActivityInfo; import android.content.res.Configuration; @@ -1029,6 +1030,30 @@ public class WindowContainerTests extends WindowTestsBase { verify(win).clearFrozenInsetsState(); } + @Test + public void testAssignRelativeLayer() { + final WindowContainer container = new WindowContainer(mWm); + container.mSurfaceControl = mock(SurfaceControl.class); + final SurfaceAnimator surfaceAnimator = container.mSurfaceAnimator; + final SurfaceControl relativeParent = mock(SurfaceControl.class); + final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class); + spyOn(container); + spyOn(surfaceAnimator); + + // Trigger for first relative layer call. + container.assignRelativeLayer(t, relativeParent, 1 /* layer */); + verify(surfaceAnimator).setRelativeLayer(t, relativeParent, 1 /* layer */); + + // Not trigger for the same relative layer call. + clearInvocations(surfaceAnimator); + container.assignRelativeLayer(t, relativeParent, 1 /* layer */); + verify(surfaceAnimator, never()).setRelativeLayer(t, relativeParent, 1 /* layer */); + + // Trigger for the same relative layer call if forceUpdate=true + container.assignRelativeLayer(t, relativeParent, 1 /* layer */, true /* forceUpdate */); + verify(surfaceAnimator).setRelativeLayer(t, relativeParent, 1 /* layer */); + } + /* Used so we can gain access to some protected members of the {@link WindowContainer} class */ private static class TestWindowContainer extends WindowContainer<TestWindowContainer> { private final int mLayer; 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 ebc5c4ff280a..8d50a77447da 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 @@ class WindowTestsBase extends SystemServiceTestsBase { 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 @@ class WindowTestsBase extends SystemServiceTestsBase { 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); @@ -538,8 +546,9 @@ class WindowTestsBase extends SystemServiceTestsBase { /** Creates a {@link DisplayContent} and adds it to the system. */ private DisplayContent createNewDisplay(DisplayInfo info, @DisplayImePolicy int imePolicy) { - final DisplayContent dc = + final DisplayContent display = new TestDisplayContent.Builder(mAtm, info).build(); + final DisplayContent dc = display.mDisplayContent; // this display can show IME. dc.mWmService.mDisplayWindowSettings.setDisplayImePolicy(dc, imePolicy); return dc; diff --git a/services/translation/java/com/android/server/translation/TEST_MAPPING b/services/translation/java/com/android/server/translation/TEST_MAPPING new file mode 100644 index 000000000000..4090b4ab2c75 --- /dev/null +++ b/services/translation/java/com/android/server/translation/TEST_MAPPING @@ -0,0 +1,12 @@ +{ + "presubmit": [ + { + "name": "CtsTranslationTestCases", + "options": [ + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + } + ] +} diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 9e419d4c3f3b..0510b9cb54e1 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -2212,6 +2212,7 @@ public class UsageStatsService extends SystemService implements @Override public void reportLocusUpdate(@NonNull ComponentName activity, @UserIdInt int userId, @Nullable LocusId locusId, @NonNull IBinder appToken) { + if (locusId == null) return; Event event = new Event(LOCUS_ID_SET, SystemClock.elapsedRealtime()); event.mLocusId = locusId.getId(); event.mPackage = activity.getPackageName(); diff --git a/telephony/common/com/android/internal/telephony/SipMessageParsingUtils.java b/telephony/common/com/android/internal/telephony/SipMessageParsingUtils.java index c7e7cd5ec64e..179248dd2cf9 100644 --- a/telephony/common/com/android/internal/telephony/SipMessageParsingUtils.java +++ b/telephony/common/com/android/internal/telephony/SipMessageParsingUtils.java @@ -65,6 +65,11 @@ public class SipMessageParsingUtils { // 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 @@ public class SipMessageParsingUtils { 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/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java index e8a51a99c6ba..15147da925b8 100644 --- a/telephony/java/android/telephony/CellIdentity.java +++ b/telephony/java/android/telephony/CellIdentity.java @@ -37,7 +37,7 @@ import java.util.UUID; public abstract class CellIdentity implements Parcelable { /** @hide */ - public static final int INVALID_CHANNEL_NUMBER = -1; + public static final int INVALID_CHANNEL_NUMBER = Integer.MAX_VALUE; /** * parameters for validation diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java index fadf0e1b84d9..a012498e157d 100644 --- a/telephony/java/android/telephony/PhysicalChannelConfig.java +++ b/telephony/java/android/telephony/PhysicalChannelConfig.java @@ -50,7 +50,7 @@ public final class PhysicalChannelConfig implements Parcelable { public static final int CONNECTION_UNKNOWN = -1; /** Channel number is unknown. */ - public static final int CHANNEL_NUMBER_UNKNOWN = -1; + public static final int CHANNEL_NUMBER_UNKNOWN = Integer.MAX_VALUE; /** Physical Cell Id is unknown. */ public static final int PHYSICAL_CELL_ID_UNKNOWN = -1; diff --git a/telephony/java/android/telephony/TelephonyDisplayInfo.java b/telephony/java/android/telephony/TelephonyDisplayInfo.java index 5b5570b27a9b..2f89bfb60d3d 100644 --- a/telephony/java/android/telephony/TelephonyDisplayInfo.java +++ b/telephony/java/android/telephony/TelephonyDisplayInfo.java @@ -30,8 +30,8 @@ import java.util.Objects; * 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 b46440d7d557..c48bd211fac2 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -5949,25 +5949,20 @@ public class TelephonyManager { * @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 @@ public class TelephonyManager { } /** - * 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 0ab679f79b29..85cd81bb4eb5 100644 --- a/telephony/java/android/telephony/ims/ProvisioningManager.java +++ b/telephony/java/android/telephony/ims/ProvisioningManager.java @@ -869,8 +869,12 @@ public class ProvisioningManager { * 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) @@ -1019,7 +1023,8 @@ public class ProvisioningManager { * server) or other operator defined triggers. If RCS provisioning is already * completed at the time of callback registration, then this method shall be * invoked with the current configuration - * @param configXml The RCS configurationXML received OTA. + * @param configXml The RCS configuration XML received by OTA. It is defined + * by GSMA RCC.07. */ public void onConfigurationChanged(@NonNull byte[] configXml) {} @@ -1386,7 +1391,9 @@ public class ProvisioningManager { * provisioning is done using autoconfiguration, then these parameters shall be * sent in the HTTP get request to fetch the RCS provisioning. RCS client * configuration must be provided by the application before registering for the - * provisioning status events {@link #registerRcsProvisioningChangedCallback} + * provisioning status events {@link #registerRcsProvisioningCallback()} + * When the IMS/RCS service receives the RCS client configuration, it will detect + * the change in the configuration, and trigger the auto-configuration as needed. * @param rcc RCS client configuration {@link RcsClientConfiguration} */ @RequiresPermission(Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) @@ -1453,7 +1460,7 @@ public class ProvisioningManager { * * @param executor The {@link Executor} to call the callback methods on * @param callback The rcs provisioning callback to be registered. - * @see #unregisterRcsProvisioningChangedCallback(RcsProvisioningCallback) + * @see #unregisterRcsProvisioningCallback(RcsProvisioningCallback) * @see SubscriptionManager.OnSubscriptionsChangedListener * @throws IllegalArgumentException if the subscription associated with this * callback is not active (SIM is not inserted, ESIM inactive) or the @@ -1469,12 +1476,12 @@ public class ProvisioningManager { */ @RequiresPermission(anyOf = {Manifest.permission.READ_PRIVILEGED_PHONE_STATE, Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) - public void registerRcsProvisioningChangedCallback( + public void registerRcsProvisioningCallback( @NonNull @CallbackExecutor Executor executor, @NonNull RcsProvisioningCallback callback) throws ImsException { callback.setExecutor(executor); try { - getITelephony().registerRcsProvisioningChangedCallback(mSubId, callback.getBinder()); + getITelephony().registerRcsProvisioningCallback(mSubId, callback.getBinder()); } catch (ServiceSpecificException e) { throw new ImsException(e.getMessage(), e.errorCode); } catch (RemoteException | IllegalStateException e) { @@ -1500,16 +1507,16 @@ public class ProvisioningManager { * * @param callback The existing {@link RcsProvisioningCallback} to be * removed. - * @see #registerRcsProvisioningChangedCallback - * @throws IllegalArgumentException if the subscription associated with this callback is - * invalid. + * @see #registerRcsProvisioningCallback(Executor, RcsProvisioningCallback) + * @throws IllegalArgumentException if the subscription associated with + * this callback is invalid. */ @RequiresPermission(anyOf = {Manifest.permission.READ_PRIVILEGED_PHONE_STATE, Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) - public void unregisterRcsProvisioningChangedCallback( + public void unregisterRcsProvisioningCallback( @NonNull RcsProvisioningCallback callback) { try { - getITelephony().unregisterRcsProvisioningChangedCallback( + getITelephony().unregisterRcsProvisioningCallback( mSubId, callback.getBinder()); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); @@ -1519,6 +1526,14 @@ public class ProvisioningManager { /** * Reconfiguration triggered by the RCS application. Most likely cause * is the 403 forbidden to a HTTP request. + * + * <p>When this api is called, the RCS configuration for the associated + * subscription will be removed, and the application which has registered + * {@link RcsProvisioningCallback} may expect to receive + * {@link RcsProvisioningCallback#onConfigurationReset}, then + * {@link RcsProvisioningCallback#onConfigurationChanged} when the new + * RCS configuration is received and notified by + * {@link #notifyRcsAutoConfigurationReceived} */ @RequiresPermission(Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void triggerRcsReconfiguration() { diff --git a/telephony/java/android/telephony/ims/SipMessage.java b/telephony/java/android/telephony/ims/SipMessage.java index 9cfa640fce18..ad6d73c39962 100644 --- a/telephony/java/android/telephony/ims/SipMessage.java +++ b/telephony/java/android/telephony/ims/SipMessage.java @@ -19,6 +19,7 @@ package android.telephony.ims; 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 @@ public final class SipMessage implements Parcelable { 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 @@ public final class SipMessage implements Parcelable { mStartLine = startLine; mHeaderSection = headerSection; mContent = content; + + mViaBranchParam = SipMessageParsingUtils.getTransactionId(mHeaderSection); + mCallIdParam = SipMessageParsingUtils.getCallId(mHeaderSection); } /** @@ -73,6 +79,8 @@ public final class SipMessage implements Parcelable { mHeaderSection = source.readString(); mContent = new byte[source.readInt()]; source.readByteArray(mContent); + mViaBranchParam = source.readString(); + mCallIdParam = source.readString(); } /** @@ -97,6 +105,25 @@ public final class SipMessage implements Parcelable { 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 @@ public final class SipMessage implements Parcelable { 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 9d919015087d..739946be2e5b 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.telephony.ims.stub.SipDelegate; 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 @@ public class SipDelegateAidlWrapper implements DelegateStateCallback, DelegateMe } 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 c877aca8ba96..3cd27264295c 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.text.TextUtils; 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 @@ public class SipDelegateConnectionAidlWrapper implements SipDelegateConnection, } 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 e87f3d9aec76..40b86966d0e8 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -1200,15 +1200,6 @@ interface ITelephony { 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 @@ -2311,13 +2302,12 @@ interface ITelephony { /** * Register RCS provisioning callback. */ - void registerRcsProvisioningChangedCallback(int subId, - IRcsConfigCallback callback); + void registerRcsProvisioningCallback(int subId, IRcsConfigCallback callback); /** * Unregister RCS provisioning callback. */ - void unregisterRcsProvisioningChangedCallback(int subId, IRcsConfigCallback callback); + void unregisterRcsProvisioningCallback(int subId, IRcsConfigCallback callback); /** * trigger RCS reconfiguration. diff --git a/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java index 01c1c70f3f2a..cf501aed1dd5 100644 --- a/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java +++ b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java @@ -19,23 +19,23 @@ package com.google.android.test.dpi; import android.app.Activity; import android.app.ActivityThread; import android.app.Application; -import android.os.Bundle; -import android.graphics.BitmapFactory; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.widget.LinearLayout; -import android.widget.TextView; -import android.widget.ScrollView; -import android.view.LayoutInflater; -import android.view.View; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.CompatibilityInfo; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Bundle; import android.util.DisplayMetrics; import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.ScrollView; +import android.widget.TextView; public class DpiTestActivity extends Activity { public DpiTestActivity() { @@ -64,7 +64,7 @@ public class DpiTestActivity extends Activity { | ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES; app.getResources().setCompatibilityInfo(new CompatibilityInfo(ai, getResources().getConfiguration().screenLayout, - getResources().getConfiguration().smallestScreenWidthDp, false)); + getResources().getConfiguration().smallestScreenWidthDp, false, 1f)); } } catch (PackageManager.NameNotFoundException e) { throw new RuntimeException("ouch", e); diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml index 62ccb1a0b9db..6bf44920ee26 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 000000000000..df5f297da729 --- /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 000000000000..f0e6299f09e9 --- /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 000000000000..9bd933afa07d --- /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 000000000000..2e985fbba269 --- /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 c19e5cc34611..c01d32bf4cd2 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 @@ class ViewFrameInfoTest { @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 @@ class ViewFrameInfoTest { @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 @@ class ViewFrameInfoTest { 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 @@ class ViewFrameInfoTest { 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 5381009fdf2b..96bbf82cfba7 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.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; 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.List; 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 @@ public class PackageWatchdogTest { 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 class PackageWatchdogTest { 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 @@ public class PackageWatchdogTest { 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 4cdf6a2a4b36..15d3398d43c0 100644 --- a/tests/net/common/java/android/net/CaptivePortalTest.java +++ b/tests/net/common/java/android/net/CaptivePortalTest.java @@ -25,6 +25,7 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter; import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; import org.junit.Rule; @@ -53,6 +54,12 @@ public class CaptivePortalTest { public void appRequest(final int request) throws RemoteException { mCode = request; } + + // This is only @Override on R- + public void logEvent(int eventId, String packageName) throws RemoteException { + mCode = eventId; + mPackageName = packageName; + } } private interface TestFunctor { @@ -91,14 +98,24 @@ public class CaptivePortalTest { assertEquals(result.mCode, CaptivePortal.APP_REQUEST_REEVALUATION_REQUIRED); } - /** - * Test testLogEvent is expected to do nothing but shouldn't crash, because the API logEvent - * has been deprecated. - */ + @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( 0, TEST_PACKAGE_NAME)); } + + @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/java/android/net/util/MultinetworkPolicyTrackerTest.kt b/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt index 9b0cfa9db30f..c1315f64c56b 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.content.res.Resources 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 @@ class MultinetworkPolicyTrackerTest { 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 3bc15a386183..cc1ac61c2ab9 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.await; 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; @@ -203,6 +204,7 @@ import android.net.NetworkRequest; import android.net.NetworkSpecifier; import android.net.NetworkStack; import android.net.NetworkStackClient; +import android.net.NetworkStateSnapshot; import android.net.NetworkTestResultParcelable; import android.net.OemNetworkPreferences; import android.net.ProxyInfo; @@ -415,6 +417,8 @@ public class ConnectivityServiceTest { 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; @@ -1081,9 +1085,11 @@ public class ConnectivityServiceTest { } } - 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 class ConnectivityServiceTest { 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 @@ public class ConnectivityServiceTest { } - private void processBroadcastForVpn(Intent intent) { + private void processBroadcast(Intent intent) { mServiceContext.sendBroadcast(intent); HandlerUtils.waitForIdle(mVMSHandlerThread, TIMEOUT_MS); waitForIdle(); @@ -1419,6 +1425,7 @@ public class ConnectivityServiceTest { 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 @@ public class ConnectivityServiceTest { 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. @@ -1555,6 +1564,7 @@ public class ConnectivityServiceTest { @After public void tearDown() throws Exception { + unregisterDefaultNetworkCallbacks(); setAlwaysOnNetworks(false); if (mCellNetworkAgent != null) { mCellNetworkAgent.disconnect(); @@ -1660,6 +1670,7 @@ public class ConnectivityServiceTest { assertNull(mCm.getActiveNetworkForUid(Process.myUid())); // Test getAllNetworks() assertEmpty(mCm.getAllNetworks()); + assertEmpty(mCm.getAllNetworkStateSnapshot()); } /** @@ -6384,7 +6395,7 @@ public class ConnectivityServiceTest { 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]); @@ -6856,7 +6867,7 @@ public class ConnectivityServiceTest { 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. @@ -6877,7 +6888,7 @@ public class ConnectivityServiceTest { 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. @@ -6902,7 +6913,7 @@ public class ConnectivityServiceTest { 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. @@ -6960,7 +6971,7 @@ public class ConnectivityServiceTest { 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)); @@ -6971,7 +6982,7 @@ public class ConnectivityServiceTest { 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)); @@ -7126,7 +7137,7 @@ public class ConnectivityServiceTest { 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(); @@ -7565,7 +7576,7 @@ public class ConnectivityServiceTest { 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()); @@ -7797,7 +7808,8 @@ public class ConnectivityServiceTest { mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); mCellNetworkAgent.connect(true); waitForIdle(); - verify(mBatteryStatsService).noteNetworkInterfaceForTransports(cellLp.getInterfaceName(), + verify(mDeps).reportNetworkInterfaceForTransports(mServiceContext, + cellLp.getInterfaceName(), new int[] { TRANSPORT_CELLULAR }); reset(mBatteryStatsService); @@ -7806,7 +7818,8 @@ public class ConnectivityServiceTest { mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp); mWiFiNetworkAgent.connect(true); waitForIdle(); - verify(mBatteryStatsService).noteNetworkInterfaceForTransports(wifiLp.getInterfaceName(), + verify(mDeps).reportNetworkInterfaceForTransports(mServiceContext, + wifiLp.getInterfaceName(), new int[] { TRANSPORT_WIFI }); reset(mBatteryStatsService); @@ -7817,7 +7830,8 @@ public class ConnectivityServiceTest { mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); mCellNetworkAgent.connect(true); waitForIdle(); - verify(mBatteryStatsService).noteNetworkInterfaceForTransports(cellLp.getInterfaceName(), + verify(mDeps).reportNetworkInterfaceForTransports(mServiceContext, + cellLp.getInterfaceName(), new int[] { TRANSPORT_CELLULAR }); mCellNetworkAgent.disconnect(); } @@ -7901,7 +7915,8 @@ public class ConnectivityServiceTest { assertRoutesAdded(cellNetId, ipv6Subnet, defaultRoute); verify(mMockDnsResolver, times(1)).createNetworkCache(eq(cellNetId)); verify(mMockNetd, times(1)).networkAddInterface(cellNetId, MOBILE_IFNAME); - verify(mBatteryStatsService).noteNetworkInterfaceForTransports(cellLp.getInterfaceName(), + verify(mDeps).reportNetworkInterfaceForTransports(mServiceContext, + cellLp.getInterfaceName(), new int[] { TRANSPORT_CELLULAR }); networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); @@ -7922,8 +7937,8 @@ public class ConnectivityServiceTest { // Make sure BatteryStats was not told about any v4- interfaces, as none should have // come online yet. waitForIdle(); - verify(mBatteryStatsService, never()).noteNetworkInterfaceForTransports(startsWith("v4-"), - any()); + verify(mDeps, never()) + .reportNetworkInterfaceForTransports(eq(mServiceContext), startsWith("v4-"), any()); verifyNoMoreInteractions(mMockNetd); verifyNoMoreInteractions(mMockDnsResolver); @@ -7975,8 +7990,9 @@ public class ConnectivityServiceTest { assertTrue(ArrayUtils.contains(resolvrParams.servers, "8.8.8.8")); for (final LinkProperties stackedLp : stackedLpsAfterChange) { - verify(mBatteryStatsService).noteNetworkInterfaceForTransports( - stackedLp.getInterfaceName(), new int[] { TRANSPORT_CELLULAR }); + verify(mDeps).reportNetworkInterfaceForTransports( + mServiceContext, stackedLp.getInterfaceName(), + new int[] { TRANSPORT_CELLULAR }); } reset(mMockNetd); when(mMockNetd.interfaceGetCfg(CLAT_PREFIX + MOBILE_IFNAME)) @@ -9284,7 +9300,7 @@ public class ConnectivityServiceTest { 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) @@ -9495,6 +9511,10 @@ public class ConnectivityServiceTest { 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(); @@ -9669,7 +9689,7 @@ public class ConnectivityServiceTest { } @Test - public void testOemNetworkRequestFactoryCorrectlySetsUids() + public void testOemNetworkRequestFactoryMultiplePrefsCorrectlySetsUids() throws Exception { // Arrange PackageManager mocks final String testPackageName2 = "com.google.apps.dialer"; @@ -9700,6 +9720,46 @@ public class ConnectivityServiceTest { } @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 @@ -9829,6 +9889,54 @@ public class ConnectivityServiceTest { 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( @@ -9856,7 +9964,7 @@ public class ConnectivityServiceTest { assertEquals(1, mService.mDefaultNetworkRequests.size()); final UidRangeParcel[] uidRanges = - toUidRangeStableParcels(uidRangesForUid(testPackageUid)); + toUidRangeStableParcels(uidRangesForUids(testPackageUid)); setupSetOemNetworkPreferenceForPreferenceTest( networkPrefToSetup, uidRanges, testPackageName); } @@ -9911,6 +10019,7 @@ public class ConnectivityServiceTest { @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 +10034,7 @@ public class ConnectivityServiceTest { // Verify that the active network is correct verifyActiveNetwork(TRANSPORT_ETHERNET); + // default NCs will be unregistered in tearDown } @Test @@ -9932,6 +10042,7 @@ public class ConnectivityServiceTest { @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 +10063,7 @@ public class ConnectivityServiceTest { mEthernetNetworkAgent.getNetwork()); assertFalse(mCm.isActiveNetworkMetered()); + // default NCs will be unregistered in tearDown } @Test @@ -10082,6 +10194,10 @@ public class ConnectivityServiceTest { 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 +10205,30 @@ public class ConnectivityServiceTest { 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 +10238,6 @@ public class ConnectivityServiceTest { /** * Test the tracked default requests clear previous OEM requests on setOemNetworkPreference(). - * @throws Exception */ @Test public void testSetOemNetworkPreferenceClearPreviousOemValues() throws Exception { @@ -10117,7 +10246,7 @@ public class ConnectivityServiceTest { 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 +10265,8 @@ public class ConnectivityServiceTest { } /** - * 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 +10275,8 @@ public class ConnectivityServiceTest { 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 +10331,8 @@ public class ConnectivityServiceTest { } /** - * 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 +10341,8 @@ public class ConnectivityServiceTest { 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 +10392,9 @@ public class ConnectivityServiceTest { } /** - * 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 +10403,8 @@ public class ConnectivityServiceTest { 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 +10444,9 @@ public class ConnectivityServiceTest { } /** - * 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 +10455,8 @@ public class ConnectivityServiceTest { 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 +10495,417 @@ public class ConnectivityServiceTest { 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 000000000000..5135ea7077a8 --- /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 66590c92579b..7515971b8307 100644 --- a/tests/vcn/java/android/net/vcn/VcnManagerTest.java +++ b/tests/vcn/java/android/net/vcn/VcnManagerTest.java @@ -203,9 +203,6 @@ public class VcnManagerTest { 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 000000000000..bc8e9d3200b6 --- /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 000000000000..4f3930f9b5af --- /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 000000000000..8ae8692b4f75 --- /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 000000000000..b3cd0ab80599 --- /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 9b500a7271d7..11498dec8165 100644 --- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java +++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java @@ -100,6 +100,8 @@ import java.util.UUID; 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 @@ public class VcnManagementServiceTest { 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 @@ public class VcnManagementServiceTest { (activeSubscriptionGroups == null || activeSubscriptionGroups.isEmpty()) ? Collections.emptySet() : Collections.singleton(TEST_PACKAGE_NAME); - doReturn(true) + doReturn(hasCarrierPrivileges) .when(snapshot) .packageHasPermissionsForSubscriptionGroup( argThat(val -> activeSubscriptionGroups.contains(val)), @@ -451,6 +461,34 @@ public class VcnManagementServiceTest { } @Test + public void testSetVcnConfigNotifiesStatusCallback() throws Exception { + mVcnMgmtSvc.systemReady(); + doReturn(true) + .when(mLocationPermissionChecker) + .checkLocationPermission(eq(TEST_PACKAGE_NAME), any(), eq(TEST_UID), any()); + triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_2)); + + mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME); + verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED); + + // Use a different UUID to simulate a new VCN config. + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); + + verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE); + } + + @Test + public void testSetVcnConfigInSafeModeNotifiesStatusCallback() throws Exception { + setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_2, false /* isActive */); + mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME); + verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE); + + mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); + + verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE); + } + + @Test public void testClearVcnConfigRequiresNonSystemServer() throws Exception { doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid(); @@ -493,6 +531,17 @@ public class VcnManagementServiceTest { } @Test + public void testClearVcnConfigNotifiesStatusCallback() throws Exception { + setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isActive */); + mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME); + verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE); + + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2); + + verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED); + } + + @Test public void testSetVcnConfigClearVcnConfigStartsUpdatesAndTeardsDownVcns() throws Exception { // Use a different UUID to simulate a new VCN config. mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); @@ -549,13 +598,6 @@ public class VcnManagementServiceTest { 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 +615,23 @@ public class VcnManagementServiceTest { } 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 +777,7 @@ public class VcnManagementServiceTest { verify(mMockPolicyListener).onPolicyChanged(); } - private void verifyVcnCallback( + private void triggerVcnSafeMode( @NonNull ParcelUuid subGroup, @NonNull TelephonySubscriptionSnapshot snapshot) throws Exception { verify(mMockDeps) @@ -732,20 +788,20 @@ public class VcnManagementServiceTest { 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 +814,9 @@ public class VcnManagementServiceTest { 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 +827,7 @@ public class VcnManagementServiceTest { mVcnMgmtSvc.registerVcnStatusCallback(subGroup, mMockStatusCallback, pkgName); - // Trigger systemReady() to set up LocationPermissionChecker - mVcnMgmtSvc.systemReady(); - - verifyVcnCallback(subGroup, snapshot); + triggerVcnSafeMode(subGroup, snapshot); } @Test @@ -825,6 +881,83 @@ public class VcnManagementServiceTest { 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/tests/vcn/java/com/android/server/vcn/VcnTest.java b/tests/vcn/java/com/android/server/vcn/VcnTest.java index 3dd710afed7b..4fa63d4ff640 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnTest.java @@ -22,7 +22,9 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.argThat; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; @@ -48,6 +50,7 @@ import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; +import java.util.Arrays; import java.util.Set; import java.util.UUID; @@ -58,7 +61,7 @@ public class VcnTest { private static final int PROVIDER_ID = 5; private static final int[][] TEST_CAPS = new int[][] { - new int[] {NET_CAPABILITY_INTERNET, NET_CAPABILITY_MMS}, + new int[] {NET_CAPABILITY_MMS, NET_CAPABILITY_INTERNET}, new int[] {NET_CAPABILITY_DUN} }; @@ -155,14 +158,6 @@ public class VcnTest { } } - @Test - public void testGatewayEnteringSafeModeNotifiesVcn() { - final NetworkRequestListener requestListener = verifyAndGetRequestListener(); - for (final int capability : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) { - startVcnGatewayWithCapabilities(requestListener, capability); - } - } - private void triggerVcnRequestListeners(NetworkRequestListener requestListener) { for (final int[] caps : TEST_CAPS) { startVcnGatewayWithCapabilities(requestListener, caps); @@ -188,8 +183,20 @@ public class VcnTest { return gatewayConnections; } + private void verifySafeMode( + NetworkRequestListener requestListener, + Set<VcnGatewayConnection> expectedGatewaysTornDown) { + assertFalse(mVcn.isActive()); + assertTrue(mVcn.getVcnGatewayConnections().isEmpty()); + for (final VcnGatewayConnection gatewayConnection : expectedGatewaysTornDown) { + verify(gatewayConnection).teardownAsynchronously(); + } + verify(mVcnNetworkProvider).unregisterListener(requestListener); + verify(mVcnCallback).onEnteredSafeMode(); + } + @Test - public void testGatewayEnteringSafemodeNotifiesVcn() { + public void testGatewayEnteringSafeModeNotifiesVcn() { final NetworkRequestListener requestListener = verifyAndGetRequestListener(); final Set<VcnGatewayConnection> gatewayConnections = startGatewaysAndGetGatewayConnections(requestListener); @@ -200,12 +207,7 @@ public class VcnTest { statusCallback.onEnteredSafeMode(); mTestLooper.dispatchAll(); - assertFalse(mVcn.isActive()); - for (final VcnGatewayConnection gatewayConnection : gatewayConnections) { - verify(gatewayConnection).teardownAsynchronously(); - } - verify(mVcnNetworkProvider).unregisterListener(requestListener); - verify(mVcnCallback).onEnteredSafeMode(); + verifySafeMode(requestListener, gatewayConnections); } @Test @@ -234,4 +236,39 @@ public class VcnTest { any(), mGatewayStatusCallbackCaptor.capture()); } + + @Test + public void testUpdateConfigExitsSafeMode() { + final NetworkRequestListener requestListener = verifyAndGetRequestListener(); + final Set<VcnGatewayConnection> gatewayConnections = + new ArraySet<>(startGatewaysAndGetGatewayConnections(requestListener)); + + final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue(); + statusCallback.onEnteredSafeMode(); + mTestLooper.dispatchAll(); + verifySafeMode(requestListener, gatewayConnections); + + doAnswer(invocation -> { + final NetworkRequestListener listener = invocation.getArgument(0); + triggerVcnRequestListeners(listener); + return null; + }).when(mVcnNetworkProvider).registerListener(eq(requestListener)); + + mVcn.updateConfig(mConfig); + mTestLooper.dispatchAll(); + + // Registered on start, then re-registered with new configs + verify(mVcnNetworkProvider, times(2)).registerListener(eq(requestListener)); + assertTrue(mVcn.isActive()); + for (final int[] caps : TEST_CAPS) { + // Expect each gateway connection created on initial startup, and again with new configs + verify(mDeps, times(2)) + .newVcnGatewayConnection( + eq(mVcnContext), + eq(TEST_SUB_GROUP), + eq(mSubscriptionSnapshot), + argThat(config -> Arrays.equals(caps, config.getExposedCapabilities())), + any()); + } + } } |