diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2021-06-23 01:07:30 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2021-06-23 01:07:30 +0000 |
commit | 7f5466cf1d7dde34bba6e2da204eba26f31c7c4e (patch) | |
tree | d4a59b5ac880a4f7e9d5c61dc742a621cf850a26 | |
parent | 37a8312d53a43d6b2ce2ebf267e840cbc3d69264 (diff) | |
parent | cfc8359f34147b7fb75204d7d8f13b3e7a16af6d (diff) |
Snap for 7482982 from cfc8359f34147b7fb75204d7d8f13b3e7a16af6d to sc-release
Change-Id: I185d55626344fc7460becf6dc041640f9f35b5db
336 files changed, 4946 insertions, 2992 deletions
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java index 4ef91b5e3bc1..0b24c0d9f5c5 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java +++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java @@ -136,8 +136,6 @@ public final class AppSearchSession implements Closeable { * @param callback Callback to receive errors resulting from setting the schema. If the * operation succeeds, the callback will be invoked with {@code null}. */ - // TODO(b/169883602): Change @code references to @link when setPlatformSurfaceable APIs are - // exposed. public void setSchema( @NonNull SetSchemaRequest request, @NonNull Executor workExecutor, @@ -152,7 +150,7 @@ public final class AppSearchSession implements Closeable { for (AppSearchSchema schema : request.getSchemas()) { schemaBundles.add(schema.getBundle()); } - Map<String, List<Bundle>> schemasPackageAccessibleBundles = + Map<String, List<Bundle>> schemasVisibleToPackagesBundles = new ArrayMap<>(request.getSchemasVisibleToPackagesInternal().size()); for (Map.Entry<String, Set<PackageIdentifier>> entry : request.getSchemasVisibleToPackagesInternal().entrySet()) { @@ -160,7 +158,7 @@ public final class AppSearchSession implements Closeable { for (PackageIdentifier packageIdentifier : entry.getValue()) { packageIdentifierBundles.add(packageIdentifier.getBundle()); } - schemasPackageAccessibleBundles.put(entry.getKey(), packageIdentifierBundles); + schemasVisibleToPackagesBundles.put(entry.getKey(), packageIdentifierBundles); } // No need to trigger migration if user never set migrator @@ -168,14 +166,14 @@ public final class AppSearchSession implements Closeable { setSchemaNoMigrations( request, schemaBundles, - schemasPackageAccessibleBundles, + schemasVisibleToPackagesBundles, callbackExecutor, callback); } else { setSchemaWithMigrations( request, schemaBundles, - schemasPackageAccessibleBundles, + schemasVisibleToPackagesBundles, workExecutor, callbackExecutor, callback); @@ -704,7 +702,7 @@ public final class AppSearchSession implements Closeable { private void setSchemaNoMigrations( @NonNull SetSchemaRequest request, @NonNull List<Bundle> schemaBundles, - @NonNull Map<String, List<Bundle>> schemasPackageAccessibleBundles, + @NonNull Map<String, List<Bundle>> schemasVisibleToPackagesBundles, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<AppSearchResult<SetSchemaResponse>> callback) { try { @@ -713,7 +711,7 @@ public final class AppSearchSession implements Closeable { mDatabaseName, schemaBundles, new ArrayList<>(request.getSchemasNotDisplayedBySystem()), - schemasPackageAccessibleBundles, + schemasVisibleToPackagesBundles, request.isForceOverride(), request.getVersion(), mUserHandle, @@ -761,7 +759,7 @@ public final class AppSearchSession implements Closeable { private void setSchemaWithMigrations( @NonNull SetSchemaRequest request, @NonNull List<Bundle> schemaBundles, - @NonNull Map<String, List<Bundle>> schemasPackageAccessibleBundles, + @NonNull Map<String, List<Bundle>> schemasVisibleToPackagesBundles, @NonNull Executor workExecutor, @NonNull @CallbackExecutor Executor callbackExecutor, @NonNull Consumer<AppSearchResult<SetSchemaResponse>> callback) { @@ -787,7 +785,7 @@ public final class AppSearchSession implements Closeable { // No need to trigger migration if no migrator is active. if (activeMigrators.isEmpty()) { - setSchemaNoMigrations(request, schemaBundles, schemasPackageAccessibleBundles, + setSchemaNoMigrations(request, schemaBundles, schemasVisibleToPackagesBundles, callbackExecutor, callback); return; } @@ -801,7 +799,7 @@ public final class AppSearchSession implements Closeable { mDatabaseName, schemaBundles, new ArrayList<>(request.getSchemasNotDisplayedBySystem()), - schemasPackageAccessibleBundles, + schemasVisibleToPackagesBundles, /*forceOverride=*/ false, request.getVersion(), mUserHandle, @@ -853,7 +851,7 @@ public final class AppSearchSession implements Closeable { mDatabaseName, schemaBundles, new ArrayList<>(request.getSchemasNotDisplayedBySystem()), - schemasPackageAccessibleBundles, + schemasVisibleToPackagesBundles, /*forceOverride=*/ true, request.getVersion(), mUserHandle, diff --git a/apex/appsearch/framework/java/android/app/appsearch/aidl/IAppSearchManager.aidl b/apex/appsearch/framework/java/android/app/appsearch/aidl/IAppSearchManager.aidl index 0b26e146a7a4..c639ef604de8 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/aidl/IAppSearchManager.aidl +++ b/apex/appsearch/framework/java/android/app/appsearch/aidl/IAppSearchManager.aidl @@ -32,7 +32,7 @@ interface IAppSearchManager { * @param schemaBundles List of {@link AppSearchSchema} bundles. * @param schemasNotDisplayedBySystem Schema types that should not be surfaced on platform * surfaces. - * @param schemasPackageAccessibleBundles Schema types that are visible to the specified + * @param schemasVisibleToPackagesBundles Schema types that are visible to the specified * packages. The value List contains PackageIdentifier Bundles. * @param forceOverride Whether to apply the new schema even if it is incompatible. All * incompatible documents will be deleted. @@ -48,7 +48,7 @@ interface IAppSearchManager { in String databaseName, in List<Bundle> schemaBundles, in List<String> schemasNotDisplayedBySystem, - in Map<String, List<Bundle>> schemasPackageAccessibleBundles, + in Map<String, List<Bundle>> schemasVisibleToPackagesBundles, boolean forceOverride, in int schemaVersion, in UserHandle userHandle, 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 400c24138060..ac584fe4b91b 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java @@ -333,7 +333,7 @@ public class AppSearchManagerService extends SystemService { for (int i = 0; i < schemaBundles.size(); i++) { schemas.add(new AppSearchSchema(schemaBundles.get(i))); } - Map<String, List<PackageIdentifier>> schemasPackageAccessible = + Map<String, List<PackageIdentifier>> schemasVisibleToPackages = new ArrayMap<>(schemasVisibleToPackagesBundles.size()); for (Map.Entry<String, List<Bundle>> entry : schemasVisibleToPackagesBundles.entrySet()) { @@ -343,7 +343,7 @@ public class AppSearchManagerService extends SystemService { packageIdentifiers.add( new PackageIdentifier(entry.getValue().get(i))); } - schemasPackageAccessible.put(entry.getKey(), packageIdentifiers); + schemasVisibleToPackages.put(entry.getKey(), packageIdentifiers); } instance = mAppSearchUserInstanceManager.getUserInstance(callingUser); SetSchemaResponse setSchemaResponse = instance.getAppSearchImpl().setSchema( @@ -352,7 +352,7 @@ public class AppSearchManagerService extends SystemService { schemas, instance.getVisibilityStore(), schemasNotDisplayedBySystem, - schemasPackageAccessible, + schemasVisibleToPackages, forceOverride, schemaVersion); ++operationSuccessCount; diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java index 77a1bb402bd3..4ad1c8c56979 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java @@ -346,11 +346,11 @@ public final class AppSearchImpl implements Closeable { * @param packageName The package name that owns the schemas. * @param databaseName The name of the database where this schema lives. * @param schemas Schemas to set for this app. - * @param visibilityStore If set, {@code schemasNotPlatformSurfaceable} and {@code - * schemasPackageAccessible} will be saved here if the schema is successfully applied. - * @param schemasNotPlatformSurfaceable Schema types that should not be surfaced on platform + * @param visibilityStore If set, {@code schemasNotDisplayedBySystem} and {@code + * schemasVisibleToPackages} will be saved here if the schema is successfully applied. + * @param schemasNotDisplayedBySystem Schema types that should not be surfaced on platform * surfaces. - * @param schemasPackageAccessible Schema types that are visible to the specified packages. + * @param schemasVisibleToPackages Schema types that are visible to the specified packages. * @param forceOverride Whether to force-apply the schema even if it is incompatible. Documents * which do not comply with the new schema will be deleted. * @param version The overall version number of the request. @@ -366,8 +366,8 @@ public final class AppSearchImpl implements Closeable { @NonNull String databaseName, @NonNull List<AppSearchSchema> schemas, @Nullable VisibilityStore visibilityStore, - @NonNull List<String> schemasNotPlatformSurfaceable, - @NonNull Map<String, List<PackageIdentifier>> schemasPackageAccessible, + @NonNull List<String> schemasNotDisplayedBySystem, + @NonNull Map<String, List<PackageIdentifier>> schemasVisibleToPackages, boolean forceOverride, int version) throws AppSearchException { @@ -430,25 +430,25 @@ public final class AppSearchImpl implements Closeable { } if (visibilityStore != null) { - Set<String> prefixedSchemasNotPlatformSurfaceable = - new ArraySet<>(schemasNotPlatformSurfaceable.size()); - for (int i = 0; i < schemasNotPlatformSurfaceable.size(); i++) { - prefixedSchemasNotPlatformSurfaceable.add( - prefix + schemasNotPlatformSurfaceable.get(i)); + Set<String> prefixedSchemasNotDisplayedBySystem = + new ArraySet<>(schemasNotDisplayedBySystem.size()); + for (int i = 0; i < schemasNotDisplayedBySystem.size(); i++) { + prefixedSchemasNotDisplayedBySystem.add( + prefix + schemasNotDisplayedBySystem.get(i)); } - Map<String, List<PackageIdentifier>> prefixedSchemasPackageAccessible = - new ArrayMap<>(schemasPackageAccessible.size()); + Map<String, List<PackageIdentifier>> prefixedSchemasVisibleToPackages = + new ArrayMap<>(schemasVisibleToPackages.size()); for (Map.Entry<String, List<PackageIdentifier>> entry : - schemasPackageAccessible.entrySet()) { - prefixedSchemasPackageAccessible.put(prefix + entry.getKey(), entry.getValue()); + schemasVisibleToPackages.entrySet()) { + prefixedSchemasVisibleToPackages.put(prefix + entry.getKey(), entry.getValue()); } visibilityStore.setVisibility( packageName, databaseName, - prefixedSchemasNotPlatformSurfaceable, - prefixedSchemasPackageAccessible); + prefixedSchemasNotDisplayedBySystem, + prefixedSchemasVisibleToPackages); } return SetSchemaResponseToProtoConverter.toSetSchemaResponse( @@ -737,6 +737,9 @@ public final class AppSearchImpl implements Closeable { if (!filterPackageNames.isEmpty() && !filterPackageNames.contains(packageName)) { // Client wanted to query over some packages that weren't its own. This isn't // allowed through local query so we can return early with no results. + if (logger != null) { + sStatsBuilder.setStatusCode(AppSearchResult.RESULT_SECURITY_ERROR); + } return new SearchResultPage(Bundle.EMPTY); } @@ -768,7 +771,7 @@ public final class AppSearchImpl implements Closeable { * @param queryExpression Query String to search. * @param searchSpec Spec for setting filters, raw query etc. * @param callerPackageName Package name of the caller, should belong to the {@code - * userContext}. + * callerUserHandle}. * @param visibilityStore Optional visibility store to obtain system and package visibility * settings from * @param callerUid UID of the client making the globalQuery call. @@ -1465,7 +1468,6 @@ public final class AppSearchImpl implements Closeable { mOptimizeIntervalCountLocked = 0; mSchemaMapLocked.clear(); mNamespaceMapLocked.clear(); - if (initStatsBuilder != null) { initStatsBuilder .setHasReset(true) diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SchemaMigrationStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SchemaMigrationStats.java new file mode 100644 index 000000000000..6e1e2d5f774b --- /dev/null +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SchemaMigrationStats.java @@ -0,0 +1,189 @@ +/* + * Copyright 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.appsearch.external.localstorage.stats; + +import android.annotation.NonNull; +import android.app.appsearch.SetSchemaRequest; + +import java.util.Objects; + +/** + * Class holds detailed stats for Schema migration. + * + * @hide + */ +// TODO(b/173532925): Hides getter and setter functions for accessing {@code +// mFirstSetSchemaLatencyMillis} and {@code mSecondSetSchemaLatencyMillis} field. + +public final class SchemaMigrationStats { + /** GetSchema latency in milliseconds. */ + private final int mGetSchemaLatencyMillis; + + /** + * Latency of querying all documents that need to be migrated to new version and transforming + * documents to new version in milliseconds. + */ + private final int mQueryAndTransformLatencyMillis; + + private final int mFirstSetSchemaLatencyMillis; + + private final int mSecondSetSchemaLatencyMillis; + + /** Latency of putting migrated document to Icing lib in milliseconds. */ + private final int mSaveDocumentLatencyMillis; + + private final int mMigratedDocumentCount; + + private final int mSavedDocumentCount; + + SchemaMigrationStats(@NonNull Builder builder) { + Objects.requireNonNull(builder); + mGetSchemaLatencyMillis = builder.mGetSchemaLatencyMillis; + mQueryAndTransformLatencyMillis = builder.mQueryAndTransformLatencyMillis; + mFirstSetSchemaLatencyMillis = builder.mFirstSetSchemaLatencyMillis; + mSecondSetSchemaLatencyMillis = builder.mSecondSetSchemaLatencyMillis; + mSaveDocumentLatencyMillis = builder.mSaveDocumentLatencyMillis; + mMigratedDocumentCount = builder.mMigratedDocumentCount; + mSavedDocumentCount = builder.mSavedDocumentCount; + } + + /** Returns GetSchema latency in milliseconds. */ + public int getGetSchemaLatencyMillis() { + return mGetSchemaLatencyMillis; + } + + /** + * Returns latency of querying all documents that need to be migrated to new version and + * transforming documents to new version in milliseconds. + */ + public int getQueryAndTransformLatencyMillis() { + return mQueryAndTransformLatencyMillis; + } + + /** + * Returns latency of first SetSchema action in milliseconds. + * + * <p>If all schema fields are backward compatible, the schema will be successful set to Icing. + * Otherwise, we will retrieve incompatible types here. + * + * <p>Please see {@link SetSchemaRequest} for what is "incompatible". + */ + public int getFirstSetSchemaLatencyMillis() { + return mFirstSetSchemaLatencyMillis; + } + + /** + * Returns latency of second SetSchema action in milliseconds. + * + * <p>If all schema fields are backward compatible, the schema will be successful set to Icing + * in the first setSchema action and this value will be 0. Otherwise, schema types will be set + * to Icing by this action. + */ + public int getSecondSetSchemaLatencyMillis() { + return mSecondSetSchemaLatencyMillis; + } + + /** Returns latency of putting migrated document to Icing lib in milliseconds. */ + public int getSaveDocumentLatencyMillis() { + return mSaveDocumentLatencyMillis; + } + + /** Returns number of migrated documents. */ + public int getMigratedDocumentCount() { + return mMigratedDocumentCount; + } + + /** Returns number of updated documents which are saved in Icing lib. */ + public int getSavedDocumentCount() { + return mSavedDocumentCount; + } + + /** Builder for {@link SchemaMigrationStats}. */ + public static class Builder { + int mGetSchemaLatencyMillis; + int mQueryAndTransformLatencyMillis; + int mFirstSetSchemaLatencyMillis; + int mSecondSetSchemaLatencyMillis; + int mSaveDocumentLatencyMillis; + int mMigratedDocumentCount; + int mSavedDocumentCount; + + /** Sets latency for the GetSchema action in milliseconds. */ + @NonNull + public SchemaMigrationStats.Builder setGetSchemaLatencyMillis(int getSchemaLatencyMillis) { + mGetSchemaLatencyMillis = getSchemaLatencyMillis; + return this; + } + + /** + * Sets latency for querying all documents that need to be migrated to new version and + * transforming documents to new version in milliseconds. + */ + @NonNull + public SchemaMigrationStats.Builder setQueryAndTransformLatencyMillis( + int queryAndTransformLatencyMillis) { + mQueryAndTransformLatencyMillis = queryAndTransformLatencyMillis; + return this; + } + + /** Sets latency of first SetSchema action in milliseconds. */ + @NonNull + public SchemaMigrationStats.Builder setFirstSetSchemaLatencyMillis( + int firstSetSchemaLatencyMillis) { + mFirstSetSchemaLatencyMillis = firstSetSchemaLatencyMillis; + return this; + } + + /** Sets latency of second SetSchema action in milliseconds. */ + @NonNull + public SchemaMigrationStats.Builder setSecondSetSchemaLatencyMillis( + int secondSetSchemaLatencyMillis) { + mSecondSetSchemaLatencyMillis = secondSetSchemaLatencyMillis; + return this; + } + + /** Sets latency for putting migrated document to Icing lib in milliseconds. */ + @NonNull + public SchemaMigrationStats.Builder setSaveDocumentLatencyMillis( + int saveDocumentLatencyMillis) { + mSaveDocumentLatencyMillis = saveDocumentLatencyMillis; + return this; + } + + /** Sets number of migrated documents. */ + @NonNull + public SchemaMigrationStats.Builder setMigratedDocumentCount(int migratedDocumentCount) { + mMigratedDocumentCount = migratedDocumentCount; + return this; + } + + /** Sets number of updated documents which are saved in Icing lib. */ + @NonNull + public SchemaMigrationStats.Builder setSavedDocumentCount(int savedDocumentCount) { + mSavedDocumentCount = savedDocumentCount; + return this; + } + + /** + * Builds a new {@link SchemaMigrationStats} from the {@link SchemaMigrationStats.Builder}. + */ + @NonNull + public SchemaMigrationStats build() { + return new SchemaMigrationStats(/* builder= */ this); + } + } +} diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SetSchemaStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SetSchemaStats.java index 56a546a2e8e1..9d789a894855 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SetSchemaStats.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SetSchemaStats.java @@ -17,6 +17,7 @@ package com.android.server.appsearch.external.localstorage.stats; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.appsearch.AppSearchResult; import java.util.Objects; @@ -38,6 +39,12 @@ public final class SetSchemaStats { */ @AppSearchResult.ResultCode private final int mStatusCode; + /** + * Stores stats of SchemaMigration in SetSchema process. Is {@code null} if no schema migration + * is needed. + */ + @Nullable private final SchemaMigrationStats mSchemaMigrationStats; + private final int mTotalLatencyMillis; /** Overall time used for the native function call. */ @@ -63,6 +70,7 @@ public final class SetSchemaStats { mPackageName = builder.mPackageName; mDatabase = builder.mDatabase; mStatusCode = builder.mStatusCode; + mSchemaMigrationStats = builder.mSchemaMigrationStats; mTotalLatencyMillis = builder.mTotalLatencyMillis; mNativeLatencyMillis = builder.mNativeLatencyMillis; mNewTypeCount = builder.mNewTypeCount; @@ -90,6 +98,15 @@ public final class SetSchemaStats { return mStatusCode; } + /** + * Returns the status of schema migration, if migration is executed during the SetSchema + * process. Otherwise, returns {@code null}. + */ + @Nullable + public SchemaMigrationStats getSchemaMigrationStats() { + return mSchemaMigrationStats; + } + /** Returns the total latency of the SetSchema action. */ public int getTotalLatencyMillis() { return mTotalLatencyMillis; @@ -140,6 +157,7 @@ public final class SetSchemaStats { @NonNull final String mPackageName; @NonNull final String mDatabase; @AppSearchResult.ResultCode int mStatusCode; + @Nullable SchemaMigrationStats mSchemaMigrationStats; int mTotalLatencyMillis; int mNativeLatencyMillis; int mNewTypeCount; @@ -161,7 +179,14 @@ public final class SetSchemaStats { return this; } - /** Sets total latency for the SetSchema action. */ + /** Sets the status of schema migration. */ + @NonNull + public Builder setSchemaMigrationStats(@NonNull SchemaMigrationStats schemaMigrationStats) { + mSchemaMigrationStats = Objects.requireNonNull(schemaMigrationStats); + return this; + } + + /** Sets total latency for the SetSchema action in milliseconds. */ @NonNull public Builder setTotalLatencyMillis(int totalLatencyMillis) { mTotalLatencyMillis = totalLatencyMillis; diff --git a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/NotPlatformSurfaceableMap.java b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/NotDisplayedBySystemMap.java index 9e36fd02569f..95905af76123 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/NotPlatformSurfaceableMap.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/NotDisplayedBySystemMap.java @@ -27,7 +27,7 @@ import java.util.Set; * * This object is not thread safe. */ -class NotPlatformSurfaceableMap { +class NotDisplayedBySystemMap { /** * Maps packages to databases to the set of prefixed schemas that are platform-hidden within * that database. @@ -39,7 +39,7 @@ class NotPlatformSurfaceableMap { * * <p>Any existing mappings for this prefix are overwritten. */ - public void setNotPlatformSurfaceable( + public void setNotDisplayedBySystem( @NonNull String packageName, @NonNull String databaseName, @NonNull Set<String> prefixedSchemas) { @@ -55,7 +55,7 @@ class NotPlatformSurfaceableMap { * Returns whether the given prefixed schema is platform surfaceable (has not opted out) in the * given database. */ - public boolean isSchemaPlatformSurfaceable( + public boolean isSchemaDisplayedBySystem( @NonNull String packageName, @NonNull String databaseName, @NonNull String prefixedSchema) { diff --git a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityDocument.java b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityDocument.java index 1771b1ddc6b6..b0108704be34 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityDocument.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityDocument.java @@ -28,10 +28,10 @@ class VisibilityDocument extends GenericDocument { /** * Property that holds the list of platform-hidden schemas, as part of the visibility settings. */ - private static final String NOT_PLATFORM_SURFACEABLE_PROPERTY = "notPlatformSurfaceable"; + private static final String NOT_DISPLAYED_BY_SYSTEM_PROPERTY = "notPlatformSurfaceable"; /** Property that holds nested documents of package accessible schemas. */ - private static final String PACKAGE_ACCESSIBLE_PROPERTY = "packageAccessible"; + private static final String VISIBLE_TO_PACKAGES_PROPERTY = "packageAccessible"; /** * Schema for the VisibilityStore's documents. @@ -41,11 +41,11 @@ class VisibilityDocument extends GenericDocument { */ public static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE) .addProperty(new AppSearchSchema.StringPropertyConfig.Builder( - NOT_PLATFORM_SURFACEABLE_PROPERTY) + NOT_DISPLAYED_BY_SYSTEM_PROPERTY) .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED) .build()) .addProperty(new AppSearchSchema.DocumentPropertyConfig.Builder( - PACKAGE_ACCESSIBLE_PROPERTY, PackageAccessibleDocument.SCHEMA_TYPE) + VISIBLE_TO_PACKAGES_PROPERTY, VisibleToPackagesDocument.SCHEMA_TYPE) .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED) .build()) .build(); @@ -55,13 +55,13 @@ class VisibilityDocument extends GenericDocument { } @Nullable - public String[] getNotPlatformSurfaceableSchemas() { - return getPropertyStringArray(NOT_PLATFORM_SURFACEABLE_PROPERTY); + public String[] getNotDisplayedBySystem() { + return getPropertyStringArray(NOT_DISPLAYED_BY_SYSTEM_PROPERTY); } @Nullable - public GenericDocument[] getPackageAccessibleSchemas() { - return getPropertyDocumentArray(PACKAGE_ACCESSIBLE_PROPERTY); + public GenericDocument[] getVisibleToPackages() { + return getPropertyDocumentArray(VISIBLE_TO_PACKAGES_PROPERTY); } /** Builder for {@link VisibilityDocument}. */ @@ -72,17 +72,15 @@ class VisibilityDocument extends GenericDocument { /** Sets which prefixed schemas have opted out of platform surfacing. */ @NonNull - public Builder setSchemasNotPlatformSurfaceable( - @NonNull String[] notPlatformSurfaceableSchemas) { - return setPropertyString( - NOT_PLATFORM_SURFACEABLE_PROPERTY, notPlatformSurfaceableSchemas); + public Builder setNotDisplayedBySystem(@NonNull String[] notDisplayedBySystemSchemas) { + return setPropertyString(NOT_DISPLAYED_BY_SYSTEM_PROPERTY, notDisplayedBySystemSchemas); } /** Sets which prefixed schemas have configured package access. */ @NonNull - public Builder setPackageAccessibleSchemas( - @NonNull PackageAccessibleDocument[] packageAccessibleSchemas) { - return setPropertyDocument(PACKAGE_ACCESSIBLE_PROPERTY, packageAccessibleSchemas); + public Builder setVisibleToPackages( + @NonNull VisibleToPackagesDocument[] visibleToPackagesDocuments) { + return setPropertyDocument(VISIBLE_TO_PACKAGES_PROPERTY, visibleToPackagesDocuments); } } } diff --git a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStore.java b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStore.java index ae1ec56b4ee6..a096aef34c71 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStore.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStore.java @@ -66,9 +66,6 @@ import java.util.Set; * @hide */ public class VisibilityStore { - /** No-op uid that won't have any visibility settings. */ - public static final int NO_OP_UID = -1; - /** Version for the visibility schema */ private static final int SCHEMA_VERSION = 0; @@ -92,11 +89,10 @@ public class VisibilityStore { private final Context mUserContext; /** Stores the schemas that are platform-hidden. All values are prefixed. */ - private final NotPlatformSurfaceableMap mNotPlatformSurfaceableMap = - new NotPlatformSurfaceableMap(); + private final NotDisplayedBySystemMap mNotDisplayedBySystemMap = new NotDisplayedBySystemMap(); - /** Stores the schemas that are package accessible. All values are prefixed. */ - private final PackageAccessibleMap mPackageAccessibleMap = new PackageAccessibleMap(); + /** Stores the schemas that are visible to 3p packages. All values are prefixed. */ + private final VisibleToPackagesMap mVisibleToPackagesMap = new VisibleToPackagesMap(); /** * Creates and initializes VisibilityStore. @@ -118,28 +114,28 @@ public class VisibilityStore { GetSchemaResponse getSchemaResponse = mAppSearchImpl.getSchema(PACKAGE_NAME, DATABASE_NAME); boolean hasVisibilityType = false; - boolean hasPackageAccessibleType = false; + boolean hasVisibleToPackagesType = false; for (AppSearchSchema schema : getSchemaResponse.getSchemas()) { if (schema.getSchemaType().equals(VisibilityDocument.SCHEMA_TYPE)) { hasVisibilityType = true; - } else if (schema.getSchemaType().equals(PackageAccessibleDocument.SCHEMA_TYPE)) { - hasPackageAccessibleType = true; + } else if (schema.getSchemaType().equals(VisibleToPackagesDocument.SCHEMA_TYPE)) { + hasVisibleToPackagesType = true; } - if (hasVisibilityType && hasPackageAccessibleType) { + if (hasVisibilityType && hasVisibleToPackagesType) { // Found both our types, can exit early. break; } } - if (!hasVisibilityType || !hasPackageAccessibleType) { + if (!hasVisibilityType || !hasVisibleToPackagesType) { // Schema type doesn't exist yet. Add it. mAppSearchImpl.setSchema( PACKAGE_NAME, DATABASE_NAME, - Arrays.asList(VisibilityDocument.SCHEMA, PackageAccessibleDocument.SCHEMA), + Arrays.asList(VisibilityDocument.SCHEMA, VisibleToPackagesDocument.SCHEMA), /*visibilityStore=*/ null, // Avoid recursive calls - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ SCHEMA_VERSION); } @@ -177,26 +173,25 @@ public class VisibilityStore { } // Update platform visibility settings - String[] notPlatformSurfaceableSchemas = - visibilityDocument.getNotPlatformSurfaceableSchemas(); - if (notPlatformSurfaceableSchemas != null) { - mNotPlatformSurfaceableMap.setNotPlatformSurfaceable( + String[] notDisplayedBySystemSchemas = visibilityDocument.getNotDisplayedBySystem(); + if (notDisplayedBySystemSchemas != null) { + mNotDisplayedBySystemMap.setNotDisplayedBySystem( packageName, databaseName, - new ArraySet<>(notPlatformSurfaceableSchemas)); + new ArraySet<>(notDisplayedBySystemSchemas)); } // Update 3p package visibility settings Map<String, Set<PackageIdentifier>> schemaToPackageIdentifierMap = new ArrayMap<>(); - GenericDocument[] packageAccessibleDocuments = - visibilityDocument.getPackageAccessibleSchemas(); - if (packageAccessibleDocuments != null) { - for (int i = 0; i < packageAccessibleDocuments.length; i++) { - PackageAccessibleDocument packageAccessibleDocument = - new PackageAccessibleDocument(packageAccessibleDocuments[i]); + GenericDocument[] visibleToPackagesDocuments = + visibilityDocument.getVisibleToPackages(); + if (visibleToPackagesDocuments != null) { + for (int i = 0; i < visibleToPackagesDocuments.length; i++) { + VisibleToPackagesDocument visibleToPackagesDocument = + new VisibleToPackagesDocument(visibleToPackagesDocuments[i]); PackageIdentifier packageIdentifier = - packageAccessibleDocument.getPackageIdentifier(); - String prefixedSchema = packageAccessibleDocument.getAccessibleSchemaType(); + visibleToPackagesDocument.getPackageIdentifier(); + String prefixedSchema = visibleToPackagesDocument.getAccessibleSchemaType(); Set<PackageIdentifier> packageIdentifiers = schemaToPackageIdentifierMap.get(prefixedSchema); if (packageIdentifiers == null) { @@ -206,7 +201,7 @@ public class VisibilityStore { schemaToPackageIdentifierMap.put(prefixedSchema, packageIdentifiers); } } - mPackageAccessibleMap.setPackageAccessible( + mVisibleToPackagesMap.setVisibleToPackages( packageName, databaseName, schemaToPackageIdentifierMap); } } @@ -216,51 +211,51 @@ public class VisibilityStore { * Sets visibility settings for the given database. Any previous visibility settings will be * overwritten. * - * @param packageName Package of app that owns the {@code schemasNotPlatformSurfaceable}. - * @param databaseName Database that owns the {@code schemasNotPlatformSurfaceable}. - * @param schemasNotPlatformSurfaceable Set of prefixed schemas that should be hidden from the + * @param packageName Package of app that owns the schemas. + * @param databaseName Database that owns the schemas. + * @param schemasNotDisplayedBySystem Set of prefixed schemas that should be hidden from the * platform. - * @param schemasPackageAccessible Map of prefixed schemas to a list of package identifiers that + * @param schemasVisibleToPackages Map of prefixed schemas to a list of package identifiers that * have access to the schema. * @throws AppSearchException on AppSearchImpl error. */ public void setVisibility( @NonNull String packageName, @NonNull String databaseName, - @NonNull Set<String> schemasNotPlatformSurfaceable, - @NonNull Map<String, List<PackageIdentifier>> schemasPackageAccessible) + @NonNull Set<String> schemasNotDisplayedBySystem, + @NonNull Map<String, List<PackageIdentifier>> schemasVisibleToPackages) throws AppSearchException { Objects.requireNonNull(packageName); Objects.requireNonNull(databaseName); - Objects.requireNonNull(schemasNotPlatformSurfaceable); - Objects.requireNonNull(schemasPackageAccessible); + Objects.requireNonNull(schemasNotDisplayedBySystem); + Objects.requireNonNull(schemasVisibleToPackages); // Persist the document VisibilityDocument.Builder visibilityDocument = new VisibilityDocument.Builder( NAMESPACE, /*id=*/ getVisibilityDocumentId(packageName, databaseName)); - if (!schemasNotPlatformSurfaceable.isEmpty()) { - visibilityDocument.setSchemasNotPlatformSurfaceable( - schemasNotPlatformSurfaceable.toArray(new String[0])); + if (!schemasNotDisplayedBySystem.isEmpty()) { + visibilityDocument.setNotDisplayedBySystem( + schemasNotDisplayedBySystem.toArray(new String[0])); } Map<String, Set<PackageIdentifier>> schemaToPackageIdentifierMap = new ArrayMap<>(); - List<PackageAccessibleDocument> packageAccessibleDocuments = new ArrayList<>(); + List<VisibleToPackagesDocument> visibleToPackagesDocuments = new ArrayList<>(); for (Map.Entry<String, List<PackageIdentifier>> entry : - schemasPackageAccessible.entrySet()) { + schemasVisibleToPackages.entrySet()) { for (int i = 0; i < entry.getValue().size(); i++) { - PackageAccessibleDocument packageAccessibleDocument = - new PackageAccessibleDocument.Builder(NAMESPACE, /*id=*/ "") + VisibleToPackagesDocument visibleToPackagesDocument = + new VisibleToPackagesDocument.Builder(NAMESPACE, /*id=*/ "") .setAccessibleSchemaType(entry.getKey()) .setPackageIdentifier(entry.getValue().get(i)) .build(); - packageAccessibleDocuments.add(packageAccessibleDocument); + visibleToPackagesDocuments.add(visibleToPackagesDocument); } schemaToPackageIdentifierMap.put(entry.getKey(), new ArraySet<>(entry.getValue())); } - if (!packageAccessibleDocuments.isEmpty()) { - visibilityDocument.setPackageAccessibleSchemas( - packageAccessibleDocuments.toArray(new PackageAccessibleDocument[0])); + if (!visibleToPackagesDocuments.isEmpty()) { + visibilityDocument.setVisibleToPackages( + visibleToPackagesDocuments.toArray(new VisibleToPackagesDocument[0])); } mAppSearchImpl.putDocument( @@ -269,9 +264,9 @@ public class VisibilityStore { mAppSearchImpl.persistToDisk(PersistType.Code.LITE); // Update derived data structures. - mNotPlatformSurfaceableMap.setNotPlatformSurfaceable( - packageName, databaseName, schemasNotPlatformSurfaceable); - mPackageAccessibleMap.setPackageAccessible( + mNotDisplayedBySystemMap.setNotDisplayedBySystem( + packageName, databaseName, schemasNotDisplayedBySystem); + mVisibleToPackagesMap.setVisibleToPackages( packageName, databaseName, schemaToPackageIdentifierMap); } @@ -313,13 +308,13 @@ public class VisibilityStore { } if (callerHasSystemAccess - && mNotPlatformSurfaceableMap.isSchemaPlatformSurfaceable( + && mNotDisplayedBySystemMap.isSchemaDisplayedBySystem( packageName, databaseName, prefixedSchema)) { return true; } // May not be platform surfaceable, but might still be accessible through 3p access. - return isSchemaPackageAccessible(packageName, databaseName, prefixedSchema, callerUid); + return isSchemaVisibleToPackages(packageName, databaseName, prefixedSchema, callerUid); } /** @@ -331,13 +326,13 @@ public class VisibilityStore { * certificate was once used to sign the package, the package will still be granted access. This * does not handle packages that have been signed by multiple certificates. */ - private boolean isSchemaPackageAccessible( + private boolean isSchemaVisibleToPackages( @NonNull String packageName, @NonNull String databaseName, @NonNull String prefixedSchema, int callerUid) { Set<PackageIdentifier> packageIdentifiers = - mPackageAccessibleMap.getAccessiblePackages( + mVisibleToPackagesMap.getAccessiblePackages( packageName, databaseName, prefixedSchema); if (packageIdentifiers.isEmpty()) { return false; diff --git a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/PackageAccessibleDocument.java b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibleToPackagesDocument.java index 0b4e196fd0c4..8d503390eaaa 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/PackageAccessibleDocument.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibleToPackagesDocument.java @@ -26,7 +26,7 @@ import android.app.appsearch.PackageIdentifier; * * @see android.app.appsearch.SetSchemaRequest.Builder#setSchemaTypeVisibilityForPackage */ -class PackageAccessibleDocument extends GenericDocument { +class VisibleToPackagesDocument extends GenericDocument { /** Schema type for nested documents that hold package accessible information. */ public static final String SCHEMA_TYPE = "PackageAccessibleType"; @@ -59,7 +59,7 @@ class PackageAccessibleDocument extends GenericDocument { .build()) .build(); - public PackageAccessibleDocument(@NonNull GenericDocument genericDocument) { + VisibleToPackagesDocument(@NonNull GenericDocument genericDocument) { super(genericDocument); } @@ -76,9 +76,9 @@ class PackageAccessibleDocument extends GenericDocument { return new PackageIdentifier(packageName, sha256Cert); } - /** Builder for {@link PackageAccessibleDocument} instances. */ - public static class Builder extends GenericDocument.Builder<PackageAccessibleDocument.Builder> { - public Builder(@NonNull String namespace, @NonNull String id) { + /** Builder for {@link VisibleToPackagesDocument} instances. */ + public static class Builder extends GenericDocument.Builder<VisibleToPackagesDocument.Builder> { + Builder(@NonNull String namespace, @NonNull String id) { super(namespace, id, SCHEMA_TYPE); } @@ -98,8 +98,8 @@ class PackageAccessibleDocument extends GenericDocument { @Override @NonNull - public PackageAccessibleDocument build() { - return new PackageAccessibleDocument(super.build()); + public VisibleToPackagesDocument build() { + return new VisibleToPackagesDocument(super.build()); } } } diff --git a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/PackageAccessibleMap.java b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibleToPackagesMap.java index cff729aa4e8a..e2b51a75025c 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/PackageAccessibleMap.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibleToPackagesMap.java @@ -29,7 +29,7 @@ import java.util.Set; * * This object is not thread safe. */ -class PackageAccessibleMap { +class VisibleToPackagesMap { /** * Maps packages to databases to prefixed schemas to PackageIdentifiers that have access to that * schema. @@ -42,7 +42,7 @@ class PackageAccessibleMap { * * <p>Any existing mappings for this prefix are overwritten. */ - public void setPackageAccessible( + public void setVisibleToPackages( @NonNull String packageName, @NonNull String databaseName, @NonNull Map<String, Set<PackageIdentifier>> schemaToPackageIdentifier) { diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt index 78d39cc6deac..9859f20643b5 100644 --- a/apex/appsearch/synced_jetpack_changeid.txt +++ b/apex/appsearch/synced_jetpack_changeid.txt @@ -1 +1 @@ -31a54dba5bda4d0109ea91eb1ac047c937cbaae3 +04351b43fbbf9d59ffeae41903322023931c84f2 diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java index d6ce3ebc267f..7b74578adfc7 100644 --- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java +++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java @@ -51,8 +51,6 @@ public interface AppSearchSessionShim extends Closeable { * @param request the schema to set or update the AppSearch database to. * @return a {@link ListenableFuture} which resolves to a {@link SetSchemaResponse} object. */ - // TODO(b/169883602): Change @code references to @link when setPlatformSurfaceable APIs are - // exposed. @NonNull ListenableFuture<SetSchemaResponse> setSchema(@NonNull SetSchemaRequest request); diff --git a/api/Android.bp b/api/Android.bp index a84e6a6cb031..2ea180ebf598 100644 --- a/api/Android.bp +++ b/api/Android.bp @@ -24,6 +24,41 @@ package { default_applicable_licenses: ["frameworks_base_license"], } +python_binary_host { + name: "api_versions_trimmer", + srcs: ["api_versions_trimmer.py"], + version: { + py2: { + enabled: false, + }, + py3: { + enabled: true, + embedded_launcher: false, + }, + }, +} + +python_test_host { + name: "api_versions_trimmer_unittests", + main: "api_versions_trimmer_unittests.py", + srcs: [ + "api_versions_trimmer_unittests.py", + "api_versions_trimmer.py", + ], + test_options: { + unit_test: true, + }, + version: { + py2: { + enabled: false, + }, + py3: { + enabled: true, + embedded_launcher: false, + }, + }, +} + metalava_cmd = "$(location metalava)" // Silence reflection warnings. See b/168689341 metalava_cmd += " -J--add-opens=java.base/java.util=ALL-UNNAMED " @@ -431,3 +466,41 @@ genrule { }, ], } + +// This rule will filter classes present in the jar files of mainline modules +// from the lint database in api-versions.xml. +// This is done to reduce the number of false positive NewApi findings in +// java libraries that compile against the module SDK +genrule { + name: "api-versions-xml-public-filtered", + srcs: [ + // Note: order matters: first parameter is the full api-versions.xml + // after that the stubs files in any order + // stubs files are all modules that export API surfaces EXCEPT ART + ":framework-doc-stubs{.api_versions.xml}", + ":android.net.ipsec.ike.stubs{.jar}", + ":conscrypt.module.public.api.stubs{.jar}", + ":framework-appsearch.stubs{.jar}", + ":framework-connectivity.stubs{.jar}", + ":framework-graphics.stubs{.jar}", + ":framework-media.stubs{.jar}", + ":framework-mediaprovider.stubs{.jar}", + ":framework-permission.stubs{.jar}", + ":framework-permission-s.stubs{.jar}", + ":framework-scheduling.stubs{.jar}", + ":framework-sdkextensions.stubs{.jar}", + ":framework-statsd.stubs{.jar}", + ":framework-tethering.stubs{.jar}", + ":framework-wifi.stubs{.jar}", + ":i18n.module.public.api.stubs{.jar}", + ], + out: ["api-versions-public-filtered.xml"], + tools: ["api_versions_trimmer"], + cmd: "$(location api_versions_trimmer) $(out) $(in)", + dist: { + targets: [ + "sdk", + "win_sdk", + ], + }, +} diff --git a/api/api_versions_trimmer.py b/api/api_versions_trimmer.py new file mode 100755 index 000000000000..9afd95a3003a --- /dev/null +++ b/api/api_versions_trimmer.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python3 +# +# 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. + +"""Script to remove mainline APIs from the api-versions.xml.""" + +import argparse +import re +import xml.etree.ElementTree as ET +import zipfile + + +def read_classes(stubs): + """Read classes from the stubs file. + + Args: + stubs: argument can be a path to a file (a string), a file-like object or a + path-like object + + Returns: + a set of the classes found in the file (set of strings) + """ + classes = set() + with zipfile.ZipFile(stubs) as z: + for info in z.infolist(): + if (not info.is_dir() + and info.filename.endswith(".class") + and not info.filename.startswith("META-INF")): + # drop ".class" extension + classes.add(info.filename[:-6]) + return classes + + +def filter_method_tag(method, classes_to_remove): + """Updates the signature of this method by calling filter_method_signature. + + Updates the method passed into this function. + + Args: + method: xml element that represents a method + classes_to_remove: set of classes you to remove + """ + filtered = filter_method_signature(method.get("name"), classes_to_remove) + method.set("name", filtered) + + +def filter_method_signature(signature, classes_to_remove): + """Removes mentions of certain classes from this method signature. + + Replaces any existing classes that need to be removed, with java/lang/Object + + Args: + signature: string that is a java representation of a method signature + classes_to_remove: set of classes you to remove + """ + regex = re.compile("L.*?;") + start = signature.find("(") + matches = set(regex.findall(signature[start:])) + for m in matches: + # m[1:-1] to drop the leading `L` and `;` ending + if m[1:-1] in classes_to_remove: + signature = signature.replace(m, "Ljava/lang/Object;") + return signature + + +def filter_lint_database(database, classes_to_remove, output): + """Reads a lint database and writes a filtered version without some classes. + + Reads database from api-versions.xml and removes any references to classes + in the second argument. Writes the result (another xml with the same format + of the database) to output. + + Args: + database: path to xml with lint database to read + classes_to_remove: iterable (ideally a set or similar for quick + lookups) that enumerates the classes that should be removed + output: path to write the filtered database + """ + xml = ET.parse(database) + root = xml.getroot() + for c in xml.findall("class"): + cname = c.get("name") + if cname in classes_to_remove: + root.remove(c) + else: + # find the <extends /> tag inside this class to see if the parent + # has been removed from the known classes (attribute called name) + super_classes = c.findall("extends") + for super_class in super_classes: + super_class_name = super_class.get("name") + if super_class_name in classes_to_remove: + super_class.set("name", "java/lang/Object") + interfaces = c.findall("implements") + for interface in interfaces: + interface_name = interface.get("name") + if interface_name in classes_to_remove: + c.remove(interface) + for method in c.findall("method"): + filter_method_tag(method, classes_to_remove) + xml.write(output) + + +def main(): + """Run the program.""" + parser = argparse.ArgumentParser( + description= + ("Read a lint database (api-versions.xml) and many stubs jar files. " + "Produce another database file that doesn't include the classes present " + "in the stubs file(s).")) + parser.add_argument("output", help="Destination of the result (xml file).") + parser.add_argument( + "api_versions", + help="The lint database (api-versions.xml file) to read data from" + ) + parser.add_argument("stubs", nargs="+", help="The stubs jar file(s)") + parsed = parser.parse_args() + classes = set() + for stub in parsed.stubs: + classes.update(read_classes(stub)) + filter_lint_database(parsed.api_versions, classes, parsed.output) + + +if __name__ == "__main__": + main() diff --git a/api/api_versions_trimmer_unittests.py b/api/api_versions_trimmer_unittests.py new file mode 100644 index 000000000000..4eb929ea1b5d --- /dev/null +++ b/api/api_versions_trimmer_unittests.py @@ -0,0 +1,307 @@ +#!/usr/bin/env python3 +# +# 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. + +import io +import re +import unittest +import xml.etree.ElementTree as ET +import zipfile + +import api_versions_trimmer + + +def create_in_memory_zip_file(files): + f = io.BytesIO() + with zipfile.ZipFile(f, "w") as z: + for fname in files: + with z.open(fname, mode="w") as class_file: + class_file.write(b"") + return f + + +def indent(elem, level=0): + i = "\n" + level * " " + j = "\n" + (level - 1) * " " + if len(elem): + if not elem.text or not elem.text.strip(): + elem.text = i + " " + if not elem.tail or not elem.tail.strip(): + elem.tail = i + for subelem in elem: + indent(subelem, level + 1) + if not elem.tail or not elem.tail.strip(): + elem.tail = j + else: + if level and (not elem.tail or not elem.tail.strip()): + elem.tail = j + return elem + + +def pretty_print(s): + tree = ET.parse(io.StringIO(s)) + el = indent(tree.getroot()) + res = ET.tostring(el).decode("utf-8") + # remove empty lines inside the result because this still breaks some + # comparisons + return re.sub(r"\n\s*\n", "\n", res, re.MULTILINE) + + +class ApiVersionsTrimmerUnittests(unittest.TestCase): + + def setUp(self): + # so it prints diffs in long strings (xml files) + self.maxDiff = None + + def test_read_classes(self): + f = create_in_memory_zip_file( + ["a/b/C.class", + "a/b/D.class", + ] + ) + res = api_versions_trimmer.read_classes(f) + self.assertEqual({"a/b/C", "a/b/D"}, res) + + def test_read_classes_ignore_dex(self): + f = create_in_memory_zip_file( + ["a/b/C.class", + "a/b/D.class", + "a/b/E.dex", + "f.dex", + ] + ) + res = api_versions_trimmer.read_classes(f) + self.assertEqual({"a/b/C", "a/b/D"}, res) + + def test_read_classes_ignore_manifest(self): + f = create_in_memory_zip_file( + ["a/b/C.class", + "a/b/D.class", + "META-INFO/G.class" + ] + ) + res = api_versions_trimmer.read_classes(f) + self.assertEqual({"a/b/C", "a/b/D"}, res) + + def test_filter_method_signature(self): + xml = """ + <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureResultCallback;Landroid/os/Handler;)Z" since="24"/> + """ + method = ET.fromstring(xml) + classes_to_remove = {"android/accessibilityservice/GestureDescription"} + expected = "dispatchGesture(Ljava/lang/Object;Landroid/accessibilityservice/AccessibilityService$GestureResultCallback;Landroid/os/Handler;)Z" + api_versions_trimmer.filter_method_tag(method, classes_to_remove) + self.assertEqual(expected, method.get("name")) + + def test_filter_method_signature_with_L_in_method(self): + xml = """ + <method name="dispatchLeftGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureResultCallback;Landroid/os/Handler;)Z" since="24"/> + """ + method = ET.fromstring(xml) + classes_to_remove = {"android/accessibilityservice/GestureDescription"} + expected = "dispatchLeftGesture(Ljava/lang/Object;Landroid/accessibilityservice/AccessibilityService$GestureResultCallback;Landroid/os/Handler;)Z" + api_versions_trimmer.filter_method_tag(method, classes_to_remove) + self.assertEqual(expected, method.get("name")) + + def test_filter_method_signature_with_L_in_class(self): + xml = """ + <method name="dispatchGesture(Landroid/accessibilityservice/LeftGestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureResultCallback;Landroid/os/Handler;)Z" since="24"/> + """ + method = ET.fromstring(xml) + classes_to_remove = {"android/accessibilityservice/LeftGestureDescription"} + expected = "dispatchGesture(Ljava/lang/Object;Landroid/accessibilityservice/AccessibilityService$GestureResultCallback;Landroid/os/Handler;)Z" + api_versions_trimmer.filter_method_tag(method, classes_to_remove) + self.assertEqual(expected, method.get("name")) + + def test_filter_method_signature_with_inner_class(self): + xml = """ + <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription$Inner;Landroid/accessibilityservice/AccessibilityService$GestureResultCallback;Landroid/os/Handler;)Z" since="24"/> + """ + method = ET.fromstring(xml) + classes_to_remove = {"android/accessibilityservice/GestureDescription$Inner"} + expected = "dispatchGesture(Ljava/lang/Object;Landroid/accessibilityservice/AccessibilityService$GestureResultCallback;Landroid/os/Handler;)Z" + api_versions_trimmer.filter_method_tag(method, classes_to_remove) + self.assertEqual(expected, method.get("name")) + + def _run_filter_db_test(self, database_str, expected): + """Performs the pattern of testing the filter_lint_database method. + + Filters instances of the class "a/b/C" (hard-coded) from the database string + and compares the result with the expected result (performs formatting of + the xml of both inputs) + + Args: + database_str: string, the contents of the lint database (api-versions.xml) + expected: string, the expected result after filtering the original + database + """ + database = io.StringIO(database_str) + classes_to_remove = {"a/b/C"} + output = io.BytesIO() + api_versions_trimmer.filter_lint_database( + database, + classes_to_remove, + output + ) + expected = pretty_print(expected) + res = pretty_print(output.getvalue().decode("utf-8")) + self.assertEqual(expected, res) + + def test_filter_lint_database_updates_method_signature_params(self): + self._run_filter_db_test( + database_str=""" + <api version="2"> + <!-- will be removed --> + <class name="a/b/C" since="1"> + <extends name="java/lang/Object"/> + </class> + + <class name="a/b/E" since="1"> + <!-- extends will be modified --> + <extends name="a/b/C"/> + <!-- first parameter will be modified --> + <method name="dispatchGesture(La/b/C;Landroid/os/Handler;)Z" since="24"/> + <!-- second should remain untouched --> + <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureRe +sultCallback;Landroid/os/Handler;)Z" since="24"/> + </class> + </api> + """, + expected=""" + <api version="2"> + <class name="a/b/E" since="1"> + <extends name="java/lang/Object"/> + <method name="dispatchGesture(Ljava/lang/Object;Landroid/os/Handler;)Z" since="24"/> + <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureRe +sultCallback;Landroid/os/Handler;)Z" since="24"/> + </class> + </api> + """) + + def test_filter_lint_database_updates_method_signature_return(self): + self._run_filter_db_test( + database_str=""" + <api version="2"> + <!-- will be removed --> + <class name="a/b/C" since="1"> + <extends name="java/lang/Object"/> + </class> + + <class name="a/b/E" since="1"> + <!-- extends will be modified --> + <extends name="a/b/C"/> + <!-- return type should be changed --> + <method name="gestureIdToString(I)La/b/C;" since="24"/> + </class> + </api> + """, + expected=""" + <api version="2"> + <class name="a/b/E" since="1"> + + <extends name="java/lang/Object"/> + + <method name="gestureIdToString(I)Ljava/lang/Object;" since="24"/> + </class> + </api> + """) + + def test_filter_lint_database_removes_implements(self): + self._run_filter_db_test( + database_str=""" + <api version="2"> + <!-- will be removed --> + <class name="a/b/C" since="1"> + <extends name="java/lang/Object"/> + </class> + + <class name="a/b/D" since="1"> + <extends name="java/lang/Object"/> + <implements name="a/b/C"/> + <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureRe +sultCallback;Landroid/os/Handler;)Z" since="24"/> + </class> + </api> + """, + expected=""" + <api version="2"> + + <class name="a/b/D" since="1"> + <extends name="java/lang/Object"/> + <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureRe +sultCallback;Landroid/os/Handler;)Z" since="24"/> + </class> + </api> + """) + + def test_filter_lint_database_updates_extends(self): + self._run_filter_db_test( + database_str=""" + <api version="2"> + <!-- will be removed --> + <class name="a/b/C" since="1"> + <extends name="java/lang/Object"/> + </class> + + <class name="a/b/E" since="1"> + <!-- extends will be modified --> + <extends name="a/b/C"/> + <method name="dispatchGesture(Ljava/lang/Object;Landroid/os/Handler;)Z" since="24"/> + <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureRe +sultCallback;Landroid/os/Handler;)Z" since="24"/> + </class> + </api> + """, + expected=""" + <api version="2"> + <class name="a/b/E" since="1"> + <extends name="java/lang/Object"/> + <method name="dispatchGesture(Ljava/lang/Object;Landroid/os/Handler;)Z" since="24"/> + <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureRe +sultCallback;Landroid/os/Handler;)Z" since="24"/> + </class> + </api> + """) + + def test_filter_lint_database_removes_class(self): + self._run_filter_db_test( + database_str=""" + <api version="2"> + <!-- will be removed --> + <class name="a/b/C" since="1"> + <extends name="java/lang/Object"/> + </class> + + <class name="a/b/D" since="1"> + <extends name="java/lang/Object"/> + <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureRe +sultCallback;Landroid/os/Handler;)Z" since="24"/> + </class> + </api> + """, + expected=""" + <api version="2"> + + <class name="a/b/D" since="1"> + <extends name="java/lang/Object"/> + <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureRe +sultCallback;Landroid/os/Handler;)Z" since="24"/> + </class> + </api> + """) + + +if __name__ == "__main__": + unittest.main() diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index ba0bc555eb57..506dfe09f3fa 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -5606,14 +5606,24 @@ public class Notification implements Parcelable final boolean snoozeEnabled = !hideSnoozeButton && mContext.getContentResolver() != null - && (Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.SHOW_NOTIFICATION_SNOOZE, 0) == 1); + && isSnoozeSettingEnabled(); if (snoozeEnabled) { big.setViewLayoutMarginDimen(R.id.notification_action_list_margin_target, RemoteViews.MARGIN_BOTTOM, 0); } } + private boolean isSnoozeSettingEnabled() { + try { + return Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.SHOW_NOTIFICATION_SNOOZE, 0) == 1; + } catch (SecurityException ex) { + // Most 3p apps can't access this snooze setting, so their NotificationListeners + // would be unable to create notification views if we propagated this exception. + return false; + } + } + /** * Returns the actions that are not contextual. */ diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java index 04a12afb8039..6ca7dfbe2284 100644 --- a/core/java/android/app/PropertyInvalidatedCache.java +++ b/core/java/android/app/PropertyInvalidatedCache.java @@ -34,6 +34,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Map; import java.util.Objects; @@ -260,12 +261,19 @@ public abstract class PropertyInvalidatedCache<Query, Result> { private static final HashMap<String, Integer> sCorks = new HashMap<>(); /** + * A map of cache keys that have been disabled in the local process. When a key is + * disabled locally, existing caches are disabled and the key is saved in this map. + * Future cache instances that use the same key will be disabled in their constructor. + */ + @GuardedBy("sCorkLock") + private static final HashSet<String> sDisabledKeys = new HashSet<>(); + + /** * Weakly references all cache objects in the current process, allowing us to iterate over * them all for purposes like issuing debug dumps and reacting to memory pressure. */ @GuardedBy("sCorkLock") - private static final WeakHashMap<PropertyInvalidatedCache, Void> sCaches = - new WeakHashMap<>(); + private static final WeakHashMap<PropertyInvalidatedCache, Void> sCaches = new WeakHashMap<>(); private final Object mLock = new Object(); @@ -348,6 +356,9 @@ public abstract class PropertyInvalidatedCache<Query, Result> { }; synchronized (sCorkLock) { sCaches.put(this, null); + if (sDisabledKeys.contains(mCacheName)) { + disableInstance(); + } } } @@ -372,6 +383,14 @@ public abstract class PropertyInvalidatedCache<Query, Result> { protected abstract Result recompute(Query query); /** + * Return true if the query should bypass the cache. The default behavior is to + * always use the cache but the method can be overridden for a specific class. + */ + protected boolean bypass(Query query) { + return false; + } + + /** * Determines if a pair of responses are considered equal. Used to determine whether * a cache is inadvertently returning stale results when VERIFY is set to true. */ @@ -414,7 +433,7 @@ public abstract class PropertyInvalidatedCache<Query, Result> { /** * Disable the use of this cache in this process. */ - public final void disableLocal() { + public final void disableInstance() { synchronized (mLock) { mDisabled = true; clear(); @@ -422,6 +441,30 @@ public abstract class PropertyInvalidatedCache<Query, Result> { } /** + * Disable the local use of all caches with the same name. All currently registered caches + * using the key will be disabled now, and all future cache instances that use the key will be + * disabled in their constructor. + */ + public static final void disableLocal(@NonNull String name) { + synchronized (sCorkLock) { + sDisabledKeys.add(name); + for (PropertyInvalidatedCache cache : sCaches.keySet()) { + if (name.equals(cache.mCacheName)) { + cache.disableInstance(); + } + } + } + } + + /** + * Disable this cache in the current process, and all other caches that use the same + * property. + */ + public final void disableLocal() { + disableLocal(mCacheName); + } + + /** * Return whether the cache is disabled in this process. */ public final boolean isDisabledLocal() { @@ -435,8 +478,8 @@ public abstract class PropertyInvalidatedCache<Query, Result> { // Let access to mDisabled race: it's atomic anyway. long currentNonce = (!isDisabledLocal()) ? getCurrentNonce() : NONCE_DISABLED; for (;;) { - if (currentNonce == NONCE_DISABLED || currentNonce == NONCE_UNSET || - currentNonce == NONCE_CORKED) { + if (currentNonce == NONCE_DISABLED || currentNonce == NONCE_UNSET + || currentNonce == NONCE_CORKED || bypass(query)) { if (!mDisabled) { // Do not bother collecting statistics if the cache is // locally disabled. @@ -875,6 +918,15 @@ public abstract class PropertyInvalidatedCache<Query, Result> { } /** + * Report the disabled status of this cache instance. The return value does not + * reflect status of the property key. + */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public boolean getDisabledState() { + return isDisabledLocal(); + } + + /** * Returns a list of caches alive at the current time. */ public static ArrayList<PropertyInvalidatedCache> getActiveCaches() { diff --git a/core/java/android/app/WallpaperColors.java b/core/java/android/app/WallpaperColors.java index cd82deb13e9b..2777a7aae517 100644 --- a/core/java/android/app/WallpaperColors.java +++ b/core/java/android/app/WallpaperColors.java @@ -111,12 +111,15 @@ public final class WallpaperColors implements Parcelable { public WallpaperColors(Parcel parcel) { mMainColors = new ArrayList<>(); mAllColors = new HashMap<>(); - final int count = parcel.readInt(); + int count = parcel.readInt(); for (int i = 0; i < count; i++) { final int colorInt = parcel.readInt(); Color color = Color.valueOf(colorInt); mMainColors.add(color); - + } + count = parcel.readInt(); + for (int i = 0; i < count; i++) { + final int colorInt = parcel.readInt(); final int population = parcel.readInt(); mAllColors.put(colorInt, population); } @@ -411,9 +414,16 @@ public final class WallpaperColors implements Parcelable { for (int i = 0; i < count; i++) { Color color = mainColors.get(i); dest.writeInt(color.toArgb()); - Integer population = mAllColors.get(color.toArgb()); - int populationInt = (population != null) ? population : 0; - dest.writeInt(populationInt); + } + count = mAllColors.size(); + dest.writeInt(count); + for (Map.Entry<Integer, Integer> colorEntry : mAllColors.entrySet()) { + if (colorEntry.getKey() != null) { + dest.writeInt(colorEntry.getKey()); + Integer population = mAllColors.get(colorEntry.getValue()); + int populationInt = (population != null) ? population : 0; + dest.writeInt(populationInt); + } } dest.writeInt(mColorHints); } @@ -476,12 +486,13 @@ public final class WallpaperColors implements Parcelable { WallpaperColors other = (WallpaperColors) o; return mMainColors.equals(other.mMainColors) + && mAllColors.equals(other.mAllColors) && mColorHints == other.mColorHints; } @Override public int hashCode() { - return 31 * mMainColors.hashCode() + mColorHints; + return (31 * mMainColors.hashCode() * mAllColors.hashCode()) + mColorHints; } /** diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl index b0ce6a55e9ba..12911d6e1232 100644 --- a/core/java/android/content/pm/IPackageInstaller.aidl +++ b/core/java/android/content/pm/IPackageInstaller.aidl @@ -62,6 +62,8 @@ interface IPackageInstaller { void bypassNextStagedInstallerCheck(boolean value); + void bypassNextAllowedApexUpdateCheck(boolean value); + void setAllowUnlimitedSilentUpdates(String installerPackageName); void setSilentUpdatesThrottleTime(long throttleTimeInSeconds); } diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index c2ac80e7c98f..d3ed00608324 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -586,11 +586,6 @@ interface IPackageManager { String targetCompilerFilter, boolean force); /** - * Ask the package manager to compile layouts in the given package. - */ - boolean compileLayouts(String packageName); - - /** * Ask the package manager to dump profiles associated with a package. */ void dumpProfiles(String packageName); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 33a34be1b968..2ed00b5d2982 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1278,6 +1278,13 @@ public abstract class PackageManager { */ public static final int INSTALL_STAGED = 0x00200000; + /** + * Flag parameter for {@link #installPackage} to indicate that check whether given APEX can be + * updated should be disabled for this install. + * @hide + */ + public static final int INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK = 0x00400000; + /** @hide */ @IntDef(flag = true, value = { DONT_KILL_APP, diff --git a/core/java/android/content/pm/PackagePartitions.java b/core/java/android/content/pm/PackagePartitions.java index 52ee4de5bed6..d1577684aac6 100644 --- a/core/java/android/content/pm/PackagePartitions.java +++ b/core/java/android/content/pm/PackagePartitions.java @@ -119,6 +119,9 @@ public class PackagePartitions { @Nullable private final DeferredCanonicalFile mOverlayFolder; + @NonNull + private final File mNonConicalFolder; + private SystemPartition(@NonNull File folder, @PartitionType int type, boolean containsPrivApp, boolean containsOverlay) { this.type = type; @@ -128,6 +131,7 @@ public class PackagePartitions { : null; this.mOverlayFolder = containsOverlay ? new DeferredCanonicalFile(folder, "overlay") : null; + this.mNonConicalFolder = folder; } public SystemPartition(@NonNull SystemPartition original) { @@ -136,6 +140,7 @@ public class PackagePartitions { this.mAppFolder = original.mAppFolder; this.mPrivAppFolder = original.mPrivAppFolder; this.mOverlayFolder = original.mOverlayFolder; + this.mNonConicalFolder = original.mNonConicalFolder; } /** @@ -153,6 +158,12 @@ public class PackagePartitions { return mFolder.getFile(); } + /** Returns the non-canonical folder of the partition. */ + @NonNull + public File getNonConicalFolder() { + return mNonConicalFolder; + } + /** Returns the canonical app folder of the partition. */ @Nullable public File getAppFolder() { diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java index 4c44ba1fc9ef..5a7f21040d0a 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java +++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java @@ -1164,7 +1164,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { dest.writeTypedList(this.usesPermissions); sForInternedStringList.parcel(this.implicitPermissions, dest, flags); sForStringSet.parcel(this.upgradeKeySets, dest, flags); - dest.writeMap(this.keySetMapping); + ParsingPackageUtils.writeKeySetMapping(dest, this.keySetMapping); sForInternedStringList.parcel(this.protectedBroadcasts, dest, flags); dest.writeTypedList(this.activities); dest.writeTypedList(this.receivers); @@ -1180,7 +1180,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { sForInternedString.parcel(this.volumeUuid, dest, flags); dest.writeParcelable(this.signingDetails, flags); dest.writeString(this.mPath); - dest.writeParcelableList(this.queriesIntents, flags); + dest.writeTypedList(this.queriesIntents, flags); sForInternedStringList.parcel(this.queriesPackages, dest, flags); sForInternedStringSet.parcel(this.queriesProviders, dest, flags); dest.writeString(this.appComponentFactory); @@ -1287,7 +1287,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { this.usesPermissions = in.createTypedArrayList(ParsedUsesPermission.CREATOR); this.implicitPermissions = sForInternedStringList.unparcel(in); this.upgradeKeySets = sForStringSet.unparcel(in); - this.keySetMapping = in.readHashMap(boot); + this.keySetMapping = ParsingPackageUtils.readKeySetMapping(in); this.protectedBroadcasts = sForInternedStringList.unparcel(in); this.activities = in.createTypedArrayList(ParsedActivity.CREATOR); diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java index 6fd533355aad..dce242c9d87c 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java +++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java @@ -87,6 +87,7 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.FileUtils; +import android.os.Parcel; import android.os.RemoteException; import android.os.Trace; import android.os.UserHandle; @@ -3160,6 +3161,68 @@ public class ParsingPackageUtils { } /** + * Writes the keyset mapping to the provided package. {@code null} mappings are permitted. + */ + public static void writeKeySetMapping(@NonNull Parcel dest, + @NonNull Map<String, ArraySet<PublicKey>> keySetMapping) { + if (keySetMapping == null) { + dest.writeInt(-1); + return; + } + + final int N = keySetMapping.size(); + dest.writeInt(N); + + for (String key : keySetMapping.keySet()) { + dest.writeString(key); + ArraySet<PublicKey> keys = keySetMapping.get(key); + if (keys == null) { + dest.writeInt(-1); + continue; + } + + final int M = keys.size(); + dest.writeInt(M); + for (int j = 0; j < M; j++) { + dest.writeSerializable(keys.valueAt(j)); + } + } + } + + /** + * Reads a keyset mapping from the given parcel at the given data position. May return + * {@code null} if the serialized mapping was {@code null}. + */ + @NonNull + public static ArrayMap<String, ArraySet<PublicKey>> readKeySetMapping(@NonNull Parcel in) { + final int N = in.readInt(); + if (N == -1) { + return null; + } + + ArrayMap<String, ArraySet<PublicKey>> keySetMapping = new ArrayMap<>(); + for (int i = 0; i < N; ++i) { + String key = in.readString(); + final int M = in.readInt(); + if (M == -1) { + keySetMapping.put(key, null); + continue; + } + + ArraySet<PublicKey> keys = new ArraySet<>(M); + for (int j = 0; j < M; ++j) { + PublicKey pk = (PublicKey) in.readSerializable(); + keys.add(pk); + } + + keySetMapping.put(key, keys); + } + + return keySetMapping; + } + + + /** * Callback interface for retrieving information that may be needed while parsing * a package. */ diff --git a/core/java/android/content/pm/parsing/component/ParsedComponent.java b/core/java/android/content/pm/parsing/component/ParsedComponent.java index 4aed77ae641b..9d830ec7a227 100644 --- a/core/java/android/content/pm/parsing/component/ParsedComponent.java +++ b/core/java/android/content/pm/parsing/component/ParsedComponent.java @@ -172,7 +172,7 @@ public abstract class ParsedComponent implements Parcelable { this.packageName = sForInternedString.unparcel(in); this.intents = sForIntentInfos.unparcel(in); this.metaData = in.readBundle(boot); - this.mProperties = in.createTypedArrayMap(Property.CREATOR); + this.mProperties = in.readHashMap(boot); } @NonNull diff --git a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java index 2d46a4073809..e665d0fcc836 100644 --- a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java +++ b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java @@ -208,7 +208,8 @@ public interface BiometricFingerprintConstants { FINGERPRINT_ACQUIRED_TOO_FAST, FINGERPRINT_ACQUIRED_VENDOR, FINGERPRINT_ACQUIRED_START, - FINGERPRINT_ACQUIRED_UNKNOWN}) + FINGERPRINT_ACQUIRED_UNKNOWN, + FINGERPRINT_ACQUIRED_IMMOBILE}) @Retention(RetentionPolicy.SOURCE) @interface FingerprintAcquired {} @@ -278,6 +279,14 @@ public interface BiometricFingerprintConstants { int FINGERPRINT_ACQUIRED_UNKNOWN = 8; /** + * This message may be sent during enrollment if the same area of the finger has already + * been captured during this enrollment session. In general, enrolling multiple areas of the + * same finger can help against false rejections. + * @hide + */ + int FINGERPRINT_ACQUIRED_IMMOBILE = 9; + + /** * @hide */ int FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000; diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java index a39bc4e0bee5..1c0ae281d9fe 100644 --- a/core/java/android/hardware/display/DisplayManagerInternal.java +++ b/core/java/android/hardware/display/DisplayManagerInternal.java @@ -16,6 +16,7 @@ package android.hardware.display; +import android.annotation.IntDef; import android.annotation.Nullable; import android.graphics.Point; import android.hardware.SensorManager; @@ -29,6 +30,9 @@ import android.view.DisplayInfo; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.List; import java.util.Objects; /** @@ -37,6 +41,16 @@ import java.util.Objects; * @hide Only for use within the system server. */ public abstract class DisplayManagerInternal { + + @IntDef(prefix = {"REFRESH_RATE_LIMIT_"}, value = { + REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE + }) + @Retention(RetentionPolicy.SOURCE) + public @interface RefreshRateLimitType {} + + /** Refresh rate should be limited when High Brightness Mode is active. */ + public static final int REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE = 1; + /** * Called by the power manager to initialize power management facilities. */ @@ -296,9 +310,10 @@ public abstract class DisplayManagerInternal { public abstract int getRefreshRateSwitchingType(); /** + * TODO: b/191384041 - Replace this with getRefreshRateLimitations() * Return the refresh rate restriction for the specified display and sensor pairing. If the * specified sensor is identified as an associated sensor in the specified display's - * display-device-config file, then return any refresh rate restrictions that it might specify. + * display-device-config file, then return any refresh rate restrictions that it might define. * If no restriction is specified, or the sensor is not associated with the display, then null * will be returned. * @@ -313,6 +328,15 @@ public abstract class DisplayManagerInternal { int displayId, String name, String type); /** + * Returns a list of various refresh rate limitations for the specified display. + * + * @param displayId The display to get limitations for. + * + * @return a list of {@link RefreshRateLimitation}s describing the various limits. + */ + public abstract List<RefreshRateLimitation> getRefreshRateLimitations(int displayId); + + /** * Describes the requested power state of the display. * * This object is intended to describe the general characteristics of the @@ -613,4 +637,25 @@ public abstract class DisplayManagerInternal { return "(" + min + " " + max + ")"; } } + + /** + * Describes a limitation on a display's refresh rate. Includes the allowed refresh rate + * range as well as information about when it applies, such as high-brightness-mode. + */ + public static final class RefreshRateLimitation { + @RefreshRateLimitType public int type; + + /** The range the that refresh rate should be limited to. */ + public RefreshRateRange range; + + public RefreshRateLimitation(@RefreshRateLimitType int type, float min, float max) { + this.type = type; + range = new RefreshRateRange(min, max); + } + + @Override + public String toString() { + return "RefreshRateLimitation(" + type + ": " + range + ")"; + } + } } diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index 688f9f1174dd..0819835f5fb5 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -1417,6 +1417,9 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing case FINGERPRINT_ACQUIRED_TOO_FAST: return context.getString( com.android.internal.R.string.fingerprint_acquired_too_fast); + case FINGERPRINT_ACQUIRED_IMMOBILE: + return context.getString( + com.android.internal.R.string.fingerprint_acquired_immobile); case FINGERPRINT_ACQUIRED_VENDOR: { String[] msgArray = context.getResources().getStringArray( com.android.internal.R.array.fingerprint_acquired_vendor); diff --git a/core/java/android/hardware/input/InputDeviceVibrator.java b/core/java/android/hardware/input/InputDeviceVibrator.java index d8150e483fd6..653c622386d6 100644 --- a/core/java/android/hardware/input/InputDeviceVibrator.java +++ b/core/java/android/hardware/input/InputDeviceVibrator.java @@ -56,10 +56,10 @@ final class InputDeviceVibrator extends Vibrator { mDeviceId = deviceId; mVibratorInfo = new VibratorInfo.Builder(vibratorId) .setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL) - // Set predefined support to empty as we know input devices do not support them. - .setSupportedEffects() - .setSupportedPrimitives() - .setSupportedBraking() + // The supported effect and braking lists are known to be empty for input devices, + // which is different from not being set (that means the device support is unknown). + .setSupportedEffects(new int[0]) + .setSupportedBraking(new int[0]) .build(); mToken = new Binder(); } diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java index 12538e6cd46b..d7893e4bbefd 100644 --- a/core/java/android/os/Vibrator.java +++ b/core/java/android/os/Vibrator.java @@ -126,6 +126,7 @@ public abstract class Vibrator { // The default vibration intensity level for ringtones. @VibrationIntensity private int mDefaultRingVibrationIntensity; + private float mHapticChannelMaxVibrationAmplitude; /** * @hide to prevent subclassing from outside of the framework @@ -134,7 +135,7 @@ public abstract class Vibrator { public Vibrator() { mPackageName = ActivityThread.currentPackageName(); final Context ctx = ActivityThread.currentActivityThread().getSystemContext(); - loadVibrationIntensities(ctx); + loadVibrationConfig(ctx); } /** @@ -142,22 +143,28 @@ public abstract class Vibrator { */ protected Vibrator(Context context) { mPackageName = context.getOpPackageName(); - loadVibrationIntensities(context); + loadVibrationConfig(context); } - private void loadVibrationIntensities(Context context) { + private void loadVibrationConfig(Context context) { mDefaultHapticFeedbackIntensity = loadDefaultIntensity(context, com.android.internal.R.integer.config_defaultHapticFeedbackIntensity); mDefaultNotificationVibrationIntensity = loadDefaultIntensity(context, com.android.internal.R.integer.config_defaultNotificationVibrationIntensity); mDefaultRingVibrationIntensity = loadDefaultIntensity(context, com.android.internal.R.integer.config_defaultRingVibrationIntensity); + mHapticChannelMaxVibrationAmplitude = loadFloat(context, + com.android.internal.R.dimen.config_hapticChannelMaxVibrationAmplitude, 0); } private int loadDefaultIntensity(Context ctx, int resId) { return ctx != null ? ctx.getResources().getInteger(resId) : VIBRATION_INTENSITY_MEDIUM; } + private float loadFloat(Context ctx, int resId, float defaultValue) { + return ctx != null ? ctx.getResources().getFloat(resId) : defaultValue; + } + /** @hide */ protected VibratorInfo getInfo() { return VibratorInfo.EMPTY_VIBRATOR_INFO; @@ -297,6 +304,24 @@ public abstract class Vibrator { } /** + * Return the maximum amplitude the vibrator can play using the audio haptic channels. + * + * <p>This is a positive value, or {@link Float#NaN NaN} if it's unknown. If this returns a + * positive value <code>maxAmplitude</code>, then the signals from the haptic channels of audio + * tracks should be in the range <code>[-maxAmplitude, maxAmplitude]</code>. + * + * @return a positive value representing the maximum absolute value the device can play signals + * from audio haptic channels, or {@link Float#NaN NaN} if it's unknown. + * @hide + */ + public float getHapticChannelMaximumAmplitude() { + if (mHapticChannelMaxVibrationAmplitude <= 0) { + return Float.NaN; + } + return mHapticChannelMaxVibrationAmplitude; + } + + /** * Configure an always-on haptics effect. * * @param alwaysOnId The board-specific always-on ID to configure. diff --git a/core/java/android/os/VibratorInfo.java b/core/java/android/os/VibratorInfo.java index 597df0811e20..486f9f139e0a 100644 --- a/core/java/android/os/VibratorInfo.java +++ b/core/java/android/os/VibratorInfo.java @@ -51,8 +51,11 @@ public class VibratorInfo implements Parcelable { private final SparseBooleanArray mSupportedEffects; @Nullable private final SparseBooleanArray mSupportedBraking; - @Nullable private final SparseIntArray mSupportedPrimitives; + private final int mPrimitiveDelayMax; + private final int mCompositionSizeMax; + private final int mPwlePrimitiveDurationMax; + private final int mPwleSizeMax; private final float mQFactor; private final FrequencyMapping mFrequencyMapping; @@ -62,6 +65,10 @@ public class VibratorInfo implements Parcelable { mSupportedEffects = in.readSparseBooleanArray(); mSupportedBraking = in.readSparseBooleanArray(); mSupportedPrimitives = in.readSparseIntArray(); + mPrimitiveDelayMax = in.readInt(); + mCompositionSizeMax = in.readInt(); + mPwlePrimitiveDurationMax = in.readInt(); + mPwleSizeMax = in.readInt(); mQFactor = in.readFloat(); mFrequencyMapping = in.readParcelable(VibratorInfo.class.getClassLoader()); } @@ -69,48 +76,50 @@ public class VibratorInfo implements Parcelable { /** * Default constructor. * - * @param id The vibrator id. - * @param capabilities All capability flags of the vibrator, defined in IVibrator.CAP_*. - * @param supportedEffects All supported predefined effects, enum values from {@link - * android.hardware.vibrator.Effect}. - * @param supportedBraking All supported braking types, enum values from {@link Braking}. - * @param supportedPrimitives All supported primitive effects, enum values from {@link - * android.hardware.vibrator.CompositePrimitive}. - * @param primitiveDurations A mapping of primitive durations, where indexes are enum values - * from {@link android.hardware.vibrator.CompositePrimitive} and the - * values are estimated durations in milliseconds. - * @param qFactor The vibrator quality factor. - * @param frequencyMapping The description of the vibrator supported frequencies and max - * amplitude mappings. + * @param id The vibrator id. + * @param capabilities All capability flags of the vibrator, defined in + * IVibrator.CAP_*. + * @param supportedEffects All supported predefined effects, enum values from + * {@link android.hardware.vibrator.Effect}. + * @param supportedBraking All supported braking types, enum values from {@link + * Braking}. + * @param supportedPrimitives All supported primitive effects, key are enum values from + * {@link android.hardware.vibrator.CompositePrimitive} and + * values are estimated durations in milliseconds. + * @param primitiveDelayMax The maximum delay that can be set to a composition primitive + * in milliseconds. + * @param compositionSizeMax The maximum number of primitives supported by a composition. + * @param pwlePrimitiveDurationMax The maximum duration of a PWLE primitive in milliseconds. + * @param pwleSizeMax The maximum number of primitives supported by a PWLE + * composition. + * @param qFactor The vibrator quality factor. + * @param frequencyMapping The description of the vibrator supported frequencies and max + * amplitude mappings. * @hide */ - public VibratorInfo(int id, long capabilities, int[] supportedEffects, int[] supportedBraking, - int[] supportedPrimitives, int[] primitiveDurations, float qFactor, - @NonNull FrequencyMapping frequencyMapping) { + public VibratorInfo(int id, long capabilities, @Nullable SparseBooleanArray supportedEffects, + @Nullable SparseBooleanArray supportedBraking, + @NonNull SparseIntArray supportedPrimitives, int primitiveDelayMax, + int compositionSizeMax, int pwlePrimitiveDurationMax, int pwleSizeMax, + float qFactor, @NonNull FrequencyMapping frequencyMapping) { mId = id; mCapabilities = capabilities; - mSupportedEffects = toSparseBooleanArray(supportedEffects); - mSupportedBraking = toSparseBooleanArray(supportedBraking); - mSupportedPrimitives = toSparseIntArray(supportedPrimitives, primitiveDurations); + mSupportedEffects = supportedEffects == null ? null : supportedEffects.clone(); + mSupportedBraking = supportedBraking == null ? null : supportedBraking.clone(); + mSupportedPrimitives = supportedPrimitives.clone(); + mPrimitiveDelayMax = primitiveDelayMax; + mCompositionSizeMax = compositionSizeMax; + mPwlePrimitiveDurationMax = pwlePrimitiveDurationMax; + mPwleSizeMax = pwleSizeMax; mQFactor = qFactor; mFrequencyMapping = frequencyMapping; } protected VibratorInfo(int id, int capabilities, VibratorInfo baseVibrator) { - mId = id; - mCapabilities = capabilities; - mSupportedEffects = baseVibrator.mSupportedEffects == null ? null : - baseVibrator.mSupportedEffects.clone(); - mSupportedBraking = baseVibrator.mSupportedBraking == null ? null : - baseVibrator.mSupportedBraking.clone(); - mSupportedPrimitives = baseVibrator.mSupportedPrimitives == null ? null : - baseVibrator.mSupportedPrimitives.clone(); - mQFactor = baseVibrator.mQFactor; - mFrequencyMapping = new FrequencyMapping(baseVibrator.mFrequencyMapping.mMinFrequencyHz, - baseVibrator.mFrequencyMapping.mResonantFrequencyHz, - baseVibrator.mFrequencyMapping.mFrequencyResolutionHz, - baseVibrator.mFrequencyMapping.mSuggestedSafeRangeHz, - baseVibrator.mFrequencyMapping.mMaxAmplitudes); + this(id, capabilities, baseVibrator.mSupportedEffects, baseVibrator.mSupportedBraking, + baseVibrator.mSupportedPrimitives, baseVibrator.mPrimitiveDelayMax, + baseVibrator.mCompositionSizeMax, baseVibrator.mPwlePrimitiveDurationMax, + baseVibrator.mPwleSizeMax, baseVibrator.mQFactor, baseVibrator.mFrequencyMapping); } @Override @@ -120,6 +129,10 @@ public class VibratorInfo implements Parcelable { dest.writeSparseBooleanArray(mSupportedEffects); dest.writeSparseBooleanArray(mSupportedBraking); dest.writeSparseIntArray(mSupportedPrimitives); + dest.writeInt(mPrimitiveDelayMax); + dest.writeInt(mCompositionSizeMax); + dest.writeInt(mPwlePrimitiveDurationMax); + dest.writeInt(mPwleSizeMax); dest.writeFloat(mQFactor); dest.writeParcelable(mFrequencyMapping, flags); } @@ -138,24 +151,23 @@ public class VibratorInfo implements Parcelable { return false; } VibratorInfo that = (VibratorInfo) o; - if (mSupportedPrimitives == null || that.mSupportedPrimitives == null) { - if (mSupportedPrimitives != that.mSupportedPrimitives) { + int supportedPrimitivesCount = mSupportedPrimitives.size(); + if (supportedPrimitivesCount != that.mSupportedPrimitives.size()) { + return false; + } + for (int i = 0; i < supportedPrimitivesCount; i++) { + if (mSupportedPrimitives.keyAt(i) != that.mSupportedPrimitives.keyAt(i)) { return false; } - } else { - if (mSupportedPrimitives.size() != that.mSupportedPrimitives.size()) { + if (mSupportedPrimitives.valueAt(i) != that.mSupportedPrimitives.valueAt(i)) { return false; } - for (int i = 0; i < mSupportedPrimitives.size(); i++) { - if (mSupportedPrimitives.keyAt(i) != that.mSupportedPrimitives.keyAt(i)) { - return false; - } - if (mSupportedPrimitives.valueAt(i) != that.mSupportedPrimitives.valueAt(i)) { - return false; - } - } } return mId == that.mId && mCapabilities == that.mCapabilities + && mPrimitiveDelayMax == that.mPrimitiveDelayMax + && mCompositionSizeMax == that.mCompositionSizeMax + && mPwlePrimitiveDurationMax == that.mPwlePrimitiveDurationMax + && mPwleSizeMax == that.mPwleSizeMax && Objects.equals(mSupportedEffects, that.mSupportedEffects) && Objects.equals(mSupportedBraking, that.mSupportedBraking) && Objects.equals(mQFactor, that.mQFactor) @@ -166,11 +178,9 @@ public class VibratorInfo implements Parcelable { public int hashCode() { int hashCode = Objects.hash(mId, mCapabilities, mSupportedEffects, mSupportedBraking, mQFactor, mFrequencyMapping); - if (mSupportedPrimitives != null) { - for (int i = 0; i < mSupportedPrimitives.size(); i++) { - hashCode = 31 * hashCode + mSupportedPrimitives.keyAt(i); - hashCode = 31 * hashCode + mSupportedPrimitives.valueAt(i); - } + for (int i = 0; i < mSupportedPrimitives.size(); i++) { + hashCode = 31 * hashCode + mSupportedPrimitives.keyAt(i); + hashCode = 31 * hashCode + mSupportedPrimitives.valueAt(i); } return hashCode; } @@ -184,6 +194,10 @@ public class VibratorInfo implements Parcelable { + ", mSupportedEffects=" + Arrays.toString(getSupportedEffectsNames()) + ", mSupportedBraking=" + Arrays.toString(getSupportedBrakingNames()) + ", mSupportedPrimitives=" + Arrays.toString(getSupportedPrimitivesNames()) + + ", mPrimitiveDelayMax=" + mPrimitiveDelayMax + + ", mCompositionSizeMax=" + mCompositionSizeMax + + ", mPwlePrimitiveDurationMax=" + mPwlePrimitiveDurationMax + + ", mPwleSizeMax=" + mPwleSizeMax + ", mQFactor=" + mQFactor + ", mFrequencyMapping=" + mFrequencyMapping + '}'; @@ -247,7 +261,7 @@ public class VibratorInfo implements Parcelable { */ public boolean isPrimitiveSupported( @VibrationEffect.Composition.PrimitiveType int primitiveId) { - return hasCapability(IVibrator.CAP_COMPOSE_EFFECTS) && mSupportedPrimitives != null + return hasCapability(IVibrator.CAP_COMPOSE_EFFECTS) && (mSupportedPrimitives.indexOfKey(primitiveId) >= 0); } @@ -260,7 +274,43 @@ public class VibratorInfo implements Parcelable { */ public int getPrimitiveDuration( @VibrationEffect.Composition.PrimitiveType int primitiveId) { - return mSupportedPrimitives != null ? mSupportedPrimitives.get(primitiveId) : 0; + return mSupportedPrimitives.get(primitiveId); + } + + /** + * Query the maximum delay supported for a primitive in a composed effect. + * + * @return The max delay in milliseconds, or zero if unlimited. + */ + public int getPrimitiveDelayMax() { + return mPrimitiveDelayMax; + } + + /** + * Query the maximum number of primitives supported in a composed effect. + * + * @return The max number of primitives supported, or zero if unlimited. + */ + public int getCompositionSizeMax() { + return mCompositionSizeMax; + } + + /** + * Query the maximum duration supported for a primitive in a PWLE composition. + * + * @return The max duration in milliseconds, or zero if unlimited. + */ + public int getPwlePrimitiveDurationMax() { + return mPwlePrimitiveDurationMax; + } + + /** + * Query the maximum number of primitives supported in a PWLE composition. + * + * @return The max number of primitives supported, or zero if unlimited. + */ + public int getPwleSizeMax() { + return mPwleSizeMax; } /** @@ -408,52 +458,15 @@ public class VibratorInfo implements Parcelable { } private String[] getSupportedPrimitivesNames() { - if (mSupportedPrimitives == null) { - return new String[0]; - } - String[] names = new String[mSupportedPrimitives.size()]; - for (int i = 0; i < mSupportedPrimitives.size(); i++) { + int supportedPrimitivesCount = mSupportedPrimitives.size(); + String[] names = new String[supportedPrimitivesCount]; + for (int i = 0; i < supportedPrimitivesCount; i++) { names[i] = VibrationEffect.Composition.primitiveToString(mSupportedPrimitives.keyAt(i)); } return names; } /** - * Create a {@link SparseBooleanArray} from given {@code supportedKeys} where each key is mapped - * to {@code true}. - */ - @Nullable - private static SparseBooleanArray toSparseBooleanArray(int[] supportedKeys) { - if (supportedKeys == null) { - return null; - } - SparseBooleanArray array = new SparseBooleanArray(); - for (int key : supportedKeys) { - array.put(key, true); - } - return array; - } - - /** - * Create a {@link SparseIntArray} from given {@code supportedKeys} where each key is mapped - * to the value indexed by it. - * - * <p>If {@code values} is null or does not contain a given key as a index, then zero is stored - * to the sparse array so it can still be used to query the supported keys. - */ - @Nullable - private static SparseIntArray toSparseIntArray(int[] supportedKeys, int[] values) { - if (supportedKeys == null) { - return null; - } - SparseIntArray array = new SparseIntArray(); - for (int key : supportedKeys) { - array.put(key, (values == null || key >= values.length) ? 0 : values[key]); - } - return array; - } - - /** * Describes how frequency should be mapped to absolute values for a specific {@link Vibrator}. * * <p>This mapping is defined by the following parameters: @@ -675,11 +688,14 @@ public class VibratorInfo implements Parcelable { /** @hide */ public static final class Builder { private final int mId; - private int mCapabilities = 0; - private int[] mSupportedEffects = null; - private int[] mSupportedBraking = null; - private int[] mSupportedPrimitives = null; - private int[] mPrimitiveDurations = new int[0]; + private long mCapabilities; + private SparseBooleanArray mSupportedEffects; + private SparseBooleanArray mSupportedBraking; + private SparseIntArray mSupportedPrimitives = new SparseIntArray(); + private int mPrimitiveDelayMax; + private int mCompositionSizeMax; + private int mPwlePrimitiveDurationMax; + private int mPwleSizeMax; private float mQFactor = Float.NaN; private FrequencyMapping mFrequencyMapping = new FrequencyMapping(Float.NaN, Float.NaN, Float.NaN, Float.NaN, null); @@ -691,7 +707,7 @@ public class VibratorInfo implements Parcelable { /** Configure the vibrator capabilities with a combination of IVibrator.CAP_* values. */ @NonNull - public Builder setCapabilities(int capabilities) { + public Builder setCapabilities(long capabilities) { mCapabilities = capabilities; return this; } @@ -699,34 +715,49 @@ public class VibratorInfo implements Parcelable { /** Configure the effects supported with {@link android.hardware.vibrator.Effect} values. */ @NonNull public Builder setSupportedEffects(int... supportedEffects) { - mSupportedEffects = supportedEffects; + mSupportedEffects = toSparseBooleanArray(supportedEffects); return this; } /** Configure braking supported with {@link android.hardware.vibrator.Braking} values. */ @NonNull public Builder setSupportedBraking(int... supportedBraking) { - mSupportedBraking = supportedBraking; + mSupportedBraking = toSparseBooleanArray(supportedBraking); return this; } - /** - * Configure the primitives supported with - * {@link android.hardware.vibrator.CompositePrimitive} values. - */ + /** Configure maximum duration, in milliseconds, of a PWLE primitive. */ + @NonNull + public Builder setPwlePrimitiveDurationMax(int pwlePrimitiveDurationMax) { + mPwlePrimitiveDurationMax = pwlePrimitiveDurationMax; + return this; + } + + /** Configure maximum number of primitives supported in a single PWLE composed effect. */ @NonNull - public Builder setSupportedPrimitives(int... supportedPrimitives) { - mSupportedPrimitives = supportedPrimitives; + public Builder setPwleSizeMax(int pwleSizeMax) { + mPwleSizeMax = pwleSizeMax; return this; } /** Configure the duration of a {@link android.hardware.vibrator.CompositePrimitive}. */ @NonNull - public Builder setPrimitiveDuration(int primitiveId, int duration) { - if (mPrimitiveDurations.length <= primitiveId) { - mPrimitiveDurations = Arrays.copyOf(mPrimitiveDurations, primitiveId + 1); - } - mPrimitiveDurations[primitiveId] = duration; + public Builder setSupportedPrimitive(int primitiveId, int duration) { + mSupportedPrimitives.put(primitiveId, duration); + return this; + } + + /** Configure maximum delay, in milliseconds, supported in a composed effect primitive. */ + @NonNull + public Builder setPrimitiveDelayMax(int primitiveDelayMax) { + mPrimitiveDelayMax = primitiveDelayMax; + return this; + } + + /** Configure maximum number of primitives supported in a single composed effect. */ + @NonNull + public Builder setCompositionSizeMax(int compositionSizeMax) { + mCompositionSizeMax = compositionSizeMax; return this; } @@ -748,7 +779,25 @@ public class VibratorInfo implements Parcelable { @NonNull public VibratorInfo build() { return new VibratorInfo(mId, mCapabilities, mSupportedEffects, mSupportedBraking, - mSupportedPrimitives, mPrimitiveDurations, mQFactor, mFrequencyMapping); + mSupportedPrimitives, mPrimitiveDelayMax, mCompositionSizeMax, + mPwlePrimitiveDurationMax, mPwleSizeMax, mQFactor, mFrequencyMapping); + } + + /** + * Create a {@link SparseBooleanArray} from given {@code supportedKeys} where each key is + * mapped + * to {@code true}. + */ + @Nullable + private static SparseBooleanArray toSparseBooleanArray(int[] supportedKeys) { + if (supportedKeys == null) { + return null; + } + SparseBooleanArray array = new SparseBooleanArray(); + for (int key : supportedKeys) { + array.put(key, true); + } + return array; } } diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java index 0b11aeb1ed65..3b4f7e241852 100644 --- a/core/java/android/security/keymaster/KeymasterDefs.java +++ b/core/java/android/security/keymaster/KeymasterDefs.java @@ -124,7 +124,6 @@ public final class KeymasterDefs { public static final int KM_TAG_DEVICE_UNIQUE_ATTESTATION = Tag.DEVICE_UNIQUE_ATTESTATION; // KM_BOOL | 720; - public static final int KM_TAG_ASSOCIATED_DATA = Tag.ASSOCIATED_DATA; // KM_BYTES | 1000; public static final int KM_TAG_NONCE = Tag.NONCE; // KM_BYTES | 1001; public static final int KM_TAG_MAC_LENGTH = Tag.MAC_LENGTH; // KM_UINT | 1003; public static final int KM_TAG_RESET_SINCE_ID_ROTATION = diff --git a/core/java/android/service/translation/TranslationService.java b/core/java/android/service/translation/TranslationService.java index e1d4a5656b39..93c006aff435 100644 --- a/core/java/android/service/translation/TranslationService.java +++ b/core/java/android/service/translation/TranslationService.java @@ -361,6 +361,11 @@ public abstract class TranslationService extends Service { new Consumer<Set<TranslationCapability>>() { @Override public void accept(Set<TranslationCapability> values) { + if (!isValidCapabilities(sourceFormat, targetFormat, values)) { + throw new IllegalStateException("Invalid capabilities and " + + "format compatibility"); + } + final ArraySet<TranslationCapability> capabilities = new ArraySet<>(values); final Bundle bundle = new Bundle(); bundle.putParcelableArray(TranslationManager.EXTRA_CAPABILITIES, @@ -369,4 +374,23 @@ public abstract class TranslationService extends Service { } }); } + + /** + * Helper method to validate capabilities and format compatibility. + */ + private boolean isValidCapabilities(@TranslationSpec.DataFormat int sourceFormat, + @TranslationSpec.DataFormat int targetFormat, Set<TranslationCapability> capabilities) { + if (sourceFormat != TranslationSpec.DATA_FORMAT_TEXT + && targetFormat != TranslationSpec.DATA_FORMAT_TEXT) { + return true; + } + + for (TranslationCapability capability : capabilities) { + if (capability.getState() == TranslationCapability.STATE_REMOVED_AND_AVAILABLE) { + return false; + } + } + + return true; + } } diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java index 67b97cee1b51..41374167cc56 100644 --- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java +++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java @@ -263,6 +263,7 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector { private static final int MSG_DETECTION_RESUME = 5; private static final int MSG_HOTWORD_REJECTED = 6; private static final int MSG_HOTWORD_STATUS_REPORTED = 7; + private static final int MSG_PROCESS_RESTARTED = 8; private final String mText; private final Locale mLocale; @@ -1212,6 +1213,12 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector { message.arg1 = status; message.sendToTarget(); } + + @Override + public void onProcessRestarted() { + Slog.i(TAG, "onProcessRestarted"); + mHandler.sendEmptyMessage(MSG_PROCESS_RESTARTED); + } } class MyHandler extends Handler { @@ -1246,6 +1253,9 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector { case MSG_HOTWORD_STATUS_REPORTED: mExternalCallback.onHotwordDetectionServiceInitialized(msg.arg1); break; + case MSG_PROCESS_RESTARTED: + mExternalCallback.onHotwordDetectionServiceRestarted(); + break; default: super.handleMessage(msg); } diff --git a/core/java/android/service/voice/HotwordDetectionService.java b/core/java/android/service/voice/HotwordDetectionService.java index b66d93d6316e..93a7ec793536 100644 --- a/core/java/android/service/voice/HotwordDetectionService.java +++ b/core/java/android/service/voice/HotwordDetectionService.java @@ -291,9 +291,7 @@ public abstract class HotwordDetectionService extends Service { @Nullable PersistableBundle options, @Nullable SharedMemory sharedMemory, @DurationMillisLong long callbackTimeoutMillis, - @Nullable IntConsumer statusCallback) { - // TODO: Handle the unimplemented case by throwing? - } + @Nullable IntConsumer statusCallback) {} /** * Called when the {@link VoiceInteractionService} requests that this service diff --git a/core/java/android/service/voice/SoftwareHotwordDetector.java b/core/java/android/service/voice/SoftwareHotwordDetector.java index 204e7df89706..fb540b1622e6 100644 --- a/core/java/android/service/voice/SoftwareHotwordDetector.java +++ b/core/java/android/service/voice/SoftwareHotwordDetector.java @@ -122,7 +122,7 @@ class SoftwareHotwordDetector extends AbstractHotwordDetector { this.mCallback = callback; } - /** TODO: onDetected */ + /** Called when the detected result is valid. */ @Override public void onDetected( @Nullable HotwordDetectedResult hotwordDetectedResult, @@ -150,33 +150,45 @@ class SoftwareHotwordDetector extends AbstractHotwordDetector { public void onKeyphraseDetected( SoundTrigger.KeyphraseRecognitionEvent recognitionEvent, HotwordDetectedResult result) { - + if (DEBUG) { + Slog.i(TAG, "Ignored #onKeyphraseDetected event"); + } } @Override public void onGenericSoundTriggerDetected( SoundTrigger.GenericRecognitionEvent recognitionEvent) throws RemoteException { - + if (DEBUG) { + Slog.i(TAG, "Ignored #onGenericSoundTriggerDetected event"); + } } @Override public void onRejected(HotwordRejectedResult result) throws RemoteException { - + if (DEBUG) { + Slog.i(TAG, "Ignored #onRejected event"); + } } @Override public void onError(int status) throws RemoteException { - + if (DEBUG) { + Slog.i(TAG, "Ignored #onError (" + status + ") event"); + } } @Override public void onRecognitionPaused() throws RemoteException { - + if (DEBUG) { + Slog.i(TAG, "Ignored #onRecognitionPaused event"); + } } @Override public void onRecognitionResumed() throws RemoteException { - + if (DEBUG) { + Slog.i(TAG, "Ignored #onRecognitionResumed event"); + } } @Override @@ -187,6 +199,14 @@ class SoftwareHotwordDetector extends AbstractHotwordDetector { mCallback, status)); } + + @Override + public void onProcessRestarted() throws RemoteException { + Slog.v(TAG, "onProcessRestarted()"); + mHandler.sendMessage(obtainMessage( + HotwordDetector.Callback::onHotwordDetectionServiceRestarted, + mCallback)); + } } /** @hide */ diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index 8080883c2b3e..145607ada4f4 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -1265,7 +1265,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } stateChanged |= getSourceConsumer(types.valueAt(j)).notifyAnimationFinished(); } - if (invokeCallback && runningAnimation.startDispatched) { + if (invokeCallback) { dispatchAnimationEnd(runningAnimation.runner.getAnimation()); } break; diff --git a/core/java/android/view/ScrollCaptureTarget.java b/core/java/android/view/ScrollCaptureTarget.java index 44017ed0d831..a8bb037af5f9 100644 --- a/core/java/android/view/ScrollCaptureTarget.java +++ b/core/java/android/view/ScrollCaptureTarget.java @@ -21,13 +21,10 @@ import static java.util.Objects.requireNonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UiThread; -import android.graphics.Matrix; import android.graphics.Point; import android.graphics.Rect; import android.os.CancellationSignal; -import com.android.internal.util.FastMath; - import java.io.PrintWriter; import java.util.function.Consumer; @@ -43,8 +40,7 @@ public final class ScrollCaptureTarget { private final int mHint; private Rect mScrollBounds; - private final float[] mTmpFloatArr = new float[2]; - private final Matrix mMatrixViewLocalToWindow = new Matrix(); + private final int[] mTmpIntArr = new int[2]; public ScrollCaptureTarget(@NonNull View scrollTarget, @NonNull Rect localVisibleRect, @NonNull Point positionInWindow, @NonNull ScrollCaptureCallback callback) { @@ -117,28 +113,15 @@ public final class ScrollCaptureTarget { } } - private static void zero(float[] pointArray) { - pointArray[0] = 0; - pointArray[1] = 0; - } - - private static void roundIntoPoint(Point pointObj, float[] pointArray) { - pointObj.x = FastMath.round(pointArray[0]); - pointObj.y = FastMath.round(pointArray[1]); - } - /** - * Refresh the local visible bounds and it's offset within the window, based on the current + * Refresh the local visible bounds and its offset within the window, based on the current * state of the {@code containing view}. */ @UiThread public void updatePositionInWindow() { - mMatrixViewLocalToWindow.reset(); - mContainingView.transformMatrixToGlobal(mMatrixViewLocalToWindow); - - zero(mTmpFloatArr); - mMatrixViewLocalToWindow.mapPoints(mTmpFloatArr); - roundIntoPoint(mPositionInWindow, mTmpFloatArr); + mContainingView.getLocationInWindow(mTmpIntArr); + mPositionInWindow.x = mTmpIntArr[0]; + mPositionInWindow.y = mTmpIntArr[1]; } public String toString() { diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index f34cd8f9de50..4e66ceb76a60 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -233,6 +233,7 @@ public final class SurfaceControl implements Parcelable { private static native void nativeRemoveJankDataListener(long nativeListener); private static native long nativeCreateJankDataListenerWrapper(OnJankDataListener listener); private static native int nativeGetGPUContextPriority(); + private static native void nativeSetTransformHint(long nativeObject, int transformHint); @Nullable @GuardedBy("mLock") @@ -348,6 +349,8 @@ public final class SurfaceControl implements Parcelable { @GuardedBy("mLock") private int mHeight; + private int mTransformHint; + private WeakReference<View> mLocalOwnerView; static GlobalTransactionWrapper sGlobalTransaction; @@ -605,6 +608,7 @@ public final class SurfaceControl implements Parcelable { mName = other.mName; mWidth = other.mWidth; mHeight = other.mHeight; + mTransformHint = other.mTransformHint; mLocalOwnerView = other.mLocalOwnerView; assignNativeObject(nativeCopyFromSurfaceControl(other.mNativeObject), callsite); } @@ -1467,6 +1471,7 @@ public final class SurfaceControl implements Parcelable { mName = in.readString8(); mWidth = in.readInt(); mHeight = in.readInt(); + mTransformHint = in.readInt(); long object = 0; if (in.readInt() != 0) { @@ -1485,6 +1490,7 @@ public final class SurfaceControl implements Parcelable { dest.writeString8(mName); dest.writeInt(mWidth); dest.writeInt(mHeight); + dest.writeInt(mTransformHint); if (mNativeObject == 0) { dest.writeInt(0); } else { @@ -3602,4 +3608,27 @@ public final class SurfaceControl implements Parcelable { mHeight = h; nativeUpdateDefaultBufferSize(mNativeObject, w, h); } + + /** + * @hide + */ + public int getTransformHint() { + return mTransformHint; + } + + /** + * Update the transform hint of current SurfaceControl. Only affect if type is + * {@link #FX_SURFACE_BLAST} + * + * The transform hint is used to prevent allocating a buffer of different size when a + * layer is rotated. The producer can choose to consume the hint and allocate the buffer + * with the same size. + * @hide + */ + public void setTransformHint(@Surface.Rotation int transformHint) { + if (mTransformHint != transformHint) { + mTransformHint = transformHint; + nativeSetTransformHint(mNativeObject, transformHint); + } + } } diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 6b0bb9df5468..4f2cf6d9001e 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -30,7 +30,6 @@ import android.graphics.BLASTBufferQueue; import android.graphics.BlendMode; import android.graphics.Canvas; import android.graphics.Color; -import android.graphics.HardwareRenderer; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PixelFormat; @@ -214,6 +213,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) final Rect mSurfaceFrame = new Rect(); int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1; + int mTransformHint = 0; private boolean mGlobalListenersAdded; private boolean mAttachedToWindow; @@ -944,7 +944,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } private boolean performSurfaceTransaction(ViewRootImpl viewRoot, Translator translator, - boolean creating, boolean sizeChanged) { + boolean creating, boolean sizeChanged, boolean hintChanged) { boolean realSizeChanged = false; mSurfaceLock.lock(); @@ -1009,7 +1009,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } } mTmpTransaction.setCornerRadius(mSurfaceControl, mCornerRadius); - if (sizeChanged && !creating) { + if ((sizeChanged || hintChanged) && !creating) { setBufferSize(mTmpTransaction); } @@ -1081,17 +1081,18 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall || mWindowSpaceTop != mLocation[1]; final boolean layoutSizeChanged = getWidth() != mScreenRect.width() || getHeight() != mScreenRect.height(); - + final boolean hintChanged = viewRoot.getSurfaceTransformHint() != mTransformHint; if (creating || formatChanged || sizeChanged || visibleChanged || (mUseAlpha && alphaChanged) || windowVisibleChanged || - positionChanged || layoutSizeChanged) { + positionChanged || layoutSizeChanged || hintChanged) { getLocationInWindow(mLocation); if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Changes: creating=" + creating + " format=" + formatChanged + " size=" + sizeChanged + " visible=" + visibleChanged + " alpha=" + alphaChanged + + " hint=" + hintChanged + " mUseAlpha=" + mUseAlpha + " visible=" + visibleChanged + " left=" + (mWindowSpaceLeft != mLocation[0]) @@ -1105,6 +1106,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mSurfaceHeight = myHeight; mFormat = mRequestedFormat; mLastWindowVisibility = mWindowVisibility; + mTransformHint = viewRoot.getSurfaceTransformHint(); mScreenRect.left = mWindowSpaceLeft; mScreenRect.top = mWindowSpaceTop; @@ -1130,9 +1132,9 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } final boolean realSizeChanged = performSurfaceTransaction(viewRoot, - translator, creating, sizeChanged); - final boolean redrawNeeded = sizeChanged || creating || - (mVisible && !mDrawFinished); + translator, creating, sizeChanged, hintChanged); + final boolean redrawNeeded = sizeChanged || creating || hintChanged + || (mVisible && !mDrawFinished); try { SurfaceHolder.Callback[] callbacks = null; @@ -1158,7 +1160,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall c.surfaceCreated(mSurfaceHolder); } } - if (creating || formatChanged || sizeChanged + if (creating || formatChanged || sizeChanged || hintChanged || visibleChanged || realSizeChanged) { if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "surfaceChanged -- format=" + mFormat @@ -1234,6 +1236,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall private void setBufferSize(Transaction transaction) { if (mUseBlastAdapter) { + mBlastSurfaceControl.setTransformHint(mTransformHint); mBlastBufferQueue.update(mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight, mFormat); } else { transaction.setBufferSize(mSurfaceControl, mSurfaceWidth, mSurfaceHeight); @@ -1330,6 +1333,8 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall if (mBlastBufferQueue != null) { mBlastBufferQueue.destroy(); } + mTransformHint = viewRoot.getSurfaceTransformHint(); + mBlastSurfaceControl.setTransformHint(mTransformHint); mBlastBufferQueue = new BLASTBufferQueue(name, mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight, mFormat); } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index cf8c746d6ecb..573ae998305e 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -10382,4 +10382,8 @@ public final class ViewRootImpl implements ViewParent, }); return true; } + + int getSurfaceTransformHint() { + return mSurfaceControl.getTransformHint(); + } } diff --git a/core/java/android/view/ViewRootInsetsControllerHost.java b/core/java/android/view/ViewRootInsetsControllerHost.java index d8cd6056de90..27821fd6608d 100644 --- a/core/java/android/view/ViewRootInsetsControllerHost.java +++ b/core/java/android/view/ViewRootInsetsControllerHost.java @@ -110,6 +110,10 @@ public class ViewRootInsetsControllerHost implements InsetsController.Host { @Override public void dispatchWindowInsetsAnimationEnd(@NonNull WindowInsetsAnimation animation) { if (DEBUG) Log.d(TAG, "windowInsetsAnimation ended"); + if (mViewRoot.mView == null) { + // The view has already detached from window. + return; + } mViewRoot.mView.dispatchWindowInsetsAnimationEnd(animation); } diff --git a/core/java/android/view/WindowInsetsAnimation.java b/core/java/android/view/WindowInsetsAnimation.java index ab5b5ba51a6e..6576eea40496 100644 --- a/core/java/android/view/WindowInsetsAnimation.java +++ b/core/java/android/view/WindowInsetsAnimation.java @@ -360,6 +360,13 @@ public final class WindowInsetsAnimation { * finished, and then revert to the starting state of the animation in the first * {@link #onProgress} callback by using post-layout view properties like {@link View#setX} * and related methods. + * + * <p>Note that the animation might be cancelled before {@link #onStart} is dispatched. On + * {@link android.os.Build.VERSION_CODES#S S} and later, {@link #onEnd} is immediately + * dispatched without an {@link #onStart} in that case. + * On {@link android.os.Build.VERSION_CODES#R R}, no callbacks are dispatched after + * {@code #onPrepare} for such an animation. + * * <p> * Note: If the animation is application controlled by using * {@link WindowInsetsController#controlWindowInsetsAnimation}, the end state of the diff --git a/core/java/android/view/translation/TranslationCapability.java b/core/java/android/view/translation/TranslationCapability.java index d104b2427c8e..65b749add1b2 100644 --- a/core/java/android/view/translation/TranslationCapability.java +++ b/core/java/android/view/translation/TranslationCapability.java @@ -61,6 +61,13 @@ public final class TranslationCapability implements Parcelable { * was dropped.</p> */ public static final @ModelState int STATE_NOT_AVAILABLE = 4; + /** + * The translation between the source and target specs were removed from the system, but is + * still available to be downloaded again. + * + * @hide + */ + public static final @ModelState int STATE_REMOVED_AND_AVAILABLE = 1000; /** * The state of translation readiness between {@code mSourceSpec} and {@code mTargetSpec}. @@ -134,7 +141,8 @@ public final class TranslationCapability implements Parcelable { STATE_AVAILABLE_TO_DOWNLOAD, STATE_DOWNLOADING, STATE_ON_DEVICE, - STATE_NOT_AVAILABLE + STATE_NOT_AVAILABLE, + STATE_REMOVED_AND_AVAILABLE }) @Retention(RetentionPolicy.SOURCE) @DataClass.Generated.Member @@ -152,6 +160,8 @@ public final class TranslationCapability implements Parcelable { return "STATE_ON_DEVICE"; case STATE_NOT_AVAILABLE: return "STATE_NOT_AVAILABLE"; + case STATE_REMOVED_AND_AVAILABLE: + return "STATE_REMOVED_AND_AVAILABLE"; default: return Integer.toHexString(value); } } @@ -255,13 +265,15 @@ public final class TranslationCapability implements Parcelable { if (!(mState == STATE_AVAILABLE_TO_DOWNLOAD) && !(mState == STATE_DOWNLOADING) && !(mState == STATE_ON_DEVICE) - && !(mState == STATE_NOT_AVAILABLE)) { + && !(mState == STATE_NOT_AVAILABLE) + && !(mState == STATE_REMOVED_AND_AVAILABLE)) { throw new java.lang.IllegalArgumentException( "state was " + mState + " but must be one of: " + "STATE_AVAILABLE_TO_DOWNLOAD(" + STATE_AVAILABLE_TO_DOWNLOAD + "), " + "STATE_DOWNLOADING(" + STATE_DOWNLOADING + "), " + "STATE_ON_DEVICE(" + STATE_ON_DEVICE + "), " - + "STATE_NOT_AVAILABLE(" + STATE_NOT_AVAILABLE + ")"); + + "STATE_NOT_AVAILABLE(" + STATE_NOT_AVAILABLE + "), " + + "STATE_REMOVED_AND_AVAILABLE(" + STATE_REMOVED_AND_AVAILABLE + ")"); } this.mSourceSpec = sourceSpec; @@ -293,10 +305,10 @@ public final class TranslationCapability implements Parcelable { }; @DataClass.Generated( - time = 1621545303074L, + time = 1624307114468L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/view/translation/TranslationCapability.java", - inputSignatures = "public static final @android.view.translation.TranslationCapability.ModelState int STATE_AVAILABLE_TO_DOWNLOAD\npublic static final @android.view.translation.TranslationCapability.ModelState int STATE_DOWNLOADING\npublic static final @android.view.translation.TranslationCapability.ModelState int STATE_ON_DEVICE\npublic static final @android.view.translation.TranslationCapability.ModelState int STATE_NOT_AVAILABLE\nprivate final @android.view.translation.TranslationCapability.ModelState int mState\nprivate final @android.annotation.NonNull android.view.translation.TranslationSpec mSourceSpec\nprivate final @android.annotation.NonNull android.view.translation.TranslationSpec mTargetSpec\nprivate final boolean mUiTranslationEnabled\nprivate final @android.view.translation.TranslationContext.TranslationFlag int mSupportedTranslationFlags\nclass TranslationCapability extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstDefs=true, genToString=true, genConstructor=false)") + inputSignatures = "public static final @android.view.translation.TranslationCapability.ModelState int STATE_AVAILABLE_TO_DOWNLOAD\npublic static final @android.view.translation.TranslationCapability.ModelState int STATE_DOWNLOADING\npublic static final @android.view.translation.TranslationCapability.ModelState int STATE_ON_DEVICE\npublic static final @android.view.translation.TranslationCapability.ModelState int STATE_NOT_AVAILABLE\npublic static final @android.view.translation.TranslationCapability.ModelState int STATE_REMOVED_AND_AVAILABLE\nprivate final @android.view.translation.TranslationCapability.ModelState int mState\nprivate final @android.annotation.NonNull android.view.translation.TranslationSpec mSourceSpec\nprivate final @android.annotation.NonNull android.view.translation.TranslationSpec mTargetSpec\nprivate final boolean mUiTranslationEnabled\nprivate final @android.view.translation.TranslationContext.TranslationFlag int mSupportedTranslationFlags\nclass TranslationCapability extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstDefs=true, genToString=true, genConstructor=false)") @Deprecated private void __metadata() {} diff --git a/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl b/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl index ec99c95a737c..d0214e6e0082 100644 --- a/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl +++ b/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl @@ -78,4 +78,7 @@ oneway interface IHotwordRecognitionStatusCallback { * @param status The status about the result of requesting update state action. */ void onStatusReported(int status); + + /** Called when the hotword detection process is restarted */ + void onProcessRestarted(); } diff --git a/core/java/com/android/internal/content/om/OverlayConfig.java b/core/java/com/android/internal/content/om/OverlayConfig.java index b38f623e3a6d..3f3c9bdbe5f5 100644 --- a/core/java/com/android/internal/content/om/OverlayConfig.java +++ b/core/java/com/android/internal/content/om/OverlayConfig.java @@ -111,7 +111,7 @@ public class OverlayConfig { // Rebase the system partitions and settings file on the specified root directory. partitions = new ArrayList<>(PackagePartitions.getOrderedPartitions( p -> new OverlayPartition( - new File(rootDirectory, p.getFolder().getPath()), + new File(rootDirectory, p.getNonConicalFolder().getPath()), p))); } diff --git a/core/java/com/android/internal/infra/ServiceConnector.java b/core/java/com/android/internal/infra/ServiceConnector.java index af21f8183d3a..9ced6097804d 100644 --- a/core/java/com/android/internal/infra/ServiceConnector.java +++ b/core/java/com/android/internal/infra/ServiceConnector.java @@ -228,7 +228,7 @@ public interface ServiceConnector<I extends IInterface> { private final int mBindingFlags; private final @Nullable Function<IBinder, I> mBinderAsInterface; private final @NonNull Handler mHandler; - private final @NonNull Executor mExecutor; + protected final @NonNull Executor mExecutor; private volatile I mService = null; private boolean mBinding = false; diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 945a6ab11856..dab3e9fa15fa 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -12141,6 +12141,15 @@ public class BatteryStatsImpl extends BatteryStats { } } } + + void reset() { + idleTimeMs = 0; + rxTimeMs = 0; + txTimeMs = 0; + energy = 0; + uidRxBytes.clear(); + uidTxBytes.clear(); + } } private final BluetoothActivityInfoCache mLastBluetoothActivityInfo @@ -12167,6 +12176,15 @@ public class BatteryStatsImpl extends BatteryStats { mHasBluetoothReporting = true; + if (info.getControllerRxTimeMillis() < mLastBluetoothActivityInfo.rxTimeMs + || info.getControllerTxTimeMillis() < mLastBluetoothActivityInfo.txTimeMs + || info.getControllerIdleTimeMillis() < mLastBluetoothActivityInfo.idleTimeMs + || info.getControllerEnergyUsed() < mLastBluetoothActivityInfo.energy) { + // A drop in accumulated Bluetooth stats is a sign of a Bluetooth crash. + // Reset the preserved previous snapshot in order to restart accumulating deltas. + mLastBluetoothActivityInfo.reset(); + } + final long rxTimeMs = info.getControllerRxTimeMillis() - mLastBluetoothActivityInfo.rxTimeMs; final long txTimeMs = diff --git a/core/java/com/android/internal/view/ScrollCaptureViewSupport.java b/core/java/com/android/internal/view/ScrollCaptureViewSupport.java index 8aa2d57e8ea6..9e09006f608d 100644 --- a/core/java/com/android/internal/view/ScrollCaptureViewSupport.java +++ b/core/java/com/android/internal/view/ScrollCaptureViewSupport.java @@ -198,12 +198,9 @@ public class ScrollCaptureViewSupport<V extends View> implements ScrollCaptureCa private static final float LIGHT_RADIUS_DP = 800; private static final String TAG = "ViewRenderer"; - private HardwareRenderer mRenderer; - private RenderNode mCaptureRenderNode; - private final RectF mTempRectF = new RectF(); - private final Rect mSourceRect = new Rect(); + private final HardwareRenderer mRenderer; + private final RenderNode mCaptureRenderNode; private final Rect mTempRect = new Rect(); - private final Matrix mTempMatrix = new Matrix(); private final int[] mTempLocation = new int[2]; private long mLastRenderedSourceDrawingId = -1; private Surface mSurface; @@ -313,11 +310,9 @@ public class ScrollCaptureViewSupport<V extends View> implements ScrollCaptureCa } private void transformToRoot(View local, Rect localRect, Rect outRect) { - mTempMatrix.reset(); - local.transformMatrixToGlobal(mTempMatrix); - mTempRectF.set(localRect); - mTempMatrix.mapRect(mTempRectF); - mTempRectF.round(outRect); + local.getLocationInWindow(mTempLocation); + outRect.set(localRect); + outRect.offset(mTempLocation[0], mTempLocation[1]); } public void setColorMode(@ColorMode int colorMode) { diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java index bd0de2984b7f..6976ace36c11 100644 --- a/core/java/com/android/server/SystemConfig.java +++ b/core/java/com/android/server/SystemConfig.java @@ -240,6 +240,7 @@ public class SystemConfig { private final ArraySet<String> mRollbackWhitelistedPackages = new ArraySet<>(); private final ArraySet<String> mWhitelistedStagedInstallers = new ArraySet<>(); + private final ArraySet<String> mAllowedPartnerApexes = new ArraySet<>(); /** * Map of system pre-defined, uniquely named actors; keys are namespace, @@ -410,6 +411,10 @@ public class SystemConfig { return mWhitelistedStagedInstallers; } + public Set<String> getAllowedPartnerApexes() { + return mAllowedPartnerApexes; + } + public ArraySet<String> getAppDataIsolationWhitelistedApps() { return mAppDataIsolationWhitelistedApps; } @@ -1212,6 +1217,21 @@ public class SystemConfig { } XmlUtils.skipCurrentTag(parser); } break; + case "allowed-partner-apex": { + // TODO(b/189274479): should this be allowOemPermissions instead? + if (allowAppConfigs) { + String pkgName = parser.getAttributeValue(null, "package"); + if (pkgName == null) { + Slog.w(TAG, "<" + name + "> without package in " + permFile + + " at " + parser.getPositionDescription()); + } else { + mAllowedPartnerApexes.add(pkgName); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; default: { Slog.w(TAG, "Tag " + name + " is unknown in " + permFile + " at " + parser.getPositionDescription()); diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index d528428a0e83..e9e79dc30c20 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -1775,6 +1775,16 @@ static jint nativeGetGPUContextPriority(JNIEnv* env, jclass clazz) { return static_cast<jint>(SurfaceComposerClient::getGPUContextPriority()); } +static void nativeSetTransformHint(JNIEnv* env, jclass clazz, jlong nativeSurfaceControl, + jint transformHint) { + sp<SurfaceControl> surface(reinterpret_cast<SurfaceControl*>(nativeSurfaceControl)); + if (surface == nullptr) { + return; + } + surface->setTransformHint( + ui::Transform::toRotationFlags(static_cast<ui::Rotation>(transformHint))); +} + // ---------------------------------------------------------------------------- static const JNINativeMethod sSurfaceControlMethods[] = { @@ -1962,6 +1972,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeCreateJankDataListenerWrapper }, {"nativeGetGPUContextPriority", "()I", (void*)nativeGetGPUContextPriority }, + {"nativeSetTransformHint", "(JI)V", + (void*)nativeSetTransformHint }, // clang-format on }; diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 803ba649bd29..cd893185b4f6 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Geen vingerafdrukke is geregistreer nie."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Vinger <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Gebruik vingerafdruk"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Gebruik vingerafdruk of skermslot"</string> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index e5ef55a2459b..b261c461cd5e 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ምንም የጣት አሻራዎች አልተመዘገቡም።"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ይህ መሣሪያ የጣት አሻራ ዳሳሽ የለውም።"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ዳሳሽ ለጊዜው ተሰናክሏል።"</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 86a09ee9643b..b38bf9f93d73 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -613,6 +613,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ليست هناك بصمات إصبع مسجَّلة."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"لا يحتوي هذا الجهاز على مستشعِر بصمات إصبع."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"تم إيقاف جهاز الاستشعار مؤقتًا."</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index 5b2149e92b83..846fb2c31d1f 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"কোনো ফিংগাৰপ্ৰিণ্ট যোগ কৰা নহ\'ল।"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"এই ডিভাইচটোত ফিংগাৰপ্ৰিণ্ট ছেন্সৰ নাই।"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ছেন্সৰটো সাময়িকভাৱে অক্ষম হৈ আছে।"</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index 54dc9322417e..6b4736f71696 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Barmaq izi qeydə alınmayıb."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Barmaq <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Barmaq izini istifadə edin"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Barmaq izi və ya ekran kilidindən istifadə edin"</string> @@ -1624,7 +1626,7 @@ <string name="wireless_display_route_description" msgid="8297563323032966831">"Simsiz ekran"</string> <string name="media_route_button_content_description" msgid="2299223698196869956">"İştirakçılar"</string> <string name="media_route_chooser_title" msgid="6646594924991269208">"Cihaza qoş"</string> - <string name="media_route_chooser_title_for_remote_display" msgid="3105906508794326446">"Ekranı cihaza yayımla"</string> + <string name="media_route_chooser_title_for_remote_display" msgid="3105906508794326446">"Ekran yayımı"</string> <string name="media_route_chooser_searching" msgid="6119673534251329535">"Cihazlar axtarılır..."</string> <string name="media_route_chooser_extended_settings" msgid="2506352159381327741">"Ayarlar"</string> <string name="media_route_controller_disconnect" msgid="7362617572732576959">"Əlaqəni kəsin"</string> @@ -1695,15 +1697,15 @@ <string name="accessibility_shortcut_menu_item_status_off" msgid="5531598275559472393">"DEAKTİV"</string> <string name="accessibility_enable_service_title" msgid="3931558336268541484">"<xliff:g id="SERVICE">%1$s</xliff:g> xidmətinin cihaza tam nəzarət etməsinə icazə verilsin?"</string> <string name="accessibility_enable_service_encryption_warning" msgid="8603532708618236909">"<xliff:g id="SERVICE">%1$s</xliff:g> aktiv olarsa, cihazınız data şifrələnməsini genişləndirmək üçün ekran kilidini istifadə etməyəcək."</string> - <string name="accessibility_service_warning_description" msgid="291674995220940133">"Tam nəzarət əlçatımlılıq ehtiyaclarınızı ödəyən bəzi tətbiqlər üçün uyğundur."</string> + <string name="accessibility_service_warning_description" msgid="291674995220940133">"Tam nəzarət icazəsi xüsusi imkanlara dair yardım edən tətbiqlərə lazımdır, digər tətbiqlərə lazım deyil."</string> <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Baxış və nəzarət ekranı"</string> <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Ekrandakı bütün kontenti oxuya və kontenti digər tətbiqlərin üzərində göstərə bilər."</string> <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"Əməliyyatlara baxın və icra edin"</string> - <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"O, tətbiq və ya avadanlıq sensoru ilə interaktivliyinizi izləyir və əvəzinizdən tətbiqlərlə qarşılıqlı əlaqəyə girir."</string> + <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Tətbiq və sensorlarla əlaqələrinizi izləyib tətbiqlərə adınızdan əmrlər verə bilər."</string> <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"İcazə verin"</string> <string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"İmtina edin"</string> <string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Funksiyanı istifadə etmək üçün onun üzərinə toxunun:"</string> - <string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Əlçatımlılıq düyməsi ilə istifadə edəcəyiniz funksiyaları seçin"</string> + <string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Xüsusi imkanlar düyməsinin köməyilə işə salınacaq funksiyaları seçin"</string> <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Səs səviyyəsi düyməsinin qısayolu ilə istifadə edəcəyiniz funksiyaları seçin"</string> <string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> deaktiv edilib"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Qısayolları redaktə edin"</string> @@ -1720,7 +1722,7 @@ <string name="accessibility_button_prompt_text" msgid="8343213623338605305">"Xüsusi imkanlar düyməsinə toxunanda istədiyiniz funksiyanı seçin:"</string> <string name="accessibility_gesture_prompt_text" msgid="8742535972130563952">"Əlçatımlılıq jesti (iki barmağınızla ekranın aşağısından yuxarı doğru sürüşdürün) ilə istifadə edəcəyiniz funksiyanı seçin:"</string> <string name="accessibility_gesture_3finger_prompt_text" msgid="5211827854510660203">"Əlçatımlılıq jesti (üç barmağınızla ekranın aşağısından yuxarı doğru sürüşdürün) ilə istifadə edəcəyiniz funksiyanı seçin:"</string> - <string name="accessibility_button_instructional_text" msgid="8853928358872550500">"Funksiyalar arasında keçid etmək üçün əlçatımlılıq düyməsinə toxunub saxlayın."</string> + <string name="accessibility_button_instructional_text" msgid="8853928358872550500">"Funksiyalar arasında keçid etmək üçün xüsusi imkanlar düyməsini basıb saxlayın."</string> <string name="accessibility_gesture_instructional_text" msgid="9196230728837090497">"Funksiyalar arasında keçid etmək üçün iki barmağınızla yuxarı sürüşdürüb saxlayın."</string> <string name="accessibility_gesture_3finger_instructional_text" msgid="3425123684990193765">"Funksiyalar arasında keçid etmək üçün üç barmağınızla yuxarı doğru sürüşdürüb saxlayın."</string> <string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Böyütmə"</string> @@ -2137,7 +2139,7 @@ <string name="accessibility_system_action_quick_settings_label" msgid="4583900123506773783">"Sürətli Ayarlar"</string> <string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Yandırıb-söndürmə dialoqu"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Kilid Ekranı"</string> - <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekran şəkli"</string> + <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skrinşot"</string> <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Ekranda Əlçatımlılıq Qısayolu"</string> <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Ekranda Əlçatımlılıq Qısayolu Seçicisi"</string> <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Əlçatımlılıq Qısayolu"</string> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index ff2289f192bf..5fcd2df25a78 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -604,6 +604,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nije registrovan nijedan otisak prsta."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Koristite otisak prsta"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Koristite otisak prsta ili zaključavanje ekrana"</string> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index b6ba47a47b1c..1af3ddd3b7fc 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -607,6 +607,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Адбіткі пальцаў не зарэгістраваны."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"На гэтай прыладзе няма сканера адбіткаў пальцаў."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Датчык часова выключаны."</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index 9ab5dfec650a..b3722abd908b 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Няма регистрирани отпечатъци."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Това устройство няма сензор за отпечатъци."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сензорът е временно деактивиран."</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index 2a9ecf66d4e9..69ddbb4f1f46 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"কোনও আঙ্গুলের ছাপ নথিভুক্ত করা হয়নি।"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"এই ডিভাইসে আঙ্গুলের ছাপ নেওয়ার সেন্সর নেই।"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"সেন্সর অস্থায়ীভাবে বন্ধ করা আছে।"</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> @@ -1458,10 +1460,8 @@ <string name="permdesc_requestDeletePackages" msgid="6133633516423860381">"একটি অ্যাপ্লিকেশানকে প্যাকেজগুলি মুছে দেওয়ার অনুরোধ জানাতে দেয়৷"</string> <string name="permlab_requestIgnoreBatteryOptimizations" msgid="7646611326036631439">"ব্যাটারি অপ্টিমাইজেশন উপেক্ষা করার জন্য অনুমতি চাওয়া"</string> <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"কোনো অ্যাপের জন্য ব্যাটারি অপ্টিমাইজেশন উপেক্ষা করতে সেটিকে অনুমতির চাওয়ার মঞ্জুরি দেয়৷"</string> - <!-- no translation found for permlab_queryAllPackages (2928450604653281650) --> - <skip /> - <!-- no translation found for permdesc_queryAllPackages (5339069855520996010) --> - <skip /> + <string name="permlab_queryAllPackages" msgid="2928450604653281650">"অন্যান্য সব প্যাকেজের তথ্য সম্পর্কিত কোয়েরি দেখুন"</string> + <string name="permdesc_queryAllPackages" msgid="5339069855520996010">"এটি কোনও অ্যাপকে সর্বদা ইনস্টল করা সব প্যাকেজ দেখতে অনুমতি দেয়।"</string> <string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"জুম নিয়ন্ত্রণের জন্য দুবার ট্যাপ করুন"</string> <string name="gadget_host_error_inflating" msgid="2449961590495198720">"উইজেট যোগ করা যায়নি৷"</string> <string name="ime_action_go" msgid="5536744546326495436">"যান"</string> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index 2d7003b6e4ab..74da24a6bfc4 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -604,6 +604,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nije prijavljen nijedan otisak prsta."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Koristi otisak prsta"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Koristi otisak prsta ili zaključavanje ekrana"</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 330713d9a6b9..03e7ef2e904b 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No s\'ha registrat cap empremta digital."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Aquest dispositiu no té sensor d\'empremtes digitals."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"El sensor està desactivat temporalment."</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dit <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Utilitza l\'empremta digital"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Utilitza l\'empremta digital o el bloqueig de pantalla"</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index c4eb66ea1a3b..bfd56343d674 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -607,6 +607,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nejsou zaregistrovány žádné otisky prstů."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Použít otisk prstu"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Použít otisk prstu nebo zámek obrazovky"</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 270848758947..4231048bccea 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Der er ikke registreret nogen fingeraftryk."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Fingeraftryk <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Brug fingeraftryk"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Brug fingeraftryk eller skærmlås"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 03b9904658d4..7a75eea2181c 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Keine Fingerabdrücke erfasst."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Fingerabdruck verwenden"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Fingerabdruck oder Displaysperre verwenden"</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index fce9d98005c8..523cde133638 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Δεν έχουν καταχωριστεί δακτυλικά αποτυπώματα."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Αυτή η συσκευή δεν διαθέτει αισθητήρα δακτυλικού αποτυπώματος."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Ο αισθητήρας απενεργοποιήθηκε προσωρινά."</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index 805f344ed20b..b2eaab053b46 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No fingerprints enrolled."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index 86ddb1f7cb72..0a257f429b76 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No fingerprints enrolled."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index da1c49a93603..5eca8a68a12f 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No fingerprints enrolled."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index eeedf2109517..74d32d4a1075 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No fingerprints enrolled."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml index 5a2d3f340cd1..385608faaf28 100644 --- a/core/res/res/values-en-rXC/strings.xml +++ b/core/res/res/values-en-rXC/strings.xml @@ -601,6 +601,7 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No fingerprints enrolled."</string> <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_error_bad_calibration" msgid="374406495079531135">"Sensor needs calibration"</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> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index d3614f1b6df9..fafb766c0dba 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -601,6 +601,8 @@ <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 dactilares."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Se inhabilitó temporalmente el sensor."</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Usar huella digital"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Usar bloqueo de huella dactilar o pantalla"</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 72571596b524..3468da5db15a 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No se ha registrado ninguna huella digital."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Usar huella digital"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Usar huella digital o bloqueo de pantalla"</string> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index 1ae8730a90e4..0a60d66cd2e2 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ühtegi sõrmejälge pole registreeritud."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Sõrmejälg <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Sõrmejälje kasutamine"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Sõrmejälje või ekraaniluku kasutamine"</string> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index de6e5e769e56..e36cc324aed9 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ez da erregistratu hatz-markarik."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>. hatza"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Erabili hatz-marka"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Erabili hatz-marka edo pantailaren blokeoa"</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index cc2223cacbb6..add623a593f9 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"اثر انگشتی ثبت نشده است."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"این دستگاه حسگر اثر انگشت ندارد."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"حسگر بهطور موقت غیرفعال است."</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 1b28ca1e5f05..5b4caa7b71fe 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Sormenjälkiä ei ole otettu käyttöön."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Sormi <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Käytä sormenjälkeä"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Käytä sormenjälkeä tai näytön lukitusta"</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index fa3737843761..29c9698479fa 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Aucune empreinte digitale enregistrée."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Doigt <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Utiliser l\'empreinte digitale"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Utiliser l\'empreinte digitale ou le verrouillage de l\'écran"</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 0ee3c889fdb2..23e599e1d948 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Aucune empreinte digitale enregistrée."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Doigt <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Utiliser l\'empreinte digitale"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Utiliser votre empreinte digitale ou le verrouillage de l\'écran"</string> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index 5e10fdb8eb45..70f703a34648 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Non se rexistraron impresións dixitais."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Utilizar impresión dixital"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Utilizar impresión dixital ou credencial do dispositivo"</string> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 4157e1fd32eb..4d27b1086f61 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"કોઈ ફિંગરપ્રિન્ટની નોંધણી કરવામાં આવી નથી."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"આ ડિવાઇસમાં કોઈ ફિંગરપ્રિન્ટ સેન્સર નથી."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"સેન્સર હંગામી રૂપે બંધ કર્યું છે."</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> @@ -1458,10 +1460,8 @@ <string name="permdesc_requestDeletePackages" msgid="6133633516423860381">"ઍપ્લિકેશનને પૅકેજો કાઢી નાખવાની વિનંતી કરવાની મંજૂરી આપે છે."</string> <string name="permlab_requestIgnoreBatteryOptimizations" msgid="7646611326036631439">"બૅટરી ઓપ્ટિમાઇઝેશન્સને અવગણવા માટે પૂછો"</string> <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"ઍપ્લિકેશનને તે ઍપ્લિકેશન માટે બૅટરી ઓપ્ટિમાઇઝેશન્સને અવગણવાની પરવાનગી આપવા માટે પૂછવાની મંજૂરી આપે છે."</string> - <!-- no translation found for permlab_queryAllPackages (2928450604653281650) --> - <skip /> - <!-- no translation found for permdesc_queryAllPackages (5339069855520996010) --> - <skip /> + <string name="permlab_queryAllPackages" msgid="2928450604653281650">"બધા પૅકેજ જુઓ"</string> + <string name="permdesc_queryAllPackages" msgid="5339069855520996010">"કોઈ ઍપને ઇન્સ્ટૉલ કરેલા બધા પૅકેજ જોવાની મંજૂરી આપે છે."</string> <string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"ઝૂમ નિયંત્રણ માટે બેવાર ટૅપ કરો"</string> <string name="gadget_host_error_inflating" msgid="2449961590495198720">"વિજેટ ઉમેરી શકાયું નથી."</string> <string name="ime_action_go" msgid="5536744546326495436">"જાઓ"</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 8fe4ebfee33e..74f4f4612d24 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"कोई फ़िंगरप्रिंट रजिस्टर नहीं किया गया है."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"इस डिवाइस में फ़िंगरप्रिंट सेंसर नहीं है."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"सेंसर कुछ समय के लिए बंद कर दिया गया है."</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index 630ba2bece23..13a7c450f6d3 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -604,6 +604,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nije registriran nijedan otisak prsta."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Upotreba otiska prsta"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Upotreba otiska prsta ili zaključavanja zaslona"</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index f945d395a6e5..a478e6763a41 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nincsenek regisztrált ujjlenyomatok."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>. ujj"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Ujjlenyomat használata"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"A folytatás ujjlenyomattal vagy képernyőzárral lehetséges"</string> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index d3057ca30809..e42eccb58cb6 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Գրանցված մատնահետք չկա:"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Այս սարքը չունի մատնահետքերի սկաներ։"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Տվիչը ժամանակավորապես անջատված է:"</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index abe36081900e..f50c4707f02a 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Tidak ada sidik jari yang terdaftar."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Jari <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Gunakan sidik jari"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Gunakan sidik jari atau kunci layar"</string> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index 6be07b0056b0..bfc747668692 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Engin fingraför hafa verið skráð."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Fingur <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Nota fingrafar"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Nota fingrafar eða skjálás"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index d4f2fdb08395..708841dafac8 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nessuna impronta digitale registrata."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dito <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Usa l\'impronta"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Usa l\'impronta o il blocco schermo"</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 7c9d97ecdd76..fabffbf34abf 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -607,6 +607,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"לא נסרקו טביעות אצבע."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"במכשיר הזה אין חיישן טביעות אצבע."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"החיישן מושבת באופן זמני."</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 39681875a345..e275df037597 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"指紋が登録されていません。"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"このデバイスには指紋認証センサーがありません。"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"センサーが一時的に無効になっています。"</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index e941b5e48806..bd85e614ce07 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"თითის ანაბეჭდები რეგისტრირებული არ არის."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ამ მოწყობილობას არ აქვს თითის ანაბეჭდის სენსორი."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"სენსორი დროებით გათიშულია."</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index 1324d2d4ce60..16da28fc28d9 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Саусақ іздері тіркелмеген."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Бұл құрылғыда саусақ ізін оқу сканері жоқ."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Датчик уақытша өшірулі."</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index df0b08299bb1..e72db139ae61 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"មិនមានការចុះឈ្មោះស្នាមម្រាមដៃទេ។"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ឧបករណ៍នេះមិនមានឧបករណ៍ចាប់ស្នាមម្រាមដៃទេ។"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"បានបិទឧបករណ៍ចាប់សញ្ញាជាបណ្តោះអាសន្ន។"</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index a8e5b6403a4d..8858d0b8896d 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ಯಾವುದೇ ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಅನ್ನು ನೋಂದಣಿ ಮಾಡಿಲ್ಲ."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ಈ ಸಾಧನವು ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ಅನ್ನು ಹೊಂದಿಲ್ಲ."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ಸೆನ್ಸಾರ್ ಅನ್ನು ತಾತ್ಕಾಲಿಕವಾಗಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index cf9ade76183c..e9d0fc5a3326 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"등록된 지문이 없습니다."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"기기에 지문 센서가 없습니다."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"센서가 일시적으로 사용 중지되었습니다."</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index 5479f119c2ba..c1961db3c757 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Бир да манжа изи катталган эмес."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Бул түзмөктө манжа изинин сенсору жок."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сенсор убактылуу өчүрүлгөн."</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index ee2f058393df..65643c35bd8f 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ບໍ່ມີການລົງທະບຽນລາຍນິ້ວມື."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ອຸປະກອນນີ້ບໍ່ມີເຊັນເຊີລາຍນິ້ວມື."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ປິດການເຮັດວຽກຂອງເຊັນເຊີໄວ້ຊົ່ວຄາວແລ້ວ."</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index 8ebb09ede62c..9849124541bd 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -607,6 +607,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Neužregistruota jokių kontrolinių kodų."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g> pirštas"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Naudoti kontrolinį kodą"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Naudoti kontrolinį kodą arba ekrano užraktą"</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 9b86c4d7fc7f..8407622b0614 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -604,6 +604,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nav reģistrēts neviens pirksta nospiedums."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>. pirksts"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Pirksta nospieduma izmantošana"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Pirksta nospieduma vai ekrāna bloķēšanas metodes izmantošana"</string> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index d0e11f1e8039..42a55c20a190 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Не се запишани отпечатоци."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Уредов нема сензор за отпечатоци."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сензорот е привремено оневозможен."</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index 22fac7ed594f..f4a79e317e0c 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"വിരലടയാളങ്ങൾ എൻറോൾ ചെയ്തിട്ടില്ല."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ഈ ഉപകരണത്തിൽ ഫിംഗർപ്രിന്റ് സെൻസറില്ല."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"സെൻസർ താൽക്കാലികമായി പ്രവർത്തനരഹിതമാക്കി."</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index 1060f64fdb1c..7d0a64345db5 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Бүртгүүлсэн хурууны хээ алга."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Энэ төхөөрөмжид хурууны хээ мэдрэгч алга."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Мэдрэгчийг түр хугацаанд идэвхгүй болгосон."</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index bf5f8e7a827e..3933bf358d8f 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"कोणत्याही फिंगरप्रिंटची नोंद झाली नाही"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"या डिव्हाइसमध्ये फिंगरप्रिंट सेन्सर नाही."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"सेन्सर तात्पुरता बंद केला आहे."</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index ccc0828daafb..2ad6baf06138 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Tiada cap jari didaftarkan."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Jari <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Gunakan cap jari"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Gunakan cap jari atau kunci skrin"</string> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index 7797e0875c2e..3543be0fb9e4 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"မည်သည့် လက်ဗွေကိုမျှ ထည့်သွင်းမထားပါ။"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ဤစက်တွင် လက်ဗွေအာရုံခံကိရိယာ မရှိပါ။"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"အာရုံခံကိရိယာကို ယာယီပိတ်ထားသည်။"</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index 395dc1da2f03..9ed34e026e80 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ingen fingeravtrykk er registrert."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Bruk fingeravtrykk"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Bruk fingeravtrykk eller skjermlås"</string> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index 130adcdcf6c9..25f59c27e077 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"कुनै पनि फिंगरप्रिन्ट दर्ता गरिएको छैन।"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"यो डिभाइसमा कुनै पनि फिंगरप्रिन्ट सेन्सर छैन।"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"केही समयका लागि सेन्सर असक्षम पारियो।"</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 9449ac1cfb91..307c125c41ca 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Geen vingerafdrukken geregistreerd."</string> <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 staat tijdelijk uit."</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Vinger <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Vingerafdruk gebruiken"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Vingerafdruk of schermvergrendeling gebruiken"</string> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index b609827b9918..1e6eb37d0132 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"କୌଣସି ଆଙ୍ଗୁଠି ଚିହ୍ନ ପଞ୍ଜୀକୃତ ହୋଇନାହିଁ।"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ଏହି ଡିଭାଇସ୍ରେ ଟିପଚିହ୍ନ ସେନ୍ସର୍ ନାହିଁ।"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ସେନ୍ସରକୁ ଅସ୍ଥାୟୀ ଭାବେ ଅକ୍ଷମ କରାଯାଇଛି।"</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index 2efcc76bae52..fbccb257569e 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ਕੋਈ ਫਿੰਗਰਪ੍ਰਿੰਟ ਦਰਜ ਨਹੀਂ ਕੀਤੇ ਗਏ।"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ਇਸ ਡੀਵਾਈਸ ਵਿੱਚ ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਨਹੀਂ ਹੈ।"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ਸੈਂਸਰ ਅਸਥਾਈ ਤੌਰ \'ਤੇ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 49890fc64d27..0671787fc470 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -607,6 +607,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nie zarejestrowano odcisków palców."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Odcisk palca <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Używaj odcisku palca"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Używaj odcisku palca lub blokady ekranu"</string> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index f4c0cdbcd2aa..8c6b146c408e 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nenhuma impressão digital registrada."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Usar impressão digital"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Usar impressão digital ou bloqueio de tela"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index f1c847647ae6..0fa0e50de0cb 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nenhuma impressão digital registada."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Utilizar a impressão digital"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Utilizar o bloqueio de ecrã ou a impressão digital"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index f4c0cdbcd2aa..8c6b146c408e 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nenhuma impressão digital registrada."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Usar impressão digital"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Usar impressão digital ou bloqueio de tela"</string> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index c50f2e3a99c0..7bbf3e1dd913 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -604,6 +604,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nu au fost înregistrate amprente."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Degetul <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Folosiți amprenta"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Folosiți amprenta sau blocarea ecranului"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index dde5ebc88d59..ebe46e8124e5 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -607,6 +607,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Нет отсканированных отпечатков пальцев"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"На этом устройстве нет сканера отпечатков пальцев."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сканер отпечатков пальцев временно отключен."</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index 13df5e2db962..eea259472033 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ඇඟිලි සලකුණු ඇතුළත් කර නොමැත."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"මෙම උපාංගයේ ඇඟිලි සලකුණු සංවේදකයක් නොමැත."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"සංවේදකය තාවකාලිකව අබල කර ඇත."</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index 4f8329a5e985..234e3a86f54f 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -607,6 +607,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Neregistrovali ste žiadne odtlačky prstov."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Prst: <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Použiť odtlačok prsta"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Použiť odtlačok prsta alebo zámku obrazovky"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index fb6fc9ae4b16..19c443444d89 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -607,6 +607,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ni registriranih prstnih odtisov."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Uporaba prstnega odtisa"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Uporaba prstnega odtisa ali odklepanja s poverilnico"</string> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index 646cc854a631..7934473206b5 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nuk ka asnjë gjurmë gishti të regjistruar."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Gishti <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Përdor gjurmën e gishtit"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Përdor gjurmën e gishtit ose kyçjen e ekranit"</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index 98ddb39e1680..a0ae389e428b 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -604,6 +604,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Није регистрован ниједан отисак прста."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Овај уређај нема сензор за отисак прста."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сензор је привремено онемогућен."</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index f155f3cd0c36..34d5e2c08ff7 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Inga fingeravtryck har registrerats."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Använd ditt fingeravtryck"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Använd ditt fingeravtryck eller skärmlåset"</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index 8ca0ac0f1aa1..cc8d644ebc0c 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Hakuna alama za vidole zilizojumuishwa."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Kidole cha <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Tumia alama ya kidole"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Tumia alama ya kidole au mbinu ya kufunga skrini"</string> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index 4a50960dd1e9..0d2815164b81 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"கைரேகைப் பதிவுகள் எதுவும் இல்லை."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"இந்தச் சாதனத்தில் கைரேகை சென்சார் இல்லை."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"சென்சார் தற்காலிகமாக முடக்கப்பட்டுள்ளது."</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index d910224af035..936b758a1db5 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"వేలిముద్రలు నమోదు చేయబడలేదు."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ఈ పరికరంలో వేలిముద్ర సెన్సార్ ఎంపిక లేదు."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"సెన్సార్ తాత్కాలికంగా డిజేబుల్ చేయబడింది."</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> @@ -1458,10 +1460,8 @@ <string name="permdesc_requestDeletePackages" msgid="6133633516423860381">"ప్యాకేజీల తొలగింపును అభ్యర్థించడానికి యాప్ను అనుమతిస్తుంది."</string> <string name="permlab_requestIgnoreBatteryOptimizations" msgid="7646611326036631439">"బ్యాటరీ అనుకూలీకరణలను విస్మరించడానికి అడగాలి"</string> <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"ఆ యాప్ కోసం బ్యాటరీ అనుకూలీకరణలు విస్మరించేలా అనుమతి కోరడానికి యాప్ను అనుమతిస్తుంది."</string> - <!-- no translation found for permlab_queryAllPackages (2928450604653281650) --> - <skip /> - <!-- no translation found for permdesc_queryAllPackages (5339069855520996010) --> - <skip /> + <string name="permlab_queryAllPackages" msgid="2928450604653281650">"అన్ని ప్యాకేజీలను క్వెరీ చేయండి"</string> + <string name="permdesc_queryAllPackages" msgid="5339069855520996010">"ఇన్స్టాల్ చేసిన అన్ని ప్యాకేజీలను చూడటానికి యాప్ను అనుమతించండి."</string> <string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"జూమ్ నియంత్రణ కోసం రెండుసార్లు నొక్కండి"</string> <string name="gadget_host_error_inflating" msgid="2449961590495198720">"విడ్జెట్ను జోడించడం సాధ్యపడలేదు."</string> <string name="ime_action_go" msgid="5536744546326495436">"వెళ్లు"</string> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 3f9ae3af84ea..9b2966f8586b 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ไม่มีลายนิ้วมือที่ลงทะเบียน"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"อุปกรณ์นี้ไม่มีเซ็นเซอร์ลายนิ้วมือ"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ปิดใช้เซ็นเซอร์ชั่วคราวแล้ว"</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index edc7427cfdc5..a34ac289dab9 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Walang naka-enroll na fingerprint."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Daliri <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Gumamit ng fingerprint"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Gumamit ng fingerprint o lock ng screen"</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index e5f9fe99de82..a08dcb23a6fc 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Parmak izi kaydedilmedi."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>. parmak"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Parmak izi kullan"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Parmak izi veya ekran kilidi kullan"</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 964c07719f4e..8be7da682be7 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -607,6 +607,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Відбитки пальців не зареєстровано."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"На цьому пристрої немає сканера відбитків пальців."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Датчик тимчасово вимкнено."</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index 7f5046b77277..e0344e05a756 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"کوئی فنگر پرنٹ مندرج شدہ نہیں ہے۔"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"اس آلہ میں فنگر پرنٹ سینسر نہیں ہے۔"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"سینسر عارضی طور غیر فعال ہے۔"</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index d8769b24eca4..25a6a1aed415 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Hech qanday barmoq izi qayd qilinmagan."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index b276ff15552b..a5cfbaf9a3d9 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Chưa đăng ký vân tay."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Ngón tay <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Dùng vân tay"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Dùng vân tay hoặc phương thức khóa màn hình"</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index b745661b42c7..23832eb16ab6 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"未注册任何指纹。"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"此设备没有指纹传感器。"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"传感器已暂时停用。"</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index fd0bd9f1be77..0b59e5255baa 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"未註冊任何指紋"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"此裝置沒有指紋感應器。"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"感應器已暫時停用。"</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 310663f005d6..8f81d83a46e5 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"未登錄任何指紋。"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"這個裝置沒有指紋感應器。"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"感應器已暫時停用。"</string> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <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> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index ae01829085f3..c5c781840ce5 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -601,6 +601,8 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Azikho izigxivizo zeminwe ezibhalisiwe."</string> <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> + <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) --> + <skip /> <string name="fingerprint_name_template" msgid="8941662088160289778">"Umunwe ongu-<xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Sebenzisa izigxivizo zeminwe"</string> <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Sebenzisa izigxivizo zeminwe noma ukukhiya isikrini"</string> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 3c47366a59db..f4aff9467cee 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -3350,6 +3350,10 @@ <!-- The default vibration strength, must be between 1 and 255 inclusive. --> <integer name="config_defaultVibrationAmplitude">255</integer> + <!-- The max vibration strength allowed in audio haptic channels, must be positive or zero if + limit is unknown. --> + <item name="config_hapticChannelMaxVibrationAmplitude" format="float" type="dimen">0</item> + <!-- If the device should still vibrate even in low power mode, for certain priority vibrations (e.g. accessibility, alarms). This is mainly for Wear devices that don't have speakers. --> <bool name="config_allowPriorityVibrationsInLowPowerMode">false</bool> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index d4ddab1ec502..302bd94c1973 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1603,6 +1603,8 @@ <string name="fingerprint_acquired_too_bright">Too bright</string> <!-- Message shown during fingerprint acquisition when a fingerprint must be adjusted.[CHAR LIMIT=50] --> <string name="fingerprint_acquired_try_adjusting">Try adjusting</string> + <!-- Message shown during fingerprint acquisition when a fingeprint area has already been captured during enrollment [CHAR LIMIT=100] --> + <string name="fingerprint_acquired_immobile">Change the position of your finger slightly each time</string> <!-- Array containing custom messages shown during fingerprint acquisision from vendor. Vendor is expected to add and translate these strings --> <string-array name="fingerprint_acquired_vendor"> </string-array> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 960bd639960e..5f849b4e1eb0 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2013,6 +2013,7 @@ <java-symbol type="integer" name="config_notificationServiceArchiveSize" /> <java-symbol type="integer" name="config_previousVibrationsDumpLimit" /> <java-symbol type="integer" name="config_defaultVibrationAmplitude" /> + <java-symbol type="dimen" name="config_hapticChannelMaxVibrationAmplitude" /> <java-symbol type="integer" name="config_vibrationWaveformRampStepDuration" /> <java-symbol type="integer" name="config_vibrationWaveformRampDownDuration" /> <java-symbol type="integer" name="config_radioScanningTimeout" /> @@ -2538,6 +2539,7 @@ <java-symbol type="string" name="fingerprint_error_hw_not_present" /> <java-symbol type="string" name="fingerprint_error_security_update_required" /> <java-symbol type="string" name="fingerprint_error_bad_calibration" /> + <java-symbol type="string" name="fingerprint_acquired_immobile" /> <!-- Fingerprint config --> <java-symbol type="integer" name="config_fingerprintMaxTemplatesPerUser"/> diff --git a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java new file mode 100644 index 000000000000..8c05978ad03c --- /dev/null +++ b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.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.app; + +import static org.junit.Assert.assertEquals; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; + +/** + * Test for verifying the behavior of {@link PropertyInvalidatedCache}. This test does + * not use any actual binder calls - it is entirely self-contained. + * <p> + * Build/Install/Run: + * atest FrameworksCoreTests:PropertyInvalidatedCacheTests + */ +@SmallTest +public class PropertyInvalidatedCacheTests { + + static final String CACHE_PROPERTY = "cache_key.cache_test_a"; + + // This class is a proxy for binder calls. It contains a counter that increments + // every time the class is queried. + private static class ServerProxy { + // The number of times this class was queried. + private int mCount = 0; + + // A single query. The key behavior is that the query count is incremented. + boolean query(int x) { + mCount++; + return value(x); + } + + // Return the expected value of an input, without incrementing the query count. + boolean value(int x) { + return x % 3 == 0; + } + + // Verify the count. + void verify(int x) { + assertEquals(x, mCount); + } + } + + @Test + public void testDisableCache1() { + + // A stand-in for the binder. The test verifies that calls are passed through to + // this class properly. + ServerProxy tester = new ServerProxy(); + + // Three caches, all using the same system property but one uses a different name. + PropertyInvalidatedCache<Integer, Boolean> cache1 = + new PropertyInvalidatedCache<>(4, CACHE_PROPERTY) { + @Override + protected Boolean recompute(Integer x) { + return tester.query(x); + } + }; + PropertyInvalidatedCache<Integer, Boolean> cache2 = + new PropertyInvalidatedCache<>(4, CACHE_PROPERTY) { + @Override + protected Boolean recompute(Integer x) { + return tester.query(x); + } + }; + PropertyInvalidatedCache<Integer, Boolean> cache3 = + new PropertyInvalidatedCache<>(4, CACHE_PROPERTY, "cache3") { + @Override + protected Boolean recompute(Integer x) { + return tester.query(x); + } + }; + + // Caches are enabled upon creation. + assertEquals(false, cache1.getDisabledState()); + assertEquals(false, cache2.getDisabledState()); + assertEquals(false, cache3.getDisabledState()); + + // Disable the cache1 instance. Only cache1 is disabled + cache1.disableInstance(); + assertEquals(true, cache1.getDisabledState()); + assertEquals(false, cache2.getDisabledState()); + assertEquals(false, cache3.getDisabledState()); + + // Disable cache1. This will disable cache1 and cache2 because they share the + // same name. cache3 has a different name and will not be disabled. + cache1.disableLocal(); + assertEquals(true, cache1.getDisabledState()); + assertEquals(true, cache2.getDisabledState()); + assertEquals(false, cache3.getDisabledState()); + + // Create a new cache1. Verify that the new instance is disabled. + cache1 = new PropertyInvalidatedCache<>(4, CACHE_PROPERTY) { + @Override + protected Boolean recompute(Integer x) { + return tester.query(x); + } + }; + assertEquals(true, cache1.getDisabledState()); + } +} diff --git a/core/tests/coretests/src/android/app/appsearch/external/app/AppSearchResultTest.java b/core/tests/coretests/src/android/app/appsearch/external/app/AppSearchResultTest.java index de0670b08ffd..228a061ae3c8 100644 --- a/core/tests/coretests/src/android/app/appsearch/external/app/AppSearchResultTest.java +++ b/core/tests/coretests/src/android/app/appsearch/external/app/AppSearchResultTest.java @@ -18,7 +18,7 @@ package android.app.appsearch; import static com.google.common.truth.Truth.assertThat; -import static org.testng.Assert.expectThrows; +import static org.junit.Assert.assertThrows; import org.junit.Test; @@ -26,7 +26,7 @@ public class AppSearchResultTest { @Test public void testMapNullPointerException() { NullPointerException e = - expectThrows( + assertThrows( NullPointerException.class, () -> { Object o = null; diff --git a/core/tests/coretests/src/android/os/VibratorInfoTest.java b/core/tests/coretests/src/android/os/VibratorInfoTest.java index 8c7d10c7a5ef..6e07fa264c1c 100644 --- a/core/tests/coretests/src/android/os/VibratorInfoTest.java +++ b/core/tests/coretests/src/android/os/VibratorInfoTest.java @@ -87,14 +87,14 @@ public class VibratorInfoTest { public void testIsPrimitiveSupported() { VibratorInfo info = new VibratorInfo.Builder(TEST_VIBRATOR_ID) .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS) - .setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK) + .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 10) .build(); assertTrue(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK)); assertFalse(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_TICK)); // Returns false when there is no compose capability. info = new VibratorInfo.Builder(TEST_VIBRATOR_ID) - .setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK) + .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 10) .build(); assertFalse(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK)); } @@ -103,8 +103,7 @@ public class VibratorInfoTest { public void testGetPrimitiveDuration() { VibratorInfo info = new VibratorInfo.Builder(TEST_VIBRATOR_ID) .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS) - .setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK) - .setPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK, 20) + .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 20) .build(); assertEquals(20, info.getPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK)); assertEquals(0, info.getPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_TICK)); @@ -113,6 +112,26 @@ public class VibratorInfoTest { } @Test + public void testCompositionLimits() { + VibratorInfo info = new VibratorInfo.Builder(TEST_VIBRATOR_ID) + .setPrimitiveDelayMax(100) + .setCompositionSizeMax(10) + .setPwlePrimitiveDurationMax(50) + .setPwleSizeMax(20) + .build(); + assertEquals(100, info.getPrimitiveDelayMax()); + assertEquals(10, info.getCompositionSizeMax()); + assertEquals(50, info.getPwlePrimitiveDurationMax()); + assertEquals(20, info.getPwleSizeMax()); + + VibratorInfo emptyInfo = new VibratorInfo.Builder(TEST_VIBRATOR_ID).build(); + assertEquals(0, emptyInfo.getPrimitiveDelayMax()); + assertEquals(0, emptyInfo.getCompositionSizeMax()); + assertEquals(0, emptyInfo.getPwlePrimitiveDurationMax()); + assertEquals(0, emptyInfo.getPwleSizeMax()); + } + + @Test public void testGetDefaultBraking_returnsFirstSupportedBraking() { assertEquals(Braking.NONE, new VibratorInfo.Builder( TEST_VIBRATOR_ID).build().getDefaultBraking()); @@ -263,8 +282,12 @@ public class VibratorInfoTest { VibratorInfo.Builder completeBuilder = new VibratorInfo.Builder(TEST_VIBRATOR_ID) .setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL) .setSupportedEffects(VibrationEffect.EFFECT_CLICK) - .setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK) - .setPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK, 20) + .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 20) + .setPrimitiveDelayMax(100) + .setCompositionSizeMax(10) + .setSupportedBraking(Braking.CLAB) + .setPwlePrimitiveDurationMax(50) + .setPwleSizeMax(20) .setQFactor(2f) .setFrequencyMapping(TEST_FREQUENCY_MAPPING); VibratorInfo complete = completeBuilder.build(); @@ -279,8 +302,7 @@ public class VibratorInfoTest { assertNotEquals(complete, completeWithComposeControl); VibratorInfo completeWithNoEffects = completeBuilder - .setSupportedEffects() - .setSupportedPrimitives() + .setSupportedEffects(new int[0]) .build(); assertNotEquals(complete, completeWithNoEffects); @@ -289,13 +311,8 @@ public class VibratorInfoTest { .build(); assertNotEquals(complete, completeWithUnknownEffects); - VibratorInfo completeWithUnknownPrimitives = completeBuilder - .setSupportedPrimitives(null) - .build(); - assertNotEquals(complete, completeWithUnknownPrimitives); - VibratorInfo completeWithDifferentPrimitiveDuration = completeBuilder - .setPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK, 10) + .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 10) .build(); assertNotEquals(complete, completeWithDifferentPrimitiveDuration); @@ -321,12 +338,17 @@ public class VibratorInfoTest { .build(); assertNotEquals(complete, completeWithDifferentQFactor); - VibratorInfo empty = new VibratorInfo.Builder(TEST_VIBRATOR_ID).build(); - VibratorInfo emptyWithKnownSupport = new VibratorInfo.Builder(TEST_VIBRATOR_ID) - .setSupportedEffects() - .setSupportedPrimitives() + VibratorInfo unknownEffectSupport = new VibratorInfo.Builder(TEST_VIBRATOR_ID).build(); + VibratorInfo knownEmptyEffectSupport = new VibratorInfo.Builder(TEST_VIBRATOR_ID) + .setSupportedEffects(new int[0]) + .build(); + assertNotEquals(unknownEffectSupport, knownEmptyEffectSupport); + + VibratorInfo unknownBrakingSupport = new VibratorInfo.Builder(TEST_VIBRATOR_ID).build(); + VibratorInfo knownEmptyBrakingSupport = new VibratorInfo.Builder(TEST_VIBRATOR_ID) + .setSupportedBraking(new int[0]) .build(); - assertNotEquals(empty, emptyWithKnownSupport); + assertNotEquals(unknownBrakingSupport, knownEmptyBrakingSupport); } @Test @@ -334,8 +356,7 @@ public class VibratorInfoTest { VibratorInfo original = new VibratorInfo.Builder(TEST_VIBRATOR_ID) .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS) .setSupportedEffects(VibrationEffect.EFFECT_CLICK) - .setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK) - .setPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK, 20) + .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 20) .setQFactor(Float.NaN) .setFrequencyMapping(TEST_FREQUENCY_MAPPING) .build(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java index 1a365fee3b13..9986154b051d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java @@ -235,7 +235,8 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener { } void onAnimationProgress(float linearProgress) { - if (mFirstWindowSurface == null || !mFirstWindowSurface.isValid()) { + if (mFirstWindowSurface == null || !mFirstWindowSurface.isValid() + || !mSplashScreenView.isAttachedToWindow()) { return; } @@ -267,15 +268,20 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener { return; } final SurfaceControl.Transaction tx = mTransactionPool.acquire(); - tx.setFrameTimelineVsync(Choreographer.getSfInstance().getVsyncId()); - - SyncRtSurfaceTransactionApplier.SurfaceParams - params = new SyncRtSurfaceTransactionApplier.SurfaceParams - .Builder(mFirstWindowSurface) - .withWindowCrop(null) - .withMergeTransaction(tx) - .build(); - mApplier.scheduleApply(params); + if (mSplashScreenView.isAttachedToWindow()) { + tx.setFrameTimelineVsync(Choreographer.getSfInstance().getVsyncId()); + + SyncRtSurfaceTransactionApplier.SurfaceParams + params = new SyncRtSurfaceTransactionApplier.SurfaceParams + .Builder(mFirstWindowSurface) + .withWindowCrop(null) + .withMergeTransaction(tx) + .build(); + mApplier.scheduleApply(params); + } else { + tx.setWindowCrop(mFirstWindowSurface, null); + tx.apply(); + } mTransactionPool.release(tx); Choreographer.getSfInstance().postCallback(CALLBACK_COMMIT, @@ -287,13 +293,14 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener { if (DEBUG_EXIT_ANIMATION) { Slog.v(TAG, "vanish animation finished"); } - mSplashScreenView.post(() -> { + + if (mSplashScreenView.isAttachedToWindow()) { mSplashScreenView.setVisibility(GONE); if (mFinishCallback != null) { mFinishCallback.run(); mFinishCallback = null; } - }); + } if (mShiftUpAnimation != null) { mShiftUpAnimation.finish(); } diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java index 4cd3616566c2..ecdd4b616e0f 100644 --- a/location/java/android/location/GnssMeasurement.java +++ b/location/java/android/location/GnssMeasurement.java @@ -214,6 +214,25 @@ public final class GnssMeasurement implements Parcelable { * * <p> When this bit is unset, the {@link #getAccumulatedDeltaRangeMeters()} corresponds to the * carrier phase measurement plus an accumulated integer number of carrier half cycles. + * + * <p> For signals that have databits, the carrier phase tracking loops typically use a costas + * loop discriminator. This type of tracking loop introduces a half-cycle ambiguity that is + * resolved by searching through the received data for known patterns of databits (e.g. GPS uses + * the TLM word) which then determines the polarity of the incoming data and resolves the + * half-cycle ambiguity. + * + * <p>Before the half-cycle ambiguity has been resolved it is possible that the ADR_STATE_VALID + * flag is set: + * + * <ul> + * <li> In cases where ADR_STATE_HALF_CYCLE_REPORTED is not set, the + * ADR_STATE_HALF_CYCLE_RESOLVED flag will not be available. Here, a half wave length will be + * added to the returned accumulated delta range uncertainty to indicate the half cycle + * ambiguity. + * <li> In cases where ADR_STATE_HALF_CYCLE_REPORTED is set, half cycle ambiguity will be + * indicated via both the ADR_STATE_HALF_CYCLE_RESOLVED flag and as well a half wave length + * added to the returned accumulated delta range uncertainty. + * </ul> */ public static final int ADR_STATE_HALF_CYCLE_RESOLVED = (1<<3); @@ -1039,9 +1058,6 @@ public final class GnssMeasurement implements Parcelable { * with integer ambiguity resolution, to determine highly precise relative location between * receivers. * - * <p>This includes ensuring that all half-cycle ambiguities are resolved before this value is - * reported as {@link #ADR_STATE_VALID}. - * * <p>The alignment of the phase measurement will not be adjusted by the receiver so the * in-phase and quadrature phase components will have a quarter cycle offset as they do when * transmitted from the satellites. If the measurement is from a combination of the in-phase diff --git a/obex/javax/obex/ObexHelper.java b/obex/javax/obex/ObexHelper.java index 478297f2a3c9..843793ad98f8 100644 --- a/obex/javax/obex/ObexHelper.java +++ b/obex/javax/obex/ObexHelper.java @@ -34,6 +34,8 @@ package javax.obex; +import android.util.Log; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -43,7 +45,6 @@ import java.util.Calendar; import java.util.Date; import java.util.TimeZone; -import android.util.Log; /** * This class defines a set of helper methods for the implementation of Obex. @@ -1083,11 +1084,12 @@ public final class ObexHelper { } private static int validateMaxPacketSize(int size) { - if(VDBG && (size > MAX_PACKET_SIZE_INT)) Log.w(TAG, - "The packet size supported for the connection (" + size + ") is larger" - + " than the configured OBEX packet size: " + MAX_PACKET_SIZE_INT); - if(size != -1) { - if(size < LOWER_LIMIT_MAX_PACKET_SIZE) { + if (VDBG && (size > MAX_PACKET_SIZE_INT)) { + Log.w(TAG, "The packet size supported for the connection (" + size + ") is larger" + + " than the configured OBEX packet size: " + MAX_PACKET_SIZE_INT); + } + if (size != -1 && size < MAX_PACKET_SIZE_INT) { + if (size < LOWER_LIMIT_MAX_PACKET_SIZE) { throw new IllegalArgumentException(size + " is less that the lower limit: " + LOWER_LIMIT_MAX_PACKET_SIZE); } diff --git a/obex/javax/obex/ObexTransport.java b/obex/javax/obex/ObexTransport.java index a5a75f55f553..4cef0b33df4f 100644 --- a/obex/javax/obex/ObexTransport.java +++ b/obex/javax/obex/ObexTransport.java @@ -81,6 +81,8 @@ public interface ObexTransport { * size. Therefore this value shall not change. * For RFCOMM or other transport types where the OBEX packets size * is unrelated to the transport packet size, return -1; + * Exception can be made (like PBAP transport) with a smaller value + * to avoid bad effect on other profiles using the RFCOMM; * @return the maximum allowed OBEX packet that can be send over * the transport. Or -1 in case of don't care. */ diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-bn/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-bn/strings.xml new file mode 100644 index 000000000000..e0dfcf24700c --- /dev/null +++ b/packages/SettingsLib/BannerMessagePreference/res/values-bn/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"বাতিল করুন"</string> +</resources> diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-de/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-de/strings.xml new file mode 100644 index 000000000000..006301b2e94e --- /dev/null +++ b/packages/SettingsLib/BannerMessagePreference/res/values-de/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Schließen"</string> +</resources> diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-mr/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-mr/strings.xml new file mode 100644 index 000000000000..4bd44859ec8f --- /dev/null +++ b/packages/SettingsLib/BannerMessagePreference/res/values-mr/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"डिसमिस करा"</string> +</resources> diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-ne/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-ne/strings.xml new file mode 100644 index 000000000000..15102541bb87 --- /dev/null +++ b/packages/SettingsLib/BannerMessagePreference/res/values-ne/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"हटाउनुहोस्"</string> +</resources> diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-or/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-or/strings.xml new file mode 100644 index 000000000000..36e7d3bdb216 --- /dev/null +++ b/packages/SettingsLib/BannerMessagePreference/res/values-or/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"ଖାରଜ କରନ୍ତୁ"</string> +</resources> diff --git a/packages/SettingsLib/FooterPreference/res/values-bn/strings.xml b/packages/SettingsLib/FooterPreference/res/values-bn/strings.xml new file mode 100644 index 000000000000..c58142d72618 --- /dev/null +++ b/packages/SettingsLib/FooterPreference/res/values-bn/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_learn_more_text" msgid="7385478101223578464">"আরও জানুন"</string> +</resources> diff --git a/packages/SettingsLib/FooterPreference/res/values-de/strings.xml b/packages/SettingsLib/FooterPreference/res/values-de/strings.xml new file mode 100644 index 000000000000..fe885aa6f091 --- /dev/null +++ b/packages/SettingsLib/FooterPreference/res/values-de/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Weitere Informationen"</string> +</resources> diff --git a/packages/SettingsLib/FooterPreference/res/values-mr/strings.xml b/packages/SettingsLib/FooterPreference/res/values-mr/strings.xml new file mode 100644 index 000000000000..45387200bdc8 --- /dev/null +++ b/packages/SettingsLib/FooterPreference/res/values-mr/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_learn_more_text" msgid="7385478101223578464">"अधिक जाणून घ्या"</string> +</resources> diff --git a/packages/SettingsLib/FooterPreference/res/values-ne/strings.xml b/packages/SettingsLib/FooterPreference/res/values-ne/strings.xml new file mode 100644 index 000000000000..ecfec36337ee --- /dev/null +++ b/packages/SettingsLib/FooterPreference/res/values-ne/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_learn_more_text" msgid="7385478101223578464">"थप जान्नुहोस्"</string> +</resources> diff --git a/packages/SettingsLib/FooterPreference/res/values-or/strings.xml b/packages/SettingsLib/FooterPreference/res/values-or/strings.xml new file mode 100644 index 000000000000..e7924d646861 --- /dev/null +++ b/packages/SettingsLib/FooterPreference/res/values-or/strings.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="settingslib_learn_more_text" msgid="7385478101223578464">"ଅଧିକ ଜାଣନ୍ତୁ"</string> +</resources> diff --git a/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/SettingsSpinnerPreference.java b/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/SettingsSpinnerPreference.java index 304c3439a60d..d993e4465343 100644 --- a/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/SettingsSpinnerPreference.java +++ b/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/SettingsSpinnerPreference.java @@ -22,6 +22,7 @@ import android.view.View; import android.widget.AdapterView; import androidx.preference.Preference; +import androidx.preference.Preference.OnPreferenceClickListener; import androidx.preference.PreferenceViewHolder; import com.android.settingslib.widget.settingsspinner.SettingsSpinner; @@ -31,12 +32,12 @@ import com.android.settingslib.widget.settingsspinner.SettingsSpinnerAdapter; * This preference uses SettingsSpinner & SettingsSpinnerAdapter which provide default layouts for * both view and drop down view of the Spinner. */ -public class SettingsSpinnerPreference extends Preference { +public class SettingsSpinnerPreference extends Preference implements OnPreferenceClickListener { private SettingsSpinnerAdapter mAdapter; private AdapterView.OnItemSelectedListener mListener; - private int mPosition; //Default 0 for internal shard storage. - private boolean mIsClickable = true; + private int mPosition; + private boolean mShouldPerformClick; /** * Perform inflation from XML and apply a class-specific base style. @@ -51,7 +52,7 @@ public class SettingsSpinnerPreference extends Preference { public SettingsSpinnerPreference(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); setLayoutResource(R.layout.settings_spinner_preference); - setSelectable(false); + setOnPreferenceClickListener(this); } /** @@ -64,7 +65,7 @@ public class SettingsSpinnerPreference extends Preference { public SettingsSpinnerPreference(Context context, AttributeSet attrs) { super(context, attrs); setLayoutResource(R.layout.settings_spinner_preference); - setSelectable(false); + setOnPreferenceClickListener(this); } /** @@ -76,6 +77,13 @@ public class SettingsSpinnerPreference extends Preference { this(context, null); } + @Override + public boolean onPreferenceClick(Preference preference) { + mShouldPerformClick = true; + notifyChanged(); + return true; + } + /** Sets adapter of the spinner. */ public <T extends SettingsSpinnerAdapter> void setAdapter(T adapter) { mAdapter = adapter; @@ -101,24 +109,19 @@ public class SettingsSpinnerPreference extends Preference { notifyChanged(); } - /** Set clickable of the spinner. */ - public void setClickable(boolean isClickable) { - if (mIsClickable == isClickable) { - return; - } - mIsClickable = isClickable; - notifyChanged(); - } @Override public void onBindViewHolder(PreferenceViewHolder holder) { super.onBindViewHolder(holder); final SettingsSpinner spinner = (SettingsSpinner) holder.findViewById(R.id.spinner); - spinner.setEnabled(mIsClickable); - spinner.setClickable(mIsClickable); spinner.setAdapter(mAdapter); spinner.setSelection(mPosition); spinner.setOnItemSelectedListener(mOnSelectedListener); + if (mShouldPerformClick) { + mShouldPerformClick = false; + // To show dropdown view. + spinner.performClick(); + } } private final AdapterView.OnItemSelectedListener mOnSelectedListener = diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml index 89bb9e8bfe01..fa3f34c96ad2 100644 --- a/packages/SettingsLib/res/values-af/strings.xml +++ b/packages/SettingsLib/res/values-af/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"Bynaam"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Voeg gas by"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Verwyder gas"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Stel gassessie terug"</string> <string name="guest_nickname" msgid="6332276931583337261">"Gas"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Neem \'n foto"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Kies \'n prent"</string> diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml index bc1bd1633e4c..7b4c832fd1d0 100644 --- a/packages/SettingsLib/res/values-am/strings.xml +++ b/packages/SettingsLib/res/values-am/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"ቅጽል ስም"</string> <string name="guest_new_guest" msgid="3482026122932643557">"እንግዳን አክል"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"እንግዳን አስወግድ"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"እንግዳን ዳግም አስጀምር"</string> <string name="guest_nickname" msgid="6332276931583337261">"እንግዳ"</string> <string name="user_image_take_photo" msgid="467512954561638530">"ፎቶ አንሳ"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"ምስል ይምረጡ"</string> diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml index f04aaac87b6d..611f2c44f565 100644 --- a/packages/SettingsLib/res/values-as/strings.xml +++ b/packages/SettingsLib/res/values-as/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"উপনাম"</string> <string name="guest_new_guest" msgid="3482026122932643557">"অতিথি যোগ কৰক"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"অতিথি আঁতৰাওক"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"অতিথিৰ ছেশ্বন ৰিছেট কৰক"</string> <string name="guest_nickname" msgid="6332276931583337261">"অতিথি"</string> <string name="user_image_take_photo" msgid="467512954561638530">"এখন ফট’ তোলক"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"এখন প্ৰতিচ্ছবি বাছনি কৰক"</string> diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml index b7cf11ae3754..c50a22d18605 100644 --- a/packages/SettingsLib/res/values-az/strings.xml +++ b/packages/SettingsLib/res/values-az/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"Ləqəb"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Qonaq əlavə edin"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Qonağı silin"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Qonaq sessiyasını sıfırlayın"</string> <string name="guest_nickname" msgid="6332276931583337261">"Qonaq"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Foto çəkin"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Şəkil seçin"</string> @@ -576,7 +575,7 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Deaktiv"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiv"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Bu dəyişikliyin tətbiq edilməsi üçün cihaz yenidən başladılmalıdır. İndi yenidən başladın və ya ləğv edin."</string> - <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Simli qulaqlıq"</string> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Naqilli qulaqlıq"</string> <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktiv"</string> <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Deaktiv"</string> <string name="carrier_network_change_mode" msgid="4257621815706644026">"Operator şəbəkəsinin dəyişilməsi"</string> diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml index 97c281ad2d67..e26d0650c8cc 100644 --- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml +++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml @@ -567,8 +567,7 @@ <string name="user_nickname" msgid="262624187455825083">"Nadimak"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gosta"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Ukloni gosta"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Resetuj sesiju gosta"</string> <string name="guest_nickname" msgid="6332276931583337261">"Gost"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Slikaj"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Odaberi sliku"</string> diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml index 09e584318173..7899fa687ddc 100644 --- a/packages/SettingsLib/res/values-bg/strings.xml +++ b/packages/SettingsLib/res/values-bg/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"Псевдоним"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Добавяне на гост"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Премахване на госта"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Нулиране на сесията като гост"</string> <string name="guest_nickname" msgid="6332276931583337261">"Гост"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Правене на снимка"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Избиране на изображение"</string> diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml index 88abe33d1f18..9eb20f90735f 100644 --- a/packages/SettingsLib/res/values-bs/strings.xml +++ b/packages/SettingsLib/res/values-bs/strings.xml @@ -567,8 +567,7 @@ <string name="user_nickname" msgid="262624187455825083">"Nadimak"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gosta"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Ukloni gosta"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Poništi sesiju gosta"</string> <string name="guest_nickname" msgid="6332276931583337261">"Gost"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Snimite fotografiju"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Odaberite sliku"</string> diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml index f499ab6cc7c0..d3590bf9e8d2 100644 --- a/packages/SettingsLib/res/values-ca/strings.xml +++ b/packages/SettingsLib/res/values-ca/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"Àlies"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Afegeix un convidat"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Suprimeix el convidat"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Restableix el convidat"</string> <string name="guest_nickname" msgid="6332276931583337261">"Convidat"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Fes una foto"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Tria una imatge"</string> diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml index 4d07eff0e858..5c664b987101 100644 --- a/packages/SettingsLib/res/values-cs/strings.xml +++ b/packages/SettingsLib/res/values-cs/strings.xml @@ -568,8 +568,7 @@ <string name="user_nickname" msgid="262624187455825083">"Přezdívka"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Přidat hosta"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Odstranit hosta"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Resetovat hosta"</string> <string name="guest_nickname" msgid="6332276931583337261">"Host"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Pořídit fotku"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Vybrat obrázek"</string> diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml index 98f53011d2ca..59bfab8ddea8 100644 --- a/packages/SettingsLib/res/values-el/strings.xml +++ b/packages/SettingsLib/res/values-el/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"Ψευδώνυμο"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Προσθήκη επισκέπτη"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Κατάργηση επισκέπτη"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Επαναφορά περιόδου επισκέπτη"</string> <string name="guest_nickname" msgid="6332276931583337261">"Επισκέπτης"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Λήψη φωτογραφίας"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Επιλογή εικόνας"</string> diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml index 6ff48541e4e8..26c7b2c7a760 100644 --- a/packages/SettingsLib/res/values-es/strings.xml +++ b/packages/SettingsLib/res/values-es/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"Apodo"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Añadir invitado"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Quitar invitado"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Restablecer invitado"</string> <string name="guest_nickname" msgid="6332276931583337261">"Invitado"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Hacer foto"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Seleccionar una imagen"</string> diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml index ef7b7db2bb9b..194aeaff4b15 100644 --- a/packages/SettingsLib/res/values-et/strings.xml +++ b/packages/SettingsLib/res/values-et/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"Hüüdnimi"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Lisa külaline"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Eemalda külaline"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Lähtesta külastajaseanss"</string> <string name="guest_nickname" msgid="6332276931583337261">"Külaline"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Pildistage"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Valige pilt"</string> diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml index 93506105d964..33e2314dd887 100644 --- a/packages/SettingsLib/res/values-eu/strings.xml +++ b/packages/SettingsLib/res/values-eu/strings.xml @@ -528,7 +528,7 @@ <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Audio-gailu kableduna"</string> <string name="help_label" msgid="3528360748637781274">"Laguntza eta iritziak"</string> <string name="storage_category" msgid="2287342585424631813">"Biltegiratzea"</string> - <string name="shared_data_title" msgid="1017034836800864953">"Partekatutako datuak"</string> + <string name="shared_data_title" msgid="1017034836800864953">"Datu partekatuak"</string> <string name="shared_data_summary" msgid="5516326713822885652">"Ikusi eta aldatu partekatutako datuak"</string> <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Ez dago erabiltzaile honen datu partekaturik."</string> <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Errore bat gertatu da datu partekatuak eskuratzean. Saiatu berriro."</string> @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"Goitizena"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Gehitu gonbidatua"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Kendu gonbidatua"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Berrezarri gonbidatuentzako saioa"</string> <string name="guest_nickname" msgid="6332276931583337261">"Gonbidatua"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Atera argazki bat"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Aukeratu irudi bat"</string> diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml index 964162b34357..a11a00a5f65d 100644 --- a/packages/SettingsLib/res/values-fi/strings.xml +++ b/packages/SettingsLib/res/values-fi/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"Lempinimi"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Lisää vieras"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Poista vieras"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Nollaa vieras"</string> <string name="guest_nickname" msgid="6332276931583337261">"Vieras"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Ota kuva"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Valitse kuva"</string> diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml index 73f98ec23ccf..dba912ea3920 100644 --- a/packages/SettingsLib/res/values-gl/strings.xml +++ b/packages/SettingsLib/res/values-gl/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"Alcume"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Engadir convidado"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Quitar convidado"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Restablecer sesión de convidado"</string> <string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Tirar foto"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Escoller imaxe"</string> diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml index 5620d946b999..bc74092efa8d 100644 --- a/packages/SettingsLib/res/values-hi/strings.xml +++ b/packages/SettingsLib/res/values-hi/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"प्रचलित नाम"</string> <string name="guest_new_guest" msgid="3482026122932643557">"मेहमान जोड़ें"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"मेहमान हटाएं"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"मेहमान के तौर पर ब्राउज़ करने का सेशन रीसेट करें"</string> <string name="guest_nickname" msgid="6332276931583337261">"मेहमान"</string> <string name="user_image_take_photo" msgid="467512954561638530">"फ़ोटो खींचें"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"कोई इमेज चुनें"</string> diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml index 0ff35f890407..d18d34cb0037 100644 --- a/packages/SettingsLib/res/values-hr/strings.xml +++ b/packages/SettingsLib/res/values-hr/strings.xml @@ -567,8 +567,7 @@ <string name="user_nickname" msgid="262624187455825083">"Nadimak"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Dodavanje gosta"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Uklanjanje gosta"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Poništi gostujuću sesiju"</string> <string name="guest_nickname" msgid="6332276931583337261">"Gost"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Fotografiraj"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Odaberi sliku"</string> diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml index 9bd4d1263abd..3ad3590ca728 100644 --- a/packages/SettingsLib/res/values-hu/strings.xml +++ b/packages/SettingsLib/res/values-hu/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"Becenév"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Vendég hozzáadása"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Vendég munkamenet eltávolítása"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Vendég munkamenet visszaállítása"</string> <string name="guest_nickname" msgid="6332276931583337261">"Vendég"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Fotó készítése"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Kép kiválasztása"</string> diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml index 662a67361b33..da92e7d4517f 100644 --- a/packages/SettingsLib/res/values-is/strings.xml +++ b/packages/SettingsLib/res/values-is/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"Gælunafn"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Bæta gesti við"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Fjarlægja gest"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Endurstilla gestastillingu"</string> <string name="guest_nickname" msgid="6332276931583337261">"Gestur"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Taka mynd"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Velja mynd"</string> diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml index 2c2d11fecda4..6f7565e3fb02 100644 --- a/packages/SettingsLib/res/values-it/strings.xml +++ b/packages/SettingsLib/res/values-it/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"Nickname"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Aggiungi ospite"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Rimuovi ospite"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Reimposta sessione Ospite"</string> <string name="guest_nickname" msgid="6332276931583337261">"Ospite"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Scatta una foto"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Scegli un\'immagine"</string> diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml index ddae3c72babb..70dd9e74929b 100644 --- a/packages/SettingsLib/res/values-kk/strings.xml +++ b/packages/SettingsLib/res/values-kk/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"Лақап ат"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Қонақ қосу"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Қонақты жою"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Қонақ сеансын әдепкі күйге қайтару"</string> <string name="guest_nickname" msgid="6332276931583337261">"Қонақ"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Фотосуретке түсіру"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Сурет таңдау"</string> diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml index d970e9590c36..26595f5cc067 100644 --- a/packages/SettingsLib/res/values-km/strings.xml +++ b/packages/SettingsLib/res/values-km/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"ឈ្មោះហៅក្រៅ"</string> <string name="guest_new_guest" msgid="3482026122932643557">"បញ្ចូលភ្ញៀវ"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"ដកភ្ញៀវចេញ"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"កំណត់ភ្ញៀវឡើងវិញ"</string> <string name="guest_nickname" msgid="6332276931583337261">"ភ្ញៀវ"</string> <string name="user_image_take_photo" msgid="467512954561638530">"ថតរូប"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"ជ្រើសរើសរូបភាព"</string> diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml index 8bad32006594..b36ef8d2a2da 100644 --- a/packages/SettingsLib/res/values-kn/strings.xml +++ b/packages/SettingsLib/res/values-kn/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"ಅಡ್ಡ ಹೆಸರು"</string> <string name="guest_new_guest" msgid="3482026122932643557">"ಅತಿಥಿಯನ್ನು ಸೇರಿಸಿ"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"ಅತಿಥಿಯನ್ನು ತೆಗೆದುಹಾಕಿ"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"ಅತಿಥಿಯನ್ನು ಮರುಹೊಂದಿಸಿ"</string> <string name="guest_nickname" msgid="6332276931583337261">"ಅತಿಥಿ"</string> <string name="user_image_take_photo" msgid="467512954561638530">"ಫೋಟೋ ತೆಗೆದುಕೊಳ್ಳಿ"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"ಚಿತ್ರವನ್ನು ಆರಿಸಿ"</string> diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml index 3383602753f1..ad0ad1fb28bf 100644 --- a/packages/SettingsLib/res/values-lt/strings.xml +++ b/packages/SettingsLib/res/values-lt/strings.xml @@ -568,8 +568,7 @@ <string name="user_nickname" msgid="262624187455825083">"Slapyvardis"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Pridėti svečią"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Pašalinti svečią"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Iš naujo nustatyti svečią"</string> <string name="guest_nickname" msgid="6332276931583337261">"Svečias"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Fotografuoti"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Pasirinkti vaizdą"</string> diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml index d655afc7ae35..586de6fcfdf7 100644 --- a/packages/SettingsLib/res/values-lv/strings.xml +++ b/packages/SettingsLib/res/values-lv/strings.xml @@ -567,8 +567,7 @@ <string name="user_nickname" msgid="262624187455825083">"Segvārds"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Pievienot viesi"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Noņemt viesi"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Atiestatīt viesa sesiju"</string> <string name="guest_nickname" msgid="6332276931583337261">"Viesis"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Uzņemt fotoattēlu"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Izvēlēties attēlu"</string> diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml index bd7f074f01a0..0d0f345af7c3 100644 --- a/packages/SettingsLib/res/values-mk/strings.xml +++ b/packages/SettingsLib/res/values-mk/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"Прекар"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Додајте гостин"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Отстрани гостин"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Ресетирајте го гостинот"</string> <string name="guest_nickname" msgid="6332276931583337261">"Гостин"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Фотографирајте"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Одберете слика"</string> diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml index 1e80ccd0f3ab..655be1a74c31 100644 --- a/packages/SettingsLib/res/values-ml/strings.xml +++ b/packages/SettingsLib/res/values-ml/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"വിളിപ്പേര്"</string> <string name="guest_new_guest" msgid="3482026122932643557">"അതിഥിയെ ചേർക്കുക"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"അതിഥിയെ നീക്കം ചെയ്യുക"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"അതിഥിയെ റീസെറ്റ് ചെയ്യുക"</string> <string name="guest_nickname" msgid="6332276931583337261">"അതിഥി"</string> <string name="user_image_take_photo" msgid="467512954561638530">"ഒരു ഫോട്ടോ എടുക്കുക"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"ഒരു ചിത്രം തിരഞ്ഞെടുക്കുക"</string> diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml index 40b65efe275e..07ed369b8d36 100644 --- a/packages/SettingsLib/res/values-mn/strings.xml +++ b/packages/SettingsLib/res/values-mn/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"Хоч"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Зочин нэмэх"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Зочин хасах"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Зочныг шинэчлэх"</string> <string name="guest_nickname" msgid="6332276931583337261">"Зочин"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Зураг авах"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Зураг сонгох"</string> diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml index 6a46edee6ce5..fe8e8375a65a 100644 --- a/packages/SettingsLib/res/values-mr/strings.xml +++ b/packages/SettingsLib/res/values-mr/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"टोपणनाव"</string> <string name="guest_new_guest" msgid="3482026122932643557">"अतिथी जोडा"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"अतिथी काढून टाका"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"अतिथी सेशन रीसेट करा"</string> <string name="guest_nickname" msgid="6332276931583337261">"अतिथी"</string> <string name="user_image_take_photo" msgid="467512954561638530">"फोटो काढा"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"इमेज निवडा"</string> diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml index 7156a8ef6548..b383ad84cadb 100644 --- a/packages/SettingsLib/res/values-my/strings.xml +++ b/packages/SettingsLib/res/values-my/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"နာမည်ပြောင်"</string> <string name="guest_new_guest" msgid="3482026122932643557">"ဧည့်သည့် ထည့်ရန်"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"ဧည့်သည်ကို ဖယ်ထုတ်ရန်"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"ဧည့်သည်ကို ပြင်ဆင်သတ်မှတ်ရန်"</string> <string name="guest_nickname" msgid="6332276931583337261">"ဧည့်သည်"</string> <string name="user_image_take_photo" msgid="467512954561638530">"ဓာတ်ပုံရိုက်ရန်"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"ပုံရွေးရန်"</string> diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml index bb93a29feaa5..84c231faed46 100644 --- a/packages/SettingsLib/res/values-nb/strings.xml +++ b/packages/SettingsLib/res/values-nb/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"Kallenavn"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Legg til en gjest"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Fjern gjesten"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Tilbakestill gjest"</string> <string name="guest_nickname" msgid="6332276931583337261">"Gjest"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Ta et bilde"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Velg et bilde"</string> diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml index a33bbf3e2dd9..1837eabf2370 100644 --- a/packages/SettingsLib/res/values-nl/strings.xml +++ b/packages/SettingsLib/res/values-nl/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"Bijnaam"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Gast toevoegen"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Gast verwijderen"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Gastsessie resetten"</string> <string name="guest_nickname" msgid="6332276931583337261">"Gast"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Foto maken"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Afbeelding kiezen"</string> diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml index 5f410a86691b..bd77d881560f 100644 --- a/packages/SettingsLib/res/values-pl/strings.xml +++ b/packages/SettingsLib/res/values-pl/strings.xml @@ -568,8 +568,7 @@ <string name="user_nickname" msgid="262624187455825083">"Pseudonim"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gościa"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Usuń gościa"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Resetuj sesję gościa"</string> <string name="guest_nickname" msgid="6332276931583337261">"Gość"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Zrób zdjęcie"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Wybierz obraz"</string> diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml index 3c8d928a7213..e39b58bb8344 100644 --- a/packages/SettingsLib/res/values-pt-rBR/strings.xml +++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"Apelido"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Adicionar convidado"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Remover convidado"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Redefinir sessão de visitante"</string> <string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Tirar uma foto"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Escolher uma imagem"</string> diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml index fc98aa732606..a5c0d1d58d40 100644 --- a/packages/SettingsLib/res/values-pt-rPT/strings.xml +++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"Alcunha"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Adicionar convidado"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Remover convidado"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Repor convidado"</string> <string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Tirar uma foto"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Escolher uma imagem"</string> diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml index 3c8d928a7213..e39b58bb8344 100644 --- a/packages/SettingsLib/res/values-pt/strings.xml +++ b/packages/SettingsLib/res/values-pt/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"Apelido"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Adicionar convidado"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Remover convidado"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Redefinir sessão de visitante"</string> <string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Tirar uma foto"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Escolher uma imagem"</string> diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml index 4db2f315a452..e1b0390fbace 100644 --- a/packages/SettingsLib/res/values-ro/strings.xml +++ b/packages/SettingsLib/res/values-ro/strings.xml @@ -567,8 +567,7 @@ <string name="user_nickname" msgid="262624187455825083">"Pseudonim"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Adăugați un invitat"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Ștergeți invitatul"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Resetați sesiunea pentru invitați"</string> <string name="guest_nickname" msgid="6332276931583337261">"Invitat"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Faceți o fotografie"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Alegeți o imagine"</string> diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml index 0bcdc230c089..1e5fce5f3bc9 100644 --- a/packages/SettingsLib/res/values-ru/strings.xml +++ b/packages/SettingsLib/res/values-ru/strings.xml @@ -568,8 +568,7 @@ <string name="user_nickname" msgid="262624187455825083">"Псевдоним"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Добавить гостя"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Удалить аккаунт гостя"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Сбросить гостевой сеанс"</string> <string name="guest_nickname" msgid="6332276931583337261">"Гость"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Сделать снимок"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Выбрать фото"</string> diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml index ef12ad36c5e1..09c0bf993f34 100644 --- a/packages/SettingsLib/res/values-sk/strings.xml +++ b/packages/SettingsLib/res/values-sk/strings.xml @@ -568,8 +568,7 @@ <string name="user_nickname" msgid="262624187455825083">"Prezývka"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Pridať hosťa"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Odobrať hosťa"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Obnoviť reláciu hosťa"</string> <string name="guest_nickname" msgid="6332276931583337261">"Hosť"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Odfotiť"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Vybrať obrázok"</string> diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml index cbdfefcd424a..b698c19ff8b8 100644 --- a/packages/SettingsLib/res/values-sl/strings.xml +++ b/packages/SettingsLib/res/values-sl/strings.xml @@ -568,8 +568,7 @@ <string name="user_nickname" msgid="262624187455825083">"Vzdevek"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Dodajanje gosta"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Odstranitev gosta"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Ponastavi gosta"</string> <string name="guest_nickname" msgid="6332276931583337261">"Gost"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Fotografiranje"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Izberi sliko"</string> diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml index 3859be937d47..b3c23b667a42 100644 --- a/packages/SettingsLib/res/values-sr/strings.xml +++ b/packages/SettingsLib/res/values-sr/strings.xml @@ -567,8 +567,7 @@ <string name="user_nickname" msgid="262624187455825083">"Надимак"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Додај госта"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Уклони госта"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Ресетуј сесију госта"</string> <string name="guest_nickname" msgid="6332276931583337261">"Гост"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Сликај"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Одабери слику"</string> diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml index 7dcca0d2b611..124c063bea95 100644 --- a/packages/SettingsLib/res/values-sv/strings.xml +++ b/packages/SettingsLib/res/values-sv/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"Smeknamn"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Lägg till gäst"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Ta bort gäst"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Återställ gästsession"</string> <string name="guest_nickname" msgid="6332276931583337261">"Gäst"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Ta ett foto"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Välj en bild"</string> diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml index b7aff721c405..7f67b88aa837 100644 --- a/packages/SettingsLib/res/values-th/strings.xml +++ b/packages/SettingsLib/res/values-th/strings.xml @@ -452,7 +452,7 @@ <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="7703677921000858479">"แท็บเล็ตอาจปิดเครื่องในไม่ช้า (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string> <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="4374784375644214578">"อุปกรณ์อาจปิดเครื่องในไม่ช้า (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string> <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string> - <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"อีก <xliff:g id="TIME">%1$s</xliff:g> จึงจะเต็ม"</string> + <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"อีก <xliff:g id="TIME">%1$s</xliff:g>จึงจะเต็ม"</string> <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - อีก <xliff:g id="TIME">%2$s</xliff:g> จึงจะเต็ม"</string> <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - จำกัดการชาร์จชั่วคราว"</string> <string name="battery_info_status_unknown" msgid="268625384868401114">"ไม่ทราบ"</string> @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"ชื่อเล่น"</string> <string name="guest_new_guest" msgid="3482026122932643557">"เพิ่มผู้ใช้ชั่วคราว"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"นำผู้ใช้ชั่วคราวออก"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"รีเซ็ตผู้เข้าร่วม"</string> <string name="guest_nickname" msgid="6332276931583337261">"ผู้ใช้ชั่วคราว"</string> <string name="user_image_take_photo" msgid="467512954561638530">"ถ่ายรูป"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"เลือกรูปภาพ"</string> diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml index 6d1f6abbdf96..cc7db29f3d32 100644 --- a/packages/SettingsLib/res/values-tl/strings.xml +++ b/packages/SettingsLib/res/values-tl/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"Nickname"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Magdagdag ng bisita"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Alisin ang bisita"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"I-reset ang bisita"</string> <string name="guest_nickname" msgid="6332276931583337261">"Bisita"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Kumuha ng larawan"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Pumili ng larawan"</string> diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml index 82e481bd0613..2cb10763fcc9 100644 --- a/packages/SettingsLib/res/values-uk/strings.xml +++ b/packages/SettingsLib/res/values-uk/strings.xml @@ -568,8 +568,7 @@ <string name="user_nickname" msgid="262624187455825083">"Псевдонім"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Додати гостя"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Видалити гостя"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Скинути сеанс у режимі \"Гість\""</string> <string name="guest_nickname" msgid="6332276931583337261">"Гість"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Зробити фотографію"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Вибрати зображення"</string> diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml index 7f4e30aa33c4..3e11124597d9 100644 --- a/packages/SettingsLib/res/values-uz/strings.xml +++ b/packages/SettingsLib/res/values-uz/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"Nik"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Mehmon kiritish"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Mehmonni olib tashlash"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Mehmon seansini tiklash"</string> <string name="guest_nickname" msgid="6332276931583337261">"Mehmon"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Suratga olish"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Rasm tanlash"</string> diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml index 2fe791a5a47c..0fa97e2011ce 100644 --- a/packages/SettingsLib/res/values-zu/strings.xml +++ b/packages/SettingsLib/res/values-zu/strings.xml @@ -566,8 +566,7 @@ <string name="user_nickname" msgid="262624187455825083">"Isiteketiso"</string> <string name="guest_new_guest" msgid="3482026122932643557">"Engeza isivakashi"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"Susa isihambeli"</string> - <!-- no translation found for guest_reset_guest (6110013010356013758) --> - <skip /> + <string name="guest_reset_guest" msgid="6110013010356013758">"Setha kabusha isivakashi"</string> <string name="guest_nickname" msgid="6332276931583337261">"Isihambeli"</string> <string name="user_image_take_photo" msgid="467512954561638530">"Thatha isithombe"</string> <string name="user_image_choose_photo" msgid="1363820919146782908">"Khetha isithombe"</string> diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/widget/SettingsSpinnerPreferenceTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/widget/SettingsSpinnerPreferenceTest.java index b0c5314a2ec0..53a382a9ebf6 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/widget/SettingsSpinnerPreferenceTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/widget/SettingsSpinnerPreferenceTest.java @@ -89,24 +89,4 @@ public class SettingsSpinnerPreferenceTest { assertThat(mSpinnerPreference.getSelectedItem()) .isEqualTo(mSpinner.getAdapter().getItem(1)); } - - @Test - public void onBindViewHolder_setClickableTrue_isClickableTrue() { - mSpinnerPreference.setClickable(true); - - mSpinnerPreference.onBindViewHolder(mViewHolder); - - assertThat(mSpinner.isClickable()).isTrue(); - assertThat(mSpinner.isEnabled()).isTrue(); - } - - @Test - public void onBindViewHolder_setClickableFalse_isClickableFalse() { - mSpinnerPreference.setClickable(false); - - mSpinnerPreference.onBindViewHolder(mViewHolder); - - assertThat(mSpinner.isClickable()).isFalse(); - assertThat(mSpinner.isEnabled()).isFalse(); - } } diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index c3b96a40023d..9502454d1c8c 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -1035,7 +1035,7 @@ <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Tam ekranı böyüdün"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ekran hissəsinin böyüdülməsi"</string> <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Dəyişdirici"</string> - <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Əlçatımlılıq düyməsi əlçatımlılıq jestini əvəz etdi\n\n"<annotation id="link">"Ayarlara baxın"</annotation></string> + <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Jest xüsusi imkanlar düyməsinə dəyişdirildi\n\n"<annotation id="link">"Ayarlara baxın"</annotation></string> <string name="accessibility_floating_button_switch_migration_tooltip" msgid="6248529129221218770">"Əlçatımlılıq jestindən düymə\n\n"<annotation id="link">"Ayarlarına"</annotation>" keçə bilərsiniz"</string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Düyməni müvəqqəti gizlətmək üçün kənara çəkin"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Yuxarıya sola köçürün"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index 2e98ad94383a..5afd979d34f5 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -484,12 +484,10 @@ <string name="user_add_user" msgid="4336657383006913022">"Дадаць карыстальніка"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Новы карыстальнік"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Выдаліць госця?"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Скінуць гасцявы сеанс?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Усе праграмы і даныя гэтага сеанса будуць выдалены."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Выдаліць"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Скінуць"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"З вяртаннем, госць!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Хочаце працягнуць сеанс?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Пачаць зноў"</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 9f71f43605ae..0eedd1ca13f1 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -1038,8 +1038,7 @@ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"স্ক্রিনের কিছুটা অংশ বড় করুন"</string> <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"বদল করুন"</string> <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"অ্যাক্সেসিবিলিটি জেসচার পরিবর্তন করে অ্যাক্সেসেবিলিটি বোতাম করা হয়েছে\n\n"<annotation id="link">"সেটিংস দেখুন"</annotation></string> - <!-- no translation found for accessibility_floating_button_switch_migration_tooltip (6248529129221218770) --> - <skip /> + <string name="accessibility_floating_button_switch_migration_tooltip" msgid="6248529129221218770">"আপনি অ্যাক্সেসিবিলিটি জেসচারের বদলে \n\n"<annotation id="link">"সেটিংস"</annotation>" বোতামে সুইচ করতে পারেন"</string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"এটি অস্থায়ীভাবে লুকাতে বোতামটি কোণে সরান"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"উপরে বাঁদিকে সরান"</string> <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"উপরে ডানদিকে সরান"</string> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index 17dbbe95a010..615d34634789 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -482,12 +482,10 @@ <string name="user_add_user" msgid="4336657383006913022">"Dodaj korisnika"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Novi korisnik"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Ukloniti gosta?"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Poništiti gostujuću sesiju?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci iz ove sesije će se izbrisati."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ukloni"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Poništi"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Zdravo! Lijepo je opet vidjeti goste."</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite li nastaviti sesiju?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Počni ispočetka"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 274ca3a32a2c..17cb3b9f3c32 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -1038,8 +1038,7 @@ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Teil des Bildschirms vergrößern"</string> <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Schalter"</string> <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Die Schaltfläche „Bedienungshilfen“ ersetzt die Touch-Geste für Bedienungshilfen\n\n"<annotation id="link">"Einstellungen aufrufen"</annotation></string> - <!-- no translation found for accessibility_floating_button_switch_migration_tooltip (6248529129221218770) --> - <skip /> + <string name="accessibility_floating_button_switch_migration_tooltip" msgid="6248529129221218770">"Du kannst von der barrierefreien Geste zu einer Schaltfläche wechseln\n\n"<annotation id="link">"Einstellungen"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Durch Ziehen an den Rand wird die Schaltfläche zeitweise ausgeblendet"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Nach oben links verschieben"</string> <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Nach rechts oben verschieben"</string> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index 662282106d1d..497845707e46 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -480,12 +480,10 @@ <string name="user_add_user" msgid="4336657383006913022">"Lisa kasutaja"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Uus kasutaja"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Kas eemaldada külaline?"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Kas lähtestada külastajaseanss?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Seansi kõik rakendused ja andmed kustutatakse."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Eemalda"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Lähtesta"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Tere tulemast tagasi, külaline!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Kas soovite seansiga jätkata?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Alusta uuesti"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 6f7aee23f190..abbbae7985d4 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -482,12 +482,10 @@ <string name="user_add_user" msgid="4336657383006913022">"Dodavanje korisnika"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Novi korisnik"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Ukloniti gosta?"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Poništiti gostujuću sesiju?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci u ovoj sesiji bit će izbrisani."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ukloni"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Poništi"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Dobro došli natrag, gostu!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite li nastaviti sesiju?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Počni ispočetka"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 800c9dc36a07..15106bb4c157 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -480,12 +480,10 @@ <string name="user_add_user" msgid="4336657383006913022">"Felhasználó hozzáadása"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Új felhasználó"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Eltávolítja a vendég munkamenetet?"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Visszaállítja a vendég munkamenetet?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"A munkamenetben található összes alkalmazás és adat törlődni fog."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Eltávolítás"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Visszaállítás"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Örülünk, hogy visszatért, vendég!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Folytatja a munkamenetet?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Újrakezdés"</string> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index deeeb209e1e3..2e2141ee075c 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -480,12 +480,10 @@ <string name="user_add_user" msgid="4336657383006913022">"Ավելացնել օգտատեր"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Նոր օգտատեր"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Հեռացնե՞լ հյուրին"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Վերակայե՞լ հյուրի աշխատաշրջանը"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Այս աշխատաշրջանի բոլոր ծրագրերն ու տվյալները կջնջվեն:"</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Հեռացնել"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Վերակայել"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Բարի վերադարձ, հյուր"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Շարունակե՞լ աշխատաշրջանը։"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Վերսկսել"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index a6cb798a188e..53a3165776fd 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -480,12 +480,10 @@ <string name="user_add_user" msgid="4336657383006913022">"Tambahkan pengguna"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Pengguna baru"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Hapus tamu?"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Reset sesi tamu?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Semua aplikasi dan data di sesi ini akan dihapus."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Hapus"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Reset"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Selamat datang kembali, tamu!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Lanjutkan sesi Anda?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Mulai ulang"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 066cd9344e91..454b5bba4a49 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -480,12 +480,10 @@ <string name="user_add_user" msgid="4336657383006913022">"Aggiungi utente"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Nuovo utente"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Rimuovere l\'ospite?"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Reimpostare sessione Ospite?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tutte le app e i dati di questa sessione verranno eliminati."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Rimuovi"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Reimposta"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Ti ridiamo il benvenuto alla sessione Ospite."</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vuoi continuare la sessione?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Ricomincia"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index b2f0fd259702..32c386d9993e 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -725,7 +725,7 @@ <string name="notification_channel_unsilenced" msgid="94878840742161152">"ההודעות אלה יישלחו כהתראות"</string> <string name="inline_blocking_helper" msgid="2891486013649543452">"ההתראות האלה בדרך כלל נדחות על ידך. \nלהמשיך להציג אותן?"</string> <string name="inline_done_button" msgid="6043094985588909584">"סיום"</string> - <string name="inline_ok_button" msgid="603075490581280343">"החלה"</string> + <string name="inline_ok_button" msgid="603075490581280343">"אישור"</string> <string name="inline_keep_showing" msgid="8736001253507073497">"שנמשיך להציג לך את ההתראות האלה?"</string> <string name="inline_stop_button" msgid="2453460935438696090">"לא, אל תמשיכו"</string> <string name="inline_deliver_silently_button" msgid="2714314213321223286">"הצגה ללא צליל"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index b1736534ffd1..dacdf2146540 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -480,12 +480,10 @@ <string name="user_add_user" msgid="4336657383006913022">"ユーザーを追加"</string> <string name="user_new_user_name" msgid="2019166282704195789">"新しいユーザー"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ゲストを削除しますか?"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"ゲストをリセットしますか?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"このセッションでのアプリとデータはすべて削除されます。"</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"削除"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"リセット"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"おかえりなさい、ゲストさん"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"セッションを続行しますか?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"最初から開始"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 09d5f9f6e3af..8366b2f48927 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -480,12 +480,10 @@ <string name="user_add_user" msgid="4336657383006913022">"Пайдаланушы қосу"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Жаңа пайдаланушы"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Қонақты жою керек пе?"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Қонақ сеансы бастапқы күйге қайтарылсын ба?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Осы сеанстағы барлық қолданбалар мен деректер жойылады."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Алып тастау"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Бастапқы күйге қайтару"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Қош келдіңіз, қонақ!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Сеансты жалғастыру керек пе?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Қайта бастау"</string> @@ -668,7 +666,7 @@ <string name="enable_demo_mode" msgid="3180345364745966431">"Демо режимін қосу"</string> <string name="show_demo_mode" msgid="3677956462273059726">"Демо режимін көрсету"</string> <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string> - <string name="status_bar_alarm" msgid="87160847643623352">"Дабыл"</string> + <string name="status_bar_alarm" msgid="87160847643623352">"Оятқыш"</string> <string name="wallet_title" msgid="5369767670735827105">"Әмиян"</string> <string name="wallet_empty_state_label" msgid="7776761245237530394">"Телефоныңызбен бұрынғыдан да жылдам әрі қауіпсіз сатып алу үшін параметрлерді орнатыңыз."</string> <string name="wallet_app_button_label" msgid="7123784239111190992">"Барлығын көрсету"</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 065a49951dfb..3baa4e1411f1 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -480,12 +480,10 @@ <string name="user_add_user" msgid="4336657383006913022">"បញ្ចូលអ្នកប្រើ"</string> <string name="user_new_user_name" msgid="2019166282704195789">"អ្នកប្រើថ្មី"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ដកភ្ញៀវចេញឬ?"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"កំណត់ភ្ញៀវឡើងវិញឬ?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"កម្មវិធី និងទិន្នន័យទាំងអស់ក្នុងវគ្គនេះនឹងត្រូវលុប។"</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ដកចេញ"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"កំណត់ឡើងវិញ"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"សូមស្វាគមន៍ការត្រឡប់មកវិញ, ភ្ញៀវ!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"តើអ្នកចង់បន្តវគ្គរបស់អ្នកទេ?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ចាប់ផ្ដើមសាជាថ្មី"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 80415d531d39..ab80f7f3acdc 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -480,12 +480,10 @@ <string name="user_add_user" msgid="4336657383006913022">"사용자 추가"</string> <string name="user_new_user_name" msgid="2019166282704195789">"신규 사용자"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"게스트를 삭제하시겠습니까?"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"게스트를 초기화하시겠습니까?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"이 세션에 있는 모든 앱과 데이터가 삭제됩니다."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"삭제"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"초기화"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"게스트 세션 진행"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"세션을 계속 진행하시겠습니까?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"다시 시작"</string> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index 2474fe1f25b5..037a765870d4 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -480,12 +480,10 @@ <string name="user_add_user" msgid="4336657383006913022">"Колдонуучу кошуу"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Жаңы колдонуучу"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Конокту алып саласызбы?"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Конок сеансын баштапкы абалга келтиресизби?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Бул сеанстагы бардык колдонмолор жана маалыматтар өчүрүлөт."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Өчүрүү"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Баштапкы абалга келтирүү"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Кайтып келишиңиз менен!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Сеансыңызды улантасызбы?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Кайра баштоо"</string> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index 106f7f20a5ba..4cdc8a5fcb4e 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -480,12 +480,10 @@ <string name="user_add_user" msgid="4336657383006913022">"ເພີ່ມຜູ້ໃຊ້"</string> <string name="user_new_user_name" msgid="2019166282704195789">"ຜູ່ໃຊ້ໃໝ່"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ລຶບແຂກບໍ?"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"ຣີເຊັດແຂກບໍ?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ແອັບຯແລະຂໍ້ມູນທັງໝົດໃນເຊດຊັນນີ້ຈະຖືກລຶບອອກ."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ລຶບ"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"ຣີເຊັດ"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"ຍິນດີຕ້ອນຮັບກັບມາ, ຜູ້ຢ້ຽມຢາມ!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"ທ່ານຕ້ອງການສືບຕໍ່ເຊດຊັນຂອງທ່ານບໍ່?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ເລີ່ມຕົ້ນໃຫມ່"</string> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index 535da7a98f87..90f775bcd310 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -480,12 +480,10 @@ <string name="user_add_user" msgid="4336657383006913022">"Додај корисник"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Нов корисник"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Да се отстрани гостинот?"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Да се ресетира гостинот?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Сите апликации и податоци во сесијата ќе се избришат."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Отстрани"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Ресетирај"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Добре дојде пак, гостине!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Дали сакате да продолжите со сесијата?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Почни одново"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 8dae31d1c7f2..976c2dd420c8 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -480,12 +480,10 @@ <string name="user_add_user" msgid="4336657383006913022">"Хэрэглэгч нэмэх"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Шинэ хэрэглэгч"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Зочныг хасах уу?"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Зочныг шинэчлэх үү?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Энэ харилцан үйлдлийн бүх апп болон дата устах болно."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Хасах"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Шинэчлэх"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Эргэн тавтай морилно уу!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Та үргэлжлүүлэхийг хүсэж байна уу?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Дахин эхлүүлэх"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index 3aae0640802f..84b559475019 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -1038,8 +1038,7 @@ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"स्क्रीनचा काही भाग मॅग्निफाय करा"</string> <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"स्विच करा"</string> <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"अॅक्सेसिबिलिटी जेश्चर हे आता अॅक्सेसिबिलिटी बटण आहे \n\n"<annotation id="link">"सेटिंग्ज पाहा"</annotation></string> - <!-- no translation found for accessibility_floating_button_switch_migration_tooltip (6248529129221218770) --> - <skip /> + <string name="accessibility_floating_button_switch_migration_tooltip" msgid="6248529129221218770">"तुम्ही अॅक्सेसिबिलिटी जेश्चरवरून बटणवर स्विच करू शकता \n\n"<annotation id="link">"सेटिंग्ज"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"बटण तात्पुरते लपवण्यासाठी ते कोपर्यामध्ये हलवा"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"वर डावीकडे हलवा"</string> <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"वर उजवीकडे हलवा"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index 9a8fc20fd6c4..efe716e9d04a 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -480,12 +480,10 @@ <string name="user_add_user" msgid="4336657383006913022">"အသုံးပြုသူ ထည့်ရန်"</string> <string name="user_new_user_name" msgid="2019166282704195789">"အသုံးပြုသူ အသစ်"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ဧည့်သည်ကို ဖယ်မလား။"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"ဧည့်သည်ကို ပြင်ဆင်သတ်မှတ်မလား။"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ဒီချိတ်ဆက်မှု ထဲက အက်ပ်များ အားလုံး နှင့် ဒေတာကို ဖျက်ပစ်မည်။"</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ဖယ်ထုတ်ပါ"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"ပြင်ဆင်သတ်မှတ်ရန်"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"ဧည့်သည်ကို ပြန်လည် ကြိုဆိုပါသည်။"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"သင်၏ စက်ရှင်ကို ဆက်လုပ်လိုပါသလား။"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ပြန်စပါ"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index 0006f7f824a3..52e615519148 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -1038,8 +1038,7 @@ <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"स्क्रिनको केही भाग म्याग्निफाइ गर्नुहोस्"</string> <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"बदल्नुहोस्"</string> <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"एक्सेसिबिलिटी इसाराका स्थानमा एक्सेसिबिलिटी बटन प्रयोग हुन थालेको छ\n\n"<annotation id="link">"सेटिङ हेर्नुहोस्"</annotation></string> - <!-- no translation found for accessibility_floating_button_switch_migration_tooltip (6248529129221218770) --> - <skip /> + <string name="accessibility_floating_button_switch_migration_tooltip" msgid="6248529129221218770">"तपाईं एक्सेसिबिलिटी जेस्चरको साटो बटन प्रयोग गर्न सक्नुहुन्छ\n\n"<annotation id="link">"सेटिङ"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"यो बटन केही बेर नदेखिने पार्न किनारातिर सार्नुहोस्"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"सिरानको बायाँतिर सार्नुहोस्"</string> <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"सिरानको दायाँतिर सार्नुहोस्"</string> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 944753ad570b..8bd41deb9499 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -480,12 +480,10 @@ <string name="user_add_user" msgid="4336657383006913022">"Gebruiker toevoegen"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Nieuwe gebruiker"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Gast verwijderen?"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Gastsessie resetten?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apps en gegevens in deze sessie worden verwijderd."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Verwijderen"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Resetten"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Welkom terug, gast!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Wil je doorgaan met je sessie?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Opnieuw starten"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index 1dcb1434bc29..003ce4c4b5ce 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -480,12 +480,10 @@ <string name="user_add_user" msgid="4336657383006913022">"ଉପଯୋଗକର୍ତ୍ତାଙ୍କୁ ଯୋଗ କରନ୍ତୁ"</string> <string name="user_new_user_name" msgid="2019166282704195789">"ନୂଆ ଉପଯୋଗକର୍ତ୍ତା"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ଅତିଥିଙ୍କୁ କାଢ଼ିଦେବେ?"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"ଅତିଥିଙ୍କୁ ରିସେଟ୍ କରିବେ?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ଏହି ସେସନର ସମସ୍ତ ଆପ୍ ଓ ଡାଟା ଡିଲିଟ୍ ହୋଇଯିବ।"</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"କାଢ଼ିଦିଅନ୍ତୁ"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"ରିସେଟ୍ କରନ୍ତୁ"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"ପୁଣି ସ୍ୱାଗତ, ଅତିଥି!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"ଆପଣ ନିଜର ସେସନ୍ ଜାରି ରଖିବାକୁ ଚାହାଁନ୍ତି କି?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ଆରମ୍ଭ କରନ୍ତୁ"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index ad41e5535e6d..e4dbca5eb8e3 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -480,12 +480,10 @@ <string name="user_add_user" msgid="4336657383006913022">"Adicionar usuário"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Novo usuário"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Remover visitante?"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Redefinir sessão de visitante?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todos os apps e dados nesta sessão serão excluídos."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Remover"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Redefinir"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Você voltou, visitante!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Quer continuar a sessão?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recomeçar"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 738e91644681..a9cb3dc88fa1 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -480,12 +480,10 @@ <string name="user_add_user" msgid="4336657383006913022">"Adicionar utilizador"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Novo utilizador"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Remover o convidado?"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Pretende repor a sessão de convidado?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todas as apps e dados desta sessão serão eliminados."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Remover"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Repor"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Bem-vindo de volta, convidado!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Pretende continuar a sessão?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recomeçar"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index ad41e5535e6d..e4dbca5eb8e3 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -480,12 +480,10 @@ <string name="user_add_user" msgid="4336657383006913022">"Adicionar usuário"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Novo usuário"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Remover visitante?"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Redefinir sessão de visitante?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todos os apps e dados nesta sessão serão excluídos."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Remover"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Redefinir"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Você voltou, visitante!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Quer continuar a sessão?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recomeçar"</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index 3a8b51c49117..6c82ad58a25f 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -480,12 +480,10 @@ <string name="user_add_user" msgid="4336657383006913022">"පරිශීලකයෙක් එක් කරන්න"</string> <string name="user_new_user_name" msgid="2019166282704195789">"නව පරිශීලකයා"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"අමුත්තාන් ඉවත් කරන්නද?"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"ආගන්තුකයා යළි සකසන්නද?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"මෙම සැසියේ සියළුම යෙදුම් සහ දත්ත මකාවී."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ඉවත් කරන්න"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"යළි සකසන්න"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"නැවත සාදරයෙන් පිළිගනිමු, අමුත්තා!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"ඔබගේ සැසිය දිගටම කරගෙන යෑමට ඔබට අවශ්යද?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"යළි මුල සිට අරඹන්න"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index 3ceef49a21e7..390a7bc268e3 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -480,12 +480,10 @@ <string name="user_add_user" msgid="4336657383006913022">"Lägg till användare"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Ny användare"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Vill du ta bort gästen?"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Vill du återställa gästsessionen?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alla appar och data i denna session kommer att raderas."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ta bort"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Återställ"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Välkommen tillbaka som gäst!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vill du fortsätta sessionen?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Börja om"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 0a4e05923f89..99bf399b3c1b 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -480,12 +480,10 @@ <string name="user_add_user" msgid="4336657383006913022">"Ongeza mtumiaji"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Mtumiaji mpya"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Ungependa kumwondoa mgeni?"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Ungependa kubadilisha kipindi cha mgeni?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Data na programu zote katika kipindi hiki zitafutwa."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ondoa"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Badilisha"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Karibu tena mgeni!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Je, unataka kuendelea na kipindi chako?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Anza upya"</string> diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml index 9f8e6364e55d..da80b85b38bf 100644 --- a/packages/SystemUI/res/values-sw600dp/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp/dimens.xml @@ -36,10 +36,6 @@ <!-- On tablets this is just the close_handle_height --> <dimen name="peek_height">@dimen/close_handle_height</dimen> - <!-- The margin between the clock and the notifications on Keyguard. See - keyguard_clock_height_fraction_* for the difference between min and max.--> - <dimen name="keyguard_clock_notifications_margin">44dp</dimen> - <!-- Height of the status bar header bar when on Keyguard --> <dimen name="status_bar_header_height_keyguard">60dp</dimen> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index d6eec3fd4fcf..b21d22faf958 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -480,12 +480,10 @@ <string name="user_add_user" msgid="4336657383006913022">"เพิ่มผู้ใช้"</string> <string name="user_new_user_name" msgid="2019166282704195789">"ผู้ใช้ใหม่"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ต้องการนำผู้ใช้ชั่วคราวออกไหม"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"รีเซ็ตผู้เข้าร่วมไหม"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ระบบจะลบแอปและข้อมูลทั้งหมดในเซสชันนี้"</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"นำออก"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"รีเซ็ต"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"ยินดีต้อนรับผู้เข้าร่วมกลับมาอีกครั้ง"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"คุณต้องการอยู่ในเซสชันต่อไปไหม"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"เริ่มต้นใหม่"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 0a7bdacc69c8..5b48488f18fe 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -480,12 +480,10 @@ <string name="user_add_user" msgid="4336657383006913022">"Magdagdag ng user"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Bagong user"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Alisin ang bisita?"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"I-reset ang session ng bisita?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Ide-delete ang lahat ng app at data sa session na ito."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Alisin"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"I-reset"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Welcome ulit, bisita!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Gusto mo bang ipagpatuloy ang iyong session?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Magsimulang muli"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 80e29fb5df6d..8a3d467fbe58 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -480,12 +480,10 @@ <string name="user_add_user" msgid="4336657383006913022">"Kullanıcı ekle"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Yeni kullanıcı"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Misafir oturumu kaldırılsın mı?"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Misafir oturumu sıfırlansın mı?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bu oturumdaki tüm uygulamalar ve veriler silinecek."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Kaldır"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Sıfırla"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Misafir kullanıcı, tekrar hoşgeldiniz"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Oturumunuza devam etmek istiyor musunuz?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Baştan başla"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 25cc331d993b..9592b2d6aa5c 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -480,12 +480,10 @@ <string name="user_add_user" msgid="4336657383006913022">"添加用户"</string> <string name="user_new_user_name" msgid="2019166282704195789">"新用户"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"要移除访客吗?"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"要重置访客会话吗?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"此会话中的所有应用和数据都将被删除。"</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"移除"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"重置"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"访客,欢迎回来!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"要继续您的会话吗?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"重新开始"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index 5c58081f5035..7be08d3fda5a 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -480,12 +480,10 @@ <string name="user_add_user" msgid="4336657383006913022">"加入使用者"</string> <string name="user_new_user_name" msgid="2019166282704195789">"新使用者"</string> <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"移除訪客?"</string> - <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) --> - <skip /> + <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"要重設訪客嗎?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"這個工作階段中的所有應用程式和資料都會被刪除。"</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"移除"</string> - <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) --> - <skip /> + <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"重設"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"訪客您好,歡迎回來!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"您要繼續您的工作階段嗎?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"重新開始"</string> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 9678affa96a7..2a1bee5344ec 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -445,6 +445,9 @@ <!-- Adjust the theme on fully custom and decorated custom view notifications --> <bool name="config_adjustThemeOnNotificationCustomViews">false</bool> + <!-- Notifications are sized to match the width of two (of 4) qs tiles in landscape. --> + <bool name="config_skinnyNotifsInLandscape">true</bool> + <!-- If true, enable the advance anti-falsing classifier on the lockscreen. On some devices it does not work well, particularly with noisy touchscreens. Note that disabling it may increase the rate of unintentional unlocks. --> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 3e4684c9b2d6..7525a9b1c19c 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -735,8 +735,8 @@ <!-- Minimum distance the user has to drag down to go to the full shade. --> <dimen name="keyguard_drag_down_min_distance">100dp</dimen> - <!-- The margin between the clock and the notifications on Keyguard.--> - <dimen name="keyguard_clock_notifications_margin">30dp</dimen> + <!-- The margin between the status view and the notifications on Keyguard.--> + <dimen name="keyguard_status_view_bottom_margin">20dp</dimen> <!-- Minimum margin between clock and status bar --> <dimen name="keyguard_clock_top_margin">36dp</dimen> <!-- The margin between top of clock and bottom of lock icon. --> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java index ef6212d4f354..a28d1747f2fe 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java @@ -205,6 +205,10 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS } } + int getNotificationIconAreaHeight() { + return mNotificationIconAreaController.getHeight(); + } + @Override protected void onViewDetached() { if (CUSTOM_CLOCKS_ENABLED) { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java index 123c0e63d7d1..2096c310744d 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java @@ -187,10 +187,11 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV } /** - * Get the height of the keyguard status view. + * Get the height of the keyguard status view without the notification icon area, as that's + * only visible on AOD. */ - public int getHeight() { - return mView.getHeight(); + public int getLockscreenHeight() { + return mView.getHeight() - mKeyguardClockSwitchController.getNotificationIconAreaHeight(); } /** diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index 7b34e52c16e8..455f3c0d6ac2 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -71,7 +71,6 @@ public class DozeTriggers implements DozeMachine.Part { * Assuming that the screen should start on. */ private static boolean sWakeDisplaySensorState = true; - private Runnable mQuickPickupDozeCancellable; private static final int PROXIMITY_TIMEOUT_DELAY_MS = 500; @@ -279,14 +278,14 @@ public class DozeTriggers implements DozeMachine.Part { boolean isWakeDisplayEvent = isQuickPickup || ((isWakeOnPresence || isWakeOnReach) && rawValues != null && rawValues.length > 0 && rawValues[0] != 0); - if (isWakeOnPresence || isQuickPickup) { - onWakeScreen(isQuickPickup || isWakeDisplayEvent, + if (isWakeOnPresence) { + onWakeScreen(isWakeDisplayEvent, mMachine.isExecutingTransition() ? null : mMachine.getState(), pulseReason); } else if (isLongPress) { requestPulse(pulseReason, true /* alreadyPerformedProxCheck */, null /* onPulseSuppressedListener */); - } else if (isWakeOnReach) { + } else if (isWakeOnReach || isQuickPickup) { if (isWakeDisplayEvent) { requestPulse(pulseReason, true /* alreadyPerformedProxCheck */, null /* onPulseSuppressedListener */); @@ -388,11 +387,7 @@ public class DozeTriggers implements DozeMachine.Part { */ private void onWakeScreen(boolean wake, @Nullable DozeMachine.State state, int reason) { mDozeLog.traceWakeDisplay(wake, reason); - final boolean isWakeOnPresence = reason == DozeLog.REASON_SENSOR_WAKE_UP; - final boolean isQuickPickup = reason == DozeLog.REASON_SENSOR_QUICK_PICKUP; - if (isWakeOnPresence) { - sWakeDisplaySensorState = wake; - } + sWakeDisplaySensorState = wake; if (wake) { proximityCheckThenCall((result) -> { @@ -405,27 +400,13 @@ public class DozeTriggers implements DozeMachine.Part { // Log sensor triggered Optional.ofNullable(DozingUpdateUiEvent.fromReason(reason)) .ifPresent(mUiEventLogger::log); - - if (isQuickPickup) { - // schedule runnable to go back to DOZE - onQuickPickup(); - } - } else if (state == DozeMachine.State.DOZE_AOD && isQuickPickup) { - // elongate time in DOZE_AOD, schedule new runnable to go back to DOZE - onQuickPickup(); } - }, isQuickPickup /* alreadyPerformedProxCheck */, reason); + }, false /* alreadyPerformedProxCheck */, reason); } else { boolean paused = (state == DozeMachine.State.DOZE_AOD_PAUSED); boolean pausing = (state == DozeMachine.State.DOZE_AOD_PAUSING); - boolean pulse = (state == DozeMachine.State.DOZE_REQUEST_PULSE) - || (state == DozeMachine.State.DOZE_PULSING) - || (state == DozeMachine.State.DOZE_PULSING_BRIGHT); - boolean docked = (state == DozeMachine.State.DOZE_AOD_DOCKED); + if (!pausing && !paused) { - if (isQuickPickup && (pulse || docked)) { - return; - } mMachine.requestState(DozeMachine.State.DOZE); // log wake timeout mUiEventLogger.log(DozingUpdateUiEvent.DOZING_UPDATE_WAKE_TIMEOUT); @@ -433,15 +414,6 @@ public class DozeTriggers implements DozeMachine.Part { } } - private void onQuickPickup() { - cancelQuickPickupDelayableDoze(); - mQuickPickupDozeCancellable = mMainExecutor.executeDelayed(() -> { - onWakeScreen(false, - mMachine.isExecutingTransition() ? null : mMachine.getState(), - DozeLog.REASON_SENSOR_QUICK_PICKUP); - }, mDozeParameters.getQuickPickupAodDuration()); - } - @Override public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) { switch (newState) { @@ -481,7 +453,6 @@ public class DozeTriggers implements DozeMachine.Part { mDozeSensors.requestTemporaryDisable(); break; case FINISH: - cancelQuickPickupDelayableDoze(); mBroadcastReceiver.unregister(mBroadcastDispatcher); mDozeHost.removeCallback(mHostCallback); mDockManager.removeListener(mDockEventListener); @@ -510,16 +481,6 @@ public class DozeTriggers implements DozeMachine.Part { } } - /** - * Cancels last scheduled Runnable that transitions to STATE_DOZE (blank screen) after - * going into STATE_AOD (AOD screen) from the quick pickup gesture. - */ - private void cancelQuickPickupDelayableDoze() { - if (mQuickPickupDozeCancellable != null) { - mQuickPickupDozeCancellable.run(); - mQuickPickupDozeCancellable = null; - } - } private void checkTriggersAtInit() { if (mUiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt index 1004e257c750..3957a60c5b45 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt @@ -32,6 +32,7 @@ import javax.inject.Provider private const val TAG = "MediaCarouselController" private val settingsIntent = Intent().setAction(ACTION_MEDIA_CONTROLS_SETTINGS) +private const val DEBUG = false /** * Class that is responsible for keeping the view carousel up to date. @@ -156,6 +157,12 @@ class MediaCarouselController @Inject constructor( } } + /** + * Update MediaCarouselScrollHandler.visibleToUser to reflect media card container visibility. + * It will be called when the container is out of view. + */ + lateinit var updateUserVisibility: () -> Unit + init { mediaFrame = inflateMediaCarousel() mediaCarousel = mediaFrame.requireViewById(R.id.media_carousel_scroller) @@ -177,6 +184,12 @@ class MediaCarouselController @Inject constructor( keysNeedRemoval.forEach { removePlayer(it) } keysNeedRemoval.clear() + // Update user visibility so that no extra impression will be logged when + // activeMediaIndex resets to 0 + if (this::updateUserVisibility.isInitialized) { + updateUserVisibility() + } + // Let's reset our scroll position mediaCarouselScrollHandler.scrollToStart() } @@ -187,16 +200,24 @@ class MediaCarouselController @Inject constructor( key: String, oldKey: String?, data: MediaData, - immediately: Boolean + immediately: Boolean, + isSsReactivated: Boolean ) { if (addOrUpdatePlayer(key, oldKey, data)) { MediaPlayerData.getMediaPlayer(key, null)?.let { logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED it.mInstanceId, /* isRecommendationCard */ false, - it.surfaceForSmartspaceLogging) + it.surfaceForSmartspaceLogging, + rank = MediaPlayerData.getMediaPlayerIndex(key)) } } + if (mediaCarouselScrollHandler.visibleToUser && + isSsReactivated && !mediaCarouselScrollHandler.qsExpanded) { + // It could happen that reactived media player isn't visible to user because + // of it is a resumption card. + logSmartspaceImpression(mediaCarouselScrollHandler.qsExpanded) + } val canRemove = data.isPlaying?.let { !it } ?: data.isClearable && !data.active if (canRemove && !Utils.useMediaResumption(context)) { // This view isn't playing, let's remove this! This happens e.g when @@ -217,17 +238,24 @@ class MediaCarouselController @Inject constructor( data: SmartspaceMediaData, shouldPrioritize: Boolean ) { - Log.d(TAG, "My Smartspace media update is here") + if (DEBUG) Log.d(TAG, "Loading Smartspace media update") if (data.isActive) { addSmartspaceMediaRecommendations(key, data, shouldPrioritize) MediaPlayerData.getMediaPlayer(key, null)?.let { logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED it.mInstanceId, /* isRecommendationCard */ true, - it.surfaceForSmartspaceLogging) - } - if (mediaCarouselScrollHandler.visibleToUser) { - logSmartspaceImpression() + it.surfaceForSmartspaceLogging, + rank = MediaPlayerData.getMediaPlayerIndex(key)) + + if (mediaCarouselScrollHandler.visibleToUser && + mediaCarouselScrollHandler.visibleMediaIndex == + MediaPlayerData.getMediaPlayerIndex(key)) { + logSmartspaceCardReported(800, // SMARTSPACE_CARD_SEEN + it.mInstanceId, + /* isRecommendationCard */ true, + it.surfaceForSmartspaceLogging) + } } } else { onSmartspaceMediaDataRemoved(data.targetId, immediately = true) @@ -239,7 +267,7 @@ class MediaCarouselController @Inject constructor( } override fun onSmartspaceMediaDataRemoved(key: String, immediately: Boolean) { - Log.d(TAG, "My Smartspace media removal request is received") + if (DEBUG) Log.d(TAG, "My Smartspace media removal request is received") if (immediately || visualStabilityManager.isReorderingAllowed) { onMediaDataRemoved(key) } else { @@ -357,7 +385,7 @@ class MediaCarouselController @Inject constructor( data: SmartspaceMediaData, shouldPrioritize: Boolean ) { - Log.d(TAG, "Updating smartspace target in carousel") + if (DEBUG) Log.d(TAG, "Updating smartspace target in carousel") if (MediaPlayerData.getMediaPlayer(key, null) != null) { Log.w(TAG, "Skip adding smartspace target in carousel") return @@ -644,17 +672,17 @@ class MediaCarouselController @Inject constructor( } /** - * Log the user impression for media card. + * Log the user impression for media card at visibleMediaIndex. */ - fun logSmartspaceImpression() { + fun logSmartspaceImpression(qsExpanded: Boolean) { val visibleMediaIndex = mediaCarouselScrollHandler.visibleMediaIndex if (MediaPlayerData.players().size > visibleMediaIndex) { val mediaControlPanel = MediaPlayerData.players().elementAt(visibleMediaIndex) - val isMediaActive = - MediaPlayerData.playerKeys().elementAt(visibleMediaIndex).data?.active + val hasActiveMediaOrRecommendationCard = + MediaPlayerData.hasActiveMediaOrRecommendationCard() val isRecommendationCard = mediaControlPanel.recommendationViewHolder != null - if (!isRecommendationCard && !isMediaActive) { - // Media control card time out or swiped away + if (!hasActiveMediaOrRecommendationCard && !qsExpanded) { + // Skip logging if on LS or QQS, and there is no active media card return } logSmartspaceCardReported(800, // SMARTSPACE_CARD_SEEN @@ -672,6 +700,13 @@ class MediaCarouselController @Inject constructor( surface: Int, rank: Int = mediaCarouselScrollHandler.visibleMediaIndex ) { + // Only log media resume card when Smartspace data is available + if (!isRecommendationCard && + !mediaManager.smartspaceMediaData.isActive && + MediaPlayerData.smartspaceMediaData == null) { + return + } + /* ktlint-disable max-line-length */ SysUiStatsLog.write(SysUiStatsLog.SMARTSPACE_CARD_REPORTED, eventId, @@ -770,6 +805,16 @@ internal object MediaPlayerData { return mediaData.get(key)?.let { mediaPlayers.get(it) } } + fun getMediaPlayerIndex(key: String): Int { + val sortKey = mediaData.get(key) + mediaPlayers.entries.forEachIndexed { index, e -> + if (e.key == sortKey) { + return index + } + } + return -1 + } + fun removeMediaPlayer(key: String) = mediaData.remove(key)?.let { if (it.isSsMediaRec) { smartspaceMediaData = null @@ -808,4 +853,15 @@ internal object MediaPlayerData { mediaData.clear() mediaPlayers.clear() } + + /* Returns true if there is active media player card or recommendation card */ + fun hasActiveMediaOrRecommendationCard(): Boolean { + if (smartspaceMediaData != null && smartspaceMediaData?.isActive!!) { + return true + } + if (firstActiveMediaIndex() != -1) { + return true + } + return false + } } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt index eb3549789c19..b0d4cb1c9818 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt @@ -62,7 +62,7 @@ class MediaCarouselScrollHandler( private val closeGuts: (immediate: Boolean) -> Unit, private val falsingCollector: FalsingCollector, private val falsingManager: FalsingManager, - private val logSmartspaceImpression: () -> Unit + private val logSmartspaceImpression: (Boolean) -> Unit ) { /** * Is the view in RTL @@ -195,18 +195,22 @@ class MediaCarouselScrollHandler( if (playerWidthPlusPadding == 0) { return } + val relativeScrollX = scrollView.relativeScrollX onMediaScrollingChanged(relativeScrollX / playerWidthPlusPadding, relativeScrollX % playerWidthPlusPadding) } } + /** + * Whether the media card is visible to user if any + */ var visibleToUser: Boolean = false - set(value) { - if (field != value) { - field = value - } - } + + /** + * Whether the quick setting is expanded or not + */ + var qsExpanded: Boolean = false init { gestureDetector = GestureDetectorCompat(scrollView.context, gestureListener) @@ -471,7 +475,7 @@ class MediaCarouselScrollHandler( val oldIndex = visibleMediaIndex visibleMediaIndex = newIndex if (oldIndex != visibleMediaIndex && visibleToUser) { - logSmartspaceImpression() + logSmartspaceImpression(qsExpanded) } closeGuts(false) updatePlayerVisibilities() diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java index 19190cd4a17d..19a67e95a496 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java @@ -266,7 +266,7 @@ public class MediaControlPanel { } mKey = key; MediaSession.Token token = data.getToken(); - mInstanceId = data.getPackageName().hashCode(); + mInstanceId = SmallHash.hash(data.getPackageName()); mBackgroundColor = data.getBackgroundColor(); if (mToken == null || !mToken.equals(token)) { @@ -504,7 +504,7 @@ public class MediaControlPanel { return; } - mInstanceId = data.getTargetId().hashCode(); + mInstanceId = SmallHash.hash(data.getTargetId()); mBackgroundColor = data.getBackgroundColor(); TransitionLayout recommendationCard = mRecommendationViewHolder.getRecommendations(); recommendationCard.setBackgroundTintList(ColorStateList.valueOf(mBackgroundColor)); diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt index ee1d3ea87da8..296bfda89432 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt @@ -31,7 +31,8 @@ class MediaDataCombineLatest @Inject constructor() : MediaDataManager.Listener, key: String, oldKey: String?, data: MediaData, - immediately: Boolean + immediately: Boolean, + isSsReactivated: Boolean ) { if (oldKey != null && oldKey != key && entries.contains(oldKey)) { entries[key] = data to entries.remove(oldKey)?.second diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt index a611b600f47f..c8deb014f781 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt @@ -83,7 +83,8 @@ class MediaDataFilter @Inject constructor( key: String, oldKey: String?, data: MediaData, - immediately: Boolean + immediately: Boolean, + isSsReactivated: Boolean ) { if (oldKey != null && oldKey != key) { allEntries.remove(oldKey) @@ -101,7 +102,7 @@ class MediaDataFilter @Inject constructor( // Notify listeners listeners.forEach { - it.onMediaDataLoaded(key, oldKey, data) + it.onMediaDataLoaded(key, oldKey, data, isSsReactivated = isSsReactivated) } } @@ -118,6 +119,8 @@ class MediaDataFilter @Inject constructor( // Override the pass-in value here, as the order of Smartspace card is only determined here. var shouldPrioritizeMutable = false smartspaceMediaData = data + // Override the pass-in value here, as the Smartspace reactivation could only happen here. + var isSsReactivated = false // Before forwarding the smartspace target, first check if we have recently inactive media val sorted = userEntries.toSortedMap(compareBy { @@ -137,9 +140,13 @@ class MediaDataFilter @Inject constructor( // Notify listeners to consider this media active Log.d(TAG, "reactivating $lastActiveKey instead of smartspace") reactivatedKey = lastActiveKey + if (MediaPlayerData.firstActiveMediaIndex() == -1) { + isSsReactivated = true + } val mediaData = sorted.get(lastActiveKey)!!.copy(active = true) listeners.forEach { - it.onMediaDataLoaded(lastActiveKey, lastActiveKey, mediaData) + it.onMediaDataLoaded(lastActiveKey, lastActiveKey, mediaData, + isSsReactivated = isSsReactivated) } } else { // Mark to prioritize Smartspace card if no recent media. diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt index 28d336ea18d5..df1b07f3e0b2 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt @@ -148,7 +148,7 @@ class MediaDataManager( private val internalListeners: MutableSet<Listener> = mutableSetOf() private val mediaEntries: LinkedHashMap<String, MediaData> = LinkedHashMap() // There should ONLY be at most one Smartspace media recommendation. - private var smartspaceMediaData: SmartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA + var smartspaceMediaData: SmartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA private var smartspaceSession: SmartspaceSession? = null private var allowMediaRecommendations = Utils.allowMediaRecommendations(context) @@ -453,7 +453,8 @@ class MediaDataManager( if (smartspaceMediaData.targetId != key) { return } - Log.d(TAG, "Dismissing Smartspace media target") + + if (DEBUG) Log.d(TAG, "Dismissing Smartspace media target") if (smartspaceMediaData.isActive) { smartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA.copy( targetId = smartspaceMediaData.targetId) @@ -709,17 +710,19 @@ class MediaDataManager( override fun onSmartspaceTargetsUpdated(targets: List<Parcelable>) { if (!allowMediaRecommendations) { + if (DEBUG) Log.d(TAG, "Smartspace recommendation is disabled in Settings.") return } val mediaTargets = targets.filterIsInstance<SmartspaceTarget>() when (mediaTargets.size) { 0 -> { - Log.d(TAG, "Empty Smartspace media target") if (!smartspaceMediaData.isActive) { return } - Log.d(TAG, "Set Smartspace media to be inactive for the data update") + if (DEBUG) { + Log.d(TAG, "Set Smartspace media to be inactive for the data update") + } smartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA.copy( targetId = smartspaceMediaData.targetId) notifySmartspaceMediaDataRemoved(smartspaceMediaData.targetId, immediately = false) @@ -728,13 +731,12 @@ class MediaDataManager( val newMediaTarget = mediaTargets.get(0) if (smartspaceMediaData.targetId == newMediaTarget.smartspaceTargetId) { // The same Smartspace updates can be received. Skip the duplicate updates. - Log.d(TAG, "Same Smartspace media update exists. Skip loading data.") - } else { - Log.d(TAG, "Forwarding Smartspace media update.") - smartspaceMediaData = toSmartspaceMediaData(newMediaTarget, isActive = true) - notifySmartspaceMediaDataLoaded( - smartspaceMediaData.targetId, smartspaceMediaData) + return } + if (DEBUG) Log.d(TAG, "Forwarding Smartspace media update.") + smartspaceMediaData = toSmartspaceMediaData(newMediaTarget, isActive = true) + notifySmartspaceMediaDataLoaded( + smartspaceMediaData.targetId, smartspaceMediaData) } else -> { // There should NOT be more than 1 Smartspace media update. When it happens, it @@ -824,12 +826,16 @@ class MediaDataManager( * @param immediately indicates should apply the UI changes immediately, otherwise wait * until the next refresh-round before UI becomes visible. True by default to take in place * immediately. + * + * @param isSsReactivated indicates transition from a state with no active media players to + * a state with active media players upon receiving Smartspace media data. */ fun onMediaDataLoaded( key: String, oldKey: String?, data: MediaData, - immediately: Boolean = true + immediately: Boolean = true, + isSsReactivated: Boolean = false ) {} /** @@ -879,7 +885,7 @@ class MediaDataManager( private fun packageName(target: SmartspaceTarget): String? { val recommendationList = target.iconGrid if (recommendationList == null || recommendationList.isEmpty()) { - Log.d(TAG, "Empty or media recommendation list.") + Log.w(TAG, "Empty or null media recommendation list.") return null } for (recommendation in recommendationList) { @@ -889,7 +895,7 @@ class MediaDataManager( packageName -> return packageName } } } - Log.d(TAG, "No valid package name is provided.") + Log.w(TAG, "No valid package name is provided.") return null } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt index 52ecbea05924..292b0e291244 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt @@ -67,7 +67,8 @@ class MediaDeviceManager @Inject constructor( key: String, oldKey: String?, data: MediaData, - immediately: Boolean + immediately: Boolean, + isSsReactivated: Boolean ) { if (oldKey != null && oldKey != key) { val oldEntry = entries.remove(oldKey) diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt index edbf18789e28..186f961ff1b6 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt @@ -220,14 +220,11 @@ class MediaHierarchyManager @Inject constructor( set(value) { if (field != value) { field = value + mediaCarouselController.mediaCarouselScrollHandler.qsExpanded = value } // qs is expanded on LS shade and HS shade if (value && (isLockScreenShadeVisibleToUser() || isHomeScreenShadeVisibleToUser())) { - mediaCarouselController.logSmartspaceImpression() - } - // Release shade and back to lock screen - if (isLockScreenVisibleToUser()) { - mediaCarouselController.logSmartspaceImpression() + mediaCarouselController.logSmartspaceImpression(value) } mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = isVisibleToUser() } @@ -409,7 +406,7 @@ class MediaHierarchyManager @Inject constructor( updateTargetState() // Enters shade from lock screen if (newState == StatusBarState.SHADE_LOCKED && isLockScreenShadeVisibleToUser()) { - mediaCarouselController.logSmartspaceImpression() + mediaCarouselController.logSmartspaceImpression(qsExpanded) } mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = isVisibleToUser() } @@ -423,7 +420,7 @@ class MediaHierarchyManager @Inject constructor( dozeAnimationRunning = false // Enters lock screen from screen off if (isLockScreenVisibleToUser()) { - mediaCarouselController.logSmartspaceImpression() + mediaCarouselController.logSmartspaceImpression(qsExpanded) } } else { updateDesiredLocation() @@ -436,11 +433,7 @@ class MediaHierarchyManager @Inject constructor( override fun onExpandedChanged(isExpanded: Boolean) { // Enters shade from home screen if (isHomeScreenShadeVisibleToUser()) { - mediaCarouselController.logSmartspaceImpression() - } - // Back to lock screen from bouncer - if (isLockScreenVisibleToUser()) { - mediaCarouselController.logSmartspaceImpression() + mediaCarouselController.logSmartspaceImpression(qsExpanded) } mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = isVisibleToUser() } @@ -465,6 +458,10 @@ class MediaHierarchyManager @Inject constructor( goingToSleep = false } }) + + mediaCarouselController.updateUserVisibility = { + mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = isVisibleToUser() + } } private fun updateConfiguration() { @@ -663,15 +660,11 @@ class MediaHierarchyManager @Inject constructor( return true } - if (statusbarState == StatusBarState.KEYGUARD) { - if (currentLocation == LOCATION_LOCKSCREEN && - previousLocation == LOCATION_QS || - (currentLocation == LOCATION_QS && - previousLocation == LOCATION_LOCKSCREEN)) { - // We're always fading from lockscreen to keyguard in situations where the player - // is already fully hidden - return false - } + if (statusbarState == StatusBarState.KEYGUARD && (currentLocation == LOCATION_LOCKSCREEN || + previousLocation == LOCATION_LOCKSCREEN)) { + // We're always fading from lockscreen to keyguard in situations where the player + // is already fully hidden + return false } return mediaFrame.isShownNotFaded || animator.isRunning || animationPending } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt index 43e21424c45e..ff085c36ef9c 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt @@ -60,7 +60,8 @@ class MediaHost constructor( key: String, oldKey: String?, data: MediaData, - immediately: Boolean + immediately: Boolean, + isSsReactivated: Boolean ) { if (immediately) { updateViewVisibility() diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt index 0da84fbac600..ab568c8c5a85 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt @@ -159,7 +159,8 @@ class MediaResumeListener @Inject constructor( key: String, oldKey: String?, data: MediaData, - immediately: Boolean + immediately: Boolean, + isSsReactivated: Boolean ) { if (useMediaResumption) { // If this had been started from a resume state, disconnect now that it's live diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaSessionBasedFilter.kt b/packages/SystemUI/src/com/android/systemui/media/MediaSessionBasedFilter.kt index a4f33e354b68..8bddde839817 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaSessionBasedFilter.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaSessionBasedFilter.kt @@ -95,7 +95,8 @@ class MediaSessionBasedFilter @Inject constructor( key: String, oldKey: String?, data: MediaData, - immediately: Boolean + immediately: Boolean, + isSsReactivated: Boolean ) { backgroundExecutor.execute { data.token?.let { diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt index bbea140ecfaf..9a3919326cbd 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt @@ -54,7 +54,8 @@ class MediaTimeoutListener @Inject constructor( key: String, oldKey: String?, data: MediaData, - immediately: Boolean + immediately: Boolean, + isSsReactivated: Boolean ) { var reusedListener: PlaybackStateListener? = null diff --git a/packages/SystemUI/src/com/android/systemui/media/SmallHash.java b/packages/SystemUI/src/com/android/systemui/media/SmallHash.java new file mode 100644 index 000000000000..de7aac609955 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/media/SmallHash.java @@ -0,0 +1,44 @@ +/* + * 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.media; + +import java.util.Objects; + +/** + * A simple hash function for use in privacy-sensitive logging. + */ +public final class SmallHash { + // Hashes will be in the range [0, MAX_HASH). + public static final int MAX_HASH = (1 << 13); + + /** Return Small hash of the string, if non-null, or 0 otherwise. */ + public static int hash(String in) { + return hash(Objects.hashCode(in)); + } + + /** + * Maps in to the range [0, MAX_HASH), keeping similar values distinct. + * + * @param in An arbitrary integer. + * @return in mod MAX_HASH, signs chosen to stay in the range [0, MAX_HASH). + */ + public static int hash(int in) { + return Math.abs(Math.floorMod(in, MAX_HASH)); + } + + private SmallHash() {} +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java index a69b8d60681c..25cbdc5c2187 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java @@ -245,7 +245,8 @@ public class NotificationMediaManager implements Dumpable { mMediaDataManager.addListener(new MediaDataManager.Listener() { @Override public void onMediaDataLoaded(@NonNull String key, - @Nullable String oldKey, @NonNull MediaData data, boolean immediately) { + @Nullable String oldKey, @NonNull MediaData data, boolean immediately, + boolean isSsReactivated) { } @Override @@ -318,7 +319,8 @@ public class NotificationMediaManager implements Dumpable { mMediaDataManager.addListener(new MediaDataManager.Listener() { @Override public void onMediaDataLoaded(@NonNull String key, - @Nullable String oldKey, @NonNull MediaData data, boolean immediately) { + @Nullable String oldKey, @NonNull MediaData data, boolean immediately, + boolean isSsReactivated) { } @Override 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 9d56e9b6f855..fe75739d33c4 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 @@ -133,7 +133,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView private boolean mUpdateBackgroundOnUpdate; private boolean mNotificationTranslationFinished = false; - private ArrayList<MenuItem> mSnoozedMenuItems; + private boolean mIsSnoozed; /** * Listener for when {@link ExpandableNotificationRow} is laid out. @@ -1105,8 +1105,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */, false /* resetMenu */); mNotificationGutsManager.openGuts(this, 0, 0, item); - mSnoozedMenuItems = mMenuRow.getMenuItems(mMenuRow.getMenuView().getContext()); - mMenuRow.resetMenu(); + mIsSnoozed = true; }; } @@ -1821,10 +1820,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView void onGutsClosed() { updateContentAccessibilityImportanceForGuts(true /* isEnabled */); - if (mSnoozedMenuItems != null && mSnoozedMenuItems.size() > 0) { - mMenuRow.setMenuItems(mSnoozedMenuItems); - mSnoozedMenuItems = null; - } + mIsSnoozed = false; } /** @@ -2981,7 +2977,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfoInternal(info); info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK); - if (canViewBeDismissed()) { + if (canViewBeDismissed() && !mIsSnoozed) { info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS); } boolean expandable = shouldShowPublic(); @@ -2997,7 +2993,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView isExpanded = isExpanded(); } } - if (expandable) { + if (expandable && !mIsSnoozed) { if (isExpanded) { info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE); } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index f0201cb3482d..9ba04bf2f49f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -111,6 +111,7 @@ import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController import com.android.systemui.statusbar.policy.HeadsUpUtil; import com.android.systemui.statusbar.policy.ScrollAdapter; import com.android.systemui.util.Assert; +import com.android.systemui.util.leak.RotationUtils; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -421,6 +422,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable animateScroll(); }; private int mCornerRadius; + private int mMinimumPaddings; + private int mQsTilePadding; + private boolean mSkinnyNotifsInLandscape; private int mSidePaddings; private final Rect mBackgroundAnimationRect = new Rect(); private ArrayList<BiConsumer<Float, Float>> mExpandedHeightListeners = new ArrayList<>(); @@ -896,7 +900,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable R.dimen.min_top_overscroll_to_qs); mStatusBarHeight = res.getDimensionPixelSize(R.dimen.status_bar_height); mBottomMargin = res.getDimensionPixelSize(R.dimen.notification_panel_margin_bottom); - mSidePaddings = res.getDimensionPixelSize(R.dimen.notification_side_paddings); + mMinimumPaddings = res.getDimensionPixelSize(R.dimen.notification_side_paddings); + mQsTilePadding = res.getDimensionPixelOffset(R.dimen.qs_tile_margin_horizontal); + mSkinnyNotifsInLandscape = res.getBoolean(R.bool.config_skinnyNotifsInLandscape); + mSidePaddings = mMinimumPaddings; // Updated in onMeasure by updateSidePadding() mMinInteractionHeight = res.getDimensionPixelSize( R.dimen.notification_min_interaction_height); mCornerRadius = res.getDimensionPixelSize(R.dimen.notification_corner_radius); @@ -906,6 +913,21 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable com.android.internal.R.dimen.quick_qs_offset_height); } + void updateSidePadding(int viewWidth) { + if (viewWidth == 0 || !mSkinnyNotifsInLandscape) { + mSidePaddings = mMinimumPaddings; + return; + } + // Portrait is easy, just use the dimen for paddings + if (RotationUtils.getRotation(mContext) == RotationUtils.ROTATION_NONE) { + mSidePaddings = mMinimumPaddings; + return; + } + final int innerWidth = viewWidth - mMinimumPaddings * 2; + final int qsTileWidth = (innerWidth - mQsTilePadding * 3) / 4; + mSidePaddings = mMinimumPaddings + qsTileWidth + mQsTilePadding; + } + void updateCornerRadius() { int newRadius = getResources().getDimensionPixelSize(R.dimen.notification_corner_radius); if (mCornerRadius != newRadius) { @@ -966,6 +988,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); + updateSidePadding(width); int childWidthSpec = MeasureSpec.makeMeasureSpec(width - mSidePaddings * 2, MeasureSpec.getMode(widthMeasureSpec)); // Don't constrain the height of the children so we know how big they'd like to be @@ -2117,7 +2140,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) private void updateContentHeight() { - final float scrimTopPadding = mAmbientState.isOnKeyguard() ? 0 : mSidePaddings; + final float scrimTopPadding = mAmbientState.isOnKeyguard() ? 0 : mMinimumPaddings; int height = (int) scrimTopPadding; float previousPaddingRequest = mPaddingBetweenElements; int numShownItems = 0; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java index 3e4177d32a34..fa5011e8802f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java @@ -40,9 +40,9 @@ public class KeyguardClockPositionAlgorithm { private static float CLOCK_HEIGHT_WEIGHT = 0.7f; /** - * Margin between the bottom of the clock and the notification shade. + * Margin between the bottom of the status view and the notification shade. */ - private int mClockNotificationsMargin; + private int mStatusViewBottomMargin; /** * Height of the parent view - display size in px. @@ -153,8 +153,8 @@ public class KeyguardClockPositionAlgorithm { * Refreshes the dimension values. */ public void loadDimens(Resources res) { - mClockNotificationsMargin = res.getDimensionPixelSize( - R.dimen.keyguard_clock_notifications_margin); + mStatusViewBottomMargin = res.getDimensionPixelSize( + R.dimen.keyguard_status_view_bottom_margin); mContainerTopPadding = res.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin) / 2; @@ -181,7 +181,7 @@ public class KeyguardClockPositionAlgorithm { mNotificationStackHeight = notificationStackHeight; mPanelExpansion = panelExpansion; mHeight = parentHeight; - mKeyguardStatusHeight = keyguardStatusHeight; + mKeyguardStatusHeight = keyguardStatusHeight + mStatusViewBottomMargin; mUserSwitchHeight = userSwitchHeight; mUserSwitchPreferredY = userSwitchPreferredY; mHasCustomClock = hasCustomClock; @@ -221,40 +221,15 @@ public class KeyguardClockPositionAlgorithm { public float getMinStackScrollerPadding() { return mBypassEnabled ? mUnlockedStackScrollerPadding - : mMinTopMargin + mKeyguardStatusHeight + mClockNotificationsMargin; - } - - private int getMaxClockY() { - return mHeight / 2 - mKeyguardStatusHeight - mClockNotificationsMargin; + : mMinTopMargin + mKeyguardStatusHeight; } private int getExpandedPreferredClockY() { return mMinTopMargin + mUserSwitchHeight; } - /** - * Vertically align the clock and the shade in the available space considering only - * a percentage of the clock height defined by {@code CLOCK_HEIGHT_WEIGHT}. - * @return Clock Y in pixels. - */ - public int getExpandedClockPosition() { - final int availableHeight = mMaxShadeBottom - mMinTopMargin; - final int containerCenter = mMinTopMargin + availableHeight / 2; - - float y = containerCenter - - (mKeyguardStatusHeight + mUserSwitchHeight) * CLOCK_HEIGHT_WEIGHT - - mClockNotificationsMargin - mNotificationStackHeight / 2; - if (y < mMinTopMargin) { - y = mMinTopMargin; - } - - // Don't allow the clock base to be under half of the screen - final float maxClockY = getMaxClockY(); - if (y > maxClockY) { - y = maxClockY; - } - - return (int) y; + public int getLockscreenStatusViewHeight() { + return mKeyguardStatusHeight; } private int getClockY(float panelExpansion, float darkAmount) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java index 6b864c9c35df..41af80e02b5a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java @@ -602,6 +602,10 @@ public class NotificationIconAreaController implements updateAodIconColors(); } + public int getHeight() { + return mAodIcons == null ? 0 : mAodIcons.getHeight(); + } + public void appearAodIcons() { if (mAodIcons == null) { return; 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 aaddfca4b685..f461d944d2c2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -1260,7 +1260,7 @@ public class NotificationPanelViewController extends PanelViewController { mNotificationStackScrollLayoutController.getIntrinsicContentHeight(), expandedFraction, totalHeight, - mKeyguardStatusViewController.getHeight(), + mKeyguardStatusViewController.getLockscreenHeight(), userIconHeight, userSwitcherPreferredY, hasCustomClock(), hasVisibleNotifications, darkamount, mOverStretchAmount, @@ -2669,14 +2669,6 @@ public class NotificationPanelViewController extends PanelViewController { @Override protected int getMaxPanelHeight() { - if (mKeyguardBypassController.getBypassEnabled() && mBarState == KEYGUARD) { - return getMaxPanelHeightBypass(); - } else { - return getMaxPanelHeightNonBypass(); - } - } - - private int getMaxPanelHeightNonBypass() { int min = mStatusBarMinHeight; if (!(mBarState == KEYGUARD) && mNotificationStackScrollLayoutController.getNotGoneChildCount() == 0) { @@ -2701,16 +2693,6 @@ public class NotificationPanelViewController extends PanelViewController { return maxHeight; } - private int getMaxPanelHeightBypass() { - int position = - mClockPositionAlgorithm.getExpandedClockPosition() - + mKeyguardStatusViewController.getHeight(); - if (mNotificationStackScrollLayoutController.getVisibleNotificationCount() != 0) { - position += mShelfHeight / 2.0f + mDarkIconSize / 2.0f; - } - return position; - } - public boolean isInSettings() { return mQsExpanded; } @@ -2782,11 +2764,8 @@ public class NotificationPanelViewController extends PanelViewController { maxHeight += mNotificationStackScrollLayoutController.getTopPaddingOverflow(); if (mBarState == KEYGUARD) { - int - minKeyguardPanelBottom = - mClockPositionAlgorithm.getExpandedClockPosition() - + mKeyguardStatusViewController.getHeight() - + mNotificationStackScrollLayoutController.getIntrinsicContentHeight(); + int minKeyguardPanelBottom = mClockPositionAlgorithm.getLockscreenStatusViewHeight() + + mNotificationStackScrollLayoutController.getIntrinsicContentHeight(); return Math.max(maxHeight, minKeyguardPanelBottom); } else { return maxHeight; @@ -3336,7 +3315,7 @@ public class NotificationPanelViewController extends PanelViewController { } if (mKeyguardBypassController.getBypassEnabled() && isOnKeyguard()) { // The expandedHeight is always the full panel Height when bypassing - expandedHeight = getMaxPanelHeightNonBypass(); + expandedHeight = getMaxPanelHeight(); } mNotificationStackScrollLayoutController.setExpandedHeight(expandedHeight); updateKeyguardBottomAreaAlpha(); 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 7a1e5cf1770b..cfcea9684c3b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -551,11 +551,11 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump */ public void setNotificationsBounds(float left, float top, float right, float bottom) { if (mClipsQsScrim) { - // notification scrim's rounded corners are anti-aliased, but clipping of the QS scrim - // can't be and it's causing jagged corners. That's why notification scrim needs - // to overlap QS scrim by one pixel - both vertically (top - 1) and - // horizontally (left - 1 and right + 1), see: b/186644628 - mNotificationsScrim.setDrawableBounds(left - 1, top - 1, right + 1, bottom); + // notification scrim's rounded corners are anti-aliased, but clipping of the QS/behind + // scrim can't be and it's causing jagged corners. That's why notification scrim needs + // to overlap QS scrim by one pixel horizontally (left - 1 and right + 1) + // see: b/186644628 + mNotificationsScrim.setDrawableBounds(left - 1, top, right + 1, bottom); mScrimBehind.setBottomEdgePosition((int) top); } else { mNotificationsScrim.setDrawableBounds(left, top, right, bottom); @@ -1242,6 +1242,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump pw.println(mDefaultScrimAlpha); pw.print(" mExpansionFraction="); pw.println(mPanelExpansion); + + pw.print(" mState.getMaxLightRevealScrimAlpha="); + pw.println(mState.getMaxLightRevealScrimAlpha()); } public void setWallpaperSupportsAmbientMode(boolean wallpaperSupportsAmbientMode) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java index e52e1fa5f39f..06811932ac0c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java @@ -197,7 +197,7 @@ public enum ScrimState { } @Override - public float getBehindAlpha() { + public float getMaxLightRevealScrimAlpha() { return mWallpaperSupportsAmbientMode && !mHasBackdrop ? 0f : 1f; } @@ -220,18 +220,11 @@ public enum ScrimState { mBlankScreen = mDisplayRequiresBlanking; mAnimationDuration = mWakeLockScreenSensorActive ? ScrimController.ANIMATION_DURATION_LONG : ScrimController.ANIMATION_DURATION; - - // Wake sensor will show the wallpaper, let's fade from black. Otherwise it will - // feel like the screen is flashing if the wallpaper is light. - if (mWakeLockScreenSensorActive && previousState == AOD) { - updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK); - } } - @Override - public float getBehindAlpha() { + public float getMaxLightRevealScrimAlpha() { return mWakeLockScreenSensorActive ? ScrimController.WAKE_SENSOR_SCRIM_ALPHA - : AOD.getBehindAlpha(); + : AOD.getMaxLightRevealScrimAlpha(); } }, @@ -351,6 +344,10 @@ public enum ScrimState { return mBehindAlpha; } + public float getMaxLightRevealScrimAlpha() { + return 1f; + } + public float getNotifAlpha() { return mNotifAlpha; } 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 5d2fe523c803..3f07785520cf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -1473,9 +1473,7 @@ public class StatusBar extends SystemUI implements DemoMode, * @param why the reason for the wake up */ public void wakeUpIfDozing(long time, View where, String why) { - if (mDozing && !(mKeyguardViewMediator.isAnimatingScreenOff() - || mUnlockedScreenOffAnimationController - .isScreenOffLightRevealAnimationPlaying())) { + if (mDozing && !mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying()) { mPowerManager.wakeUp( time, PowerManager.WAKE_REASON_GESTURE, "com.android.systemui:" + why); mWakeUpComingFromTouch = true; @@ -4444,6 +4442,8 @@ public class StatusBar extends SystemUI implements DemoMode, } else { mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback); } + updateLightRevealScrimVisibility(); + Trace.endSection(); } @@ -4894,6 +4894,7 @@ public class StatusBar extends SystemUI implements DemoMode, return; } + mLightRevealScrim.setAlpha(mScrimController.getState().getMaxLightRevealScrimAlpha()); if (mFeatureFlags.useNewLockscreenAnimations() && (mDozeParameters.getAlwaysOn() || mDozeParameters.isQuickPickupEnabled())) { mLightRevealScrim.setVisibility(View.VISIBLE); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt index 52bf2d577776..9a04d39c4e9e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt @@ -172,7 +172,8 @@ class UnlockedScreenOffAnimationController @Inject constructor( // We currently draw both the light reveal scrim, and the AOD UI, in the shade. If it's // already expanded and showing notifications/QS, the animation looks really messy. For now, // disable it if the notification panel is expanded. - if (statusBar.notificationPanelViewController.isFullyExpanded) { + if (!this::statusBar.isInitialized || + statusBar.notificationPanelViewController.isFullyExpanded) { return false } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java index ce080752b5cc..2ac5c1eeae8e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java @@ -387,15 +387,8 @@ public class MobileSignalController extends SignalController<MobileState, Mobile int qsTypeIcon = 0; IconState qsIcon = null; CharSequence description = null; - // Mobile icon will only be shown in the statusbar in 2 scenarios - // 1. Mobile is the default network, and it is validated - // 2. Mobile is the default network, it is not validated and there is no other - // non-Carrier WiFi networks available. - boolean maybeShowIcons = (mCurrentState.inetCondition == 1) - || (mCurrentState.inetCondition == 0 - && !mNetworkController.isNonCarrierWifiNetworkAvailable()); // Only send data sim callbacks to QS. - if (mCurrentState.dataSim && mCurrentState.isDefault && maybeShowIcons) { + if (mCurrentState.dataSim && mCurrentState.isDefault) { qsTypeIcon = (showDataIcon || mConfig.alwaysShowDataRatIcon) ? icons.qsDataType : 0; qsIcon = new IconState(mCurrentState.enabled @@ -408,7 +401,7 @@ public class MobileSignalController extends SignalController<MobileState, Mobile boolean activityOut = mCurrentState.dataConnected && !mCurrentState.carrierNetworkChangeMode && mCurrentState.activityOut; - showDataIcon &= mCurrentState.dataSim && mCurrentState.isDefault && maybeShowIcons; + showDataIcon &= mCurrentState.dataSim && mCurrentState.isDefault; boolean showTriangle = showDataIcon && !mCurrentState.airplaneMode; int typeIcon = (showDataIcon || mConfig.alwaysShowDataRatIcon) ? icons.dataType : 0; showDataIcon |= mCurrentState.roaming; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java index 753def0b0f1c..2406db3ee58f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java @@ -109,17 +109,10 @@ public class WifiSignalController extends contentDescription += ("," + mContext.getString(R.string.data_connection_no_internet)); } if (mProviderModel) { - // WiFi icon will only be shown in the statusbar in 2 scenarios - // 1. WiFi is the default network, and it is validated - // 2. WiFi is the default network, it is not validated and there is no other - // non-Carrier WiFi networks available. - boolean maybeShowIcons = (mCurrentState.inetCondition == 1) - || (mCurrentState.inetCondition == 0 - && !mNetworkController.isNonCarrierWifiNetworkAvailable()); IconState statusIcon = new IconState( - wifiVisible && maybeShowIcons, getCurrentIconId(), contentDescription); + wifiVisible, getCurrentIconId(), contentDescription); IconState qsIcon = null; - if ((mCurrentState.isDefault && maybeShowIcons) || (!mNetworkController.isRadioOn() + if (mCurrentState.isDefault || (!mNetworkController.isRadioOn() && !mNetworkController.isEthernetDefault())) { qsIcon = new IconState(mCurrentState.connected, mWifiTracker.isCaptivePortal ? R.drawable.ic_qs_wifi_disconnected @@ -158,15 +151,8 @@ public class WifiSignalController extends if (mCurrentState.inetCondition == 0) { dataContentDescription = mContext.getString(R.string.data_connection_no_internet); } - // Mobile icon will only be shown in the statusbar in 2 scenarios - // 1. Mobile is the default network, and it is validated - // 2. Mobile is the default network, it is not validated and there is no other - // non-Carrier WiFi networks available. - boolean maybeShowIcons = (mCurrentState.inetCondition == 1) - || (mCurrentState.inetCondition == 0 - && !mNetworkController.isNonCarrierWifiNetworkAvailable()); boolean sbVisible = mCurrentState.enabled && mCurrentState.connected - && maybeShowIcons && mCurrentState.isDefault; + && mCurrentState.isDefault; IconState statusIcon = new IconState(sbVisible, getCurrentIconIdForCarrierWifi(), contentDescription); int typeIcon = sbVisible ? icons.dataType : 0; diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java index a11b9cf357a8..10997fab081f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java @@ -209,33 +209,14 @@ public class DozeTriggersTest extends SysuiTestCase { // WHEN quick pick up is triggered mTriggers.onSensor(DozeLog.REASON_SENSOR_QUICK_PICKUP, 100, 100, null); - // THEN device goes into aod (shows clock with black background) - verify(mMachine).requestState(DOZE_AOD); + // THEN request pulse + verify(mMachine).requestPulse(anyInt()); // THEN a log is taken that quick pick up was triggered verify(mUiEventLogger).log(DozingUpdateUiEvent.DOZING_UPDATE_QUICK_PICKUP); } @Test - public void testQuickPickupTimeOutAfterExecutables() { - // GIVEN quick pickup is triggered when device is in DOZE - when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE); - mTriggers.onSensor(DozeLog.REASON_SENSOR_QUICK_PICKUP, 100, 100, null); - verify(mMachine).requestState(DOZE_AOD); - verify(mMachine, never()).requestState(DozeMachine.State.DOZE); - - // WHEN next executable is run - mExecutor.advanceClockToLast(); - mExecutor.runAllReady(); - - // THEN device goes back into DOZE - verify(mMachine).requestState(DozeMachine.State.DOZE); - - // THEN a log is taken that wake up timeout expired - verify(mUiEventLogger).log(DozingUpdateUiEvent.DOZING_UPDATE_WAKE_TIMEOUT); - } - - @Test public void testOnSensor_Fingerprint() { // GIVEN dozing state when(mMachine.getState()).thenReturn(DOZE_AOD); diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java index e20b426907be..66b64708ad24 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java @@ -82,9 +82,11 @@ public class MediaDataCombineLatestTest extends SysuiTestCase { @Test public void eventNotEmittedWithoutDevice() { // WHEN data source emits an event without device data - mManager.onMediaDataLoaded(KEY, null, mMediaData, true /* immediately */); + mManager.onMediaDataLoaded(KEY, null, mMediaData, true /* immediately */, + false /* isSsReactivated */); // THEN an event isn't emitted - verify(mListener, never()).onMediaDataLoaded(eq(KEY), any(), any(), anyBoolean()); + verify(mListener, never()).onMediaDataLoaded(eq(KEY), any(), any(), anyBoolean(), + anyBoolean()); } @Test @@ -92,7 +94,8 @@ public class MediaDataCombineLatestTest extends SysuiTestCase { // WHEN device source emits an event without media data mManager.onMediaDeviceChanged(KEY, null, mDeviceData); // THEN an event isn't emitted - verify(mListener, never()).onMediaDataLoaded(eq(KEY), any(), any(), anyBoolean()); + verify(mListener, never()).onMediaDataLoaded(eq(KEY), any(), any(), anyBoolean(), + anyBoolean()); } @Test @@ -100,80 +103,95 @@ public class MediaDataCombineLatestTest extends SysuiTestCase { // GIVEN that a device event has already been received mManager.onMediaDeviceChanged(KEY, null, mDeviceData); // WHEN media event is received - mManager.onMediaDataLoaded(KEY, null, mMediaData, true /* immediately */); + mManager.onMediaDataLoaded(KEY, null, mMediaData, true /* immediately */, + false /* isSsReactivated */); // THEN the listener receives a combined event ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class); - verify(mListener).onMediaDataLoaded(eq(KEY), any(), captor.capture(), anyBoolean()); + verify(mListener).onMediaDataLoaded(eq(KEY), any(), captor.capture(), anyBoolean(), + anyBoolean()); assertThat(captor.getValue().getDevice()).isNotNull(); } @Test public void emitEventAfterMediaFirst() { // GIVEN that media event has already been received - mManager.onMediaDataLoaded(KEY, null, mMediaData, true /* immediately */); + mManager.onMediaDataLoaded(KEY, null, mMediaData, true /* immediately */, + false /* isSsReactivated */); // WHEN device event is received mManager.onMediaDeviceChanged(KEY, null, mDeviceData); // THEN the listener receives a combined event ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class); - verify(mListener).onMediaDataLoaded(eq(KEY), any(), captor.capture(), anyBoolean()); + verify(mListener).onMediaDataLoaded(eq(KEY), any(), captor.capture(), anyBoolean(), + anyBoolean()); assertThat(captor.getValue().getDevice()).isNotNull(); } @Test public void migrateKeyMediaFirst() { // GIVEN that media and device info has already been received - mManager.onMediaDataLoaded(OLD_KEY, null, mMediaData, true /* immediately */); + mManager.onMediaDataLoaded(OLD_KEY, null, mMediaData, true /* immediately */, + false /* isSsReactivated */); mManager.onMediaDeviceChanged(OLD_KEY, null, mDeviceData); reset(mListener); // WHEN a key migration event is received - mManager.onMediaDataLoaded(KEY, OLD_KEY, mMediaData, true /* immediately */); + mManager.onMediaDataLoaded(KEY, OLD_KEY, mMediaData, true /* immediately */, + false /* isSsReactivated */); // THEN the listener receives a combined event ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class); - verify(mListener).onMediaDataLoaded(eq(KEY), eq(OLD_KEY), captor.capture(), anyBoolean()); + verify(mListener).onMediaDataLoaded(eq(KEY), eq(OLD_KEY), captor.capture(), anyBoolean(), + anyBoolean()); assertThat(captor.getValue().getDevice()).isNotNull(); } @Test public void migrateKeyDeviceFirst() { // GIVEN that media and device info has already been received - mManager.onMediaDataLoaded(OLD_KEY, null, mMediaData, true /* immediately */); + mManager.onMediaDataLoaded(OLD_KEY, null, mMediaData, true /* immediately */, + false /* isSsReactivated */); mManager.onMediaDeviceChanged(OLD_KEY, null, mDeviceData); reset(mListener); // WHEN a key migration event is received mManager.onMediaDeviceChanged(KEY, OLD_KEY, mDeviceData); // THEN the listener receives a combined event ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class); - verify(mListener).onMediaDataLoaded(eq(KEY), eq(OLD_KEY), captor.capture(), anyBoolean()); + verify(mListener).onMediaDataLoaded(eq(KEY), eq(OLD_KEY), captor.capture(), anyBoolean(), + anyBoolean()); assertThat(captor.getValue().getDevice()).isNotNull(); } @Test public void migrateKeyMediaAfter() { // GIVEN that media and device info has already been received - mManager.onMediaDataLoaded(OLD_KEY, null, mMediaData, true /* immediately */); + mManager.onMediaDataLoaded(OLD_KEY, null, mMediaData, true /* immediately */, + false /* isSsReactivated */); mManager.onMediaDeviceChanged(OLD_KEY, null, mDeviceData); mManager.onMediaDeviceChanged(KEY, OLD_KEY, mDeviceData); reset(mListener); // WHEN a second key migration event is received for media - mManager.onMediaDataLoaded(KEY, OLD_KEY, mMediaData, true /* immediately */); + mManager.onMediaDataLoaded(KEY, OLD_KEY, mMediaData, true /* immediately */, + false /* isSsReactivated */); // THEN the key has already been migrated ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class); - verify(mListener).onMediaDataLoaded(eq(KEY), eq(KEY), captor.capture(), anyBoolean()); + verify(mListener).onMediaDataLoaded(eq(KEY), eq(KEY), captor.capture(), anyBoolean(), + anyBoolean()); assertThat(captor.getValue().getDevice()).isNotNull(); } @Test public void migrateKeyDeviceAfter() { // GIVEN that media and device info has already been received - mManager.onMediaDataLoaded(OLD_KEY, null, mMediaData, true /* immediately */); + mManager.onMediaDataLoaded(OLD_KEY, null, mMediaData, true /* immediately */, + false /* isSsReactivated */); mManager.onMediaDeviceChanged(OLD_KEY, null, mDeviceData); - mManager.onMediaDataLoaded(KEY, OLD_KEY, mMediaData, true /* immediately */); + mManager.onMediaDataLoaded(KEY, OLD_KEY, mMediaData, true /* immediately */, + false /* isSsReactivated */); reset(mListener); // WHEN a second key migration event is received for the device mManager.onMediaDeviceChanged(KEY, OLD_KEY, mDeviceData); // THEN the key has already be migrated ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class); - verify(mListener).onMediaDataLoaded(eq(KEY), eq(KEY), captor.capture(), anyBoolean()); + verify(mListener).onMediaDataLoaded(eq(KEY), eq(KEY), captor.capture(), anyBoolean(), + anyBoolean()); assertThat(captor.getValue().getDevice()).isNotNull(); } @@ -187,7 +205,8 @@ public class MediaDataCombineLatestTest extends SysuiTestCase { @Test public void mediaDataRemovedAfterMediaEvent() { - mManager.onMediaDataLoaded(KEY, null, mMediaData, true /* immediately */); + mManager.onMediaDataLoaded(KEY, null, mMediaData, true /* immediately */, + false /* isSsReactivated */); mManager.onMediaDataRemoved(KEY); verify(mListener).onMediaDataRemoved(eq(KEY)); } @@ -202,13 +221,15 @@ public class MediaDataCombineLatestTest extends SysuiTestCase { @Test public void mediaDataKeyUpdated() { // GIVEN that device and media events have already been received - mManager.onMediaDataLoaded(KEY, null, mMediaData, true /* immediately */); + mManager.onMediaDataLoaded(KEY, null, mMediaData, true /* immediately */, + false /* isSsReactivated */); mManager.onMediaDeviceChanged(KEY, null, mDeviceData); // WHEN the key is changed - mManager.onMediaDataLoaded("NEW_KEY", KEY, mMediaData, true /* immediately */); + mManager.onMediaDataLoaded("NEW_KEY", KEY, mMediaData, true /* immediately */, + false /* isSsReactivated */); // THEN the listener gets a load event with the correct keys ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class); verify(mListener).onMediaDataLoaded( - eq("NEW_KEY"), any(), captor.capture(), anyBoolean()); + eq("NEW_KEY"), any(), captor.capture(), anyBoolean(), anyBoolean()); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt index 17f2a07eb249..d8791867cb45 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt @@ -120,7 +120,8 @@ class MediaDataFilterTest : SysuiTestCase() { mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain) // THEN we should tell the listener - verify(listener).onMediaDataLoaded(eq(KEY), eq(null), eq(dataMain), eq(true)) + verify(listener).onMediaDataLoaded(eq(KEY), eq(null), eq(dataMain), eq(true), + eq(false)) } @Test @@ -129,7 +130,7 @@ class MediaDataFilterTest : SysuiTestCase() { mediaDataFilter.onMediaDataLoaded(KEY, null, dataGuest) // THEN we should NOT tell the listener - verify(listener, never()).onMediaDataLoaded(any(), any(), any(), anyBoolean()) + verify(listener, never()).onMediaDataLoaded(any(), any(), any(), anyBoolean(), anyBoolean()) } @Test @@ -175,10 +176,12 @@ class MediaDataFilterTest : SysuiTestCase() { setUser(USER_GUEST) // THEN we should add back the guest user media - verify(listener).onMediaDataLoaded(eq(KEY_ALT), eq(null), eq(dataGuest), eq(true)) + verify(listener).onMediaDataLoaded(eq(KEY_ALT), eq(null), eq(dataGuest), eq(true), + eq(false)) // but not the main user's - verify(listener, never()).onMediaDataLoaded(eq(KEY), any(), eq(dataMain), anyBoolean()) + verify(listener, never()).onMediaDataLoaded(eq(KEY), any(), eq(dataMain), anyBoolean(), + anyBoolean()) } @Test @@ -245,7 +248,7 @@ class MediaDataFilterTest : SysuiTestCase() { mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) - verify(listener, never()).onMediaDataLoaded(any(), any(), any(), anyBoolean()) + verify(listener, never()).onMediaDataLoaded(any(), any(), any(), anyBoolean(), anyBoolean()) verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean()) assertThat(mediaDataFilter.hasActiveMedia()).isFalse() } @@ -282,12 +285,15 @@ class MediaDataFilterTest : SysuiTestCase() { // WHEN we have media that was recently played, but not currently active val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) - verify(listener).onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true)) + verify(listener).onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), + eq(false)) // AND we get a smartspace signal mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) - // THEN we should tell listeners to treat the media as active instead + // THEN we should tell listeners to treat the media as not active instead + verify(listener, never()).onMediaDataLoaded(eq(KEY), eq(KEY), any(), anyBoolean(), + anyBoolean()) verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean()) assertThat(mediaDataFilter.hasActiveMedia()).isFalse() } @@ -299,14 +305,16 @@ class MediaDataFilterTest : SysuiTestCase() { // WHEN we have media that was recently played, but not currently active val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) - verify(listener).onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true)) + verify(listener).onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), + eq(false)) // AND we get a smartspace signal mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) // THEN we should tell listeners to treat the media as active instead val dataCurrentAndActive = dataCurrent.copy(active = true) - verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), eq(dataCurrentAndActive), eq(true)) + verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), eq(dataCurrentAndActive), eq(true), + eq(true)) assertThat(mediaDataFilter.hasActiveMedia()).isTrue() // Smartspace update shouldn't be propagated for the empty rec list. verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean()) @@ -317,14 +325,16 @@ class MediaDataFilterTest : SysuiTestCase() { // WHEN we have media that was recently played, but not currently active val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) - verify(listener).onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true)) + verify(listener).onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), + eq(false)) // AND we get a smartspace signal mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) // THEN we should tell listeners to treat the media as active instead val dataCurrentAndActive = dataCurrent.copy(active = true) - verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), eq(dataCurrentAndActive), eq(true)) + verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), eq(dataCurrentAndActive), eq(true), + eq(true)) assertThat(mediaDataFilter.hasActiveMedia()).isTrue() // Smartspace update should also be propagated but not prioritized. verify(listener) @@ -344,11 +354,17 @@ class MediaDataFilterTest : SysuiTestCase() { fun testOnSmartspaceMediaDataRemoved_usedMediaAndSmartspace_clearsBoth() { val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) + verify(listener).onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), + eq(false)) + mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) + val dataCurrentAndActive = dataCurrent.copy(active = true) + verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), eq(dataCurrentAndActive), eq(true), + eq(true)) + mediaDataFilter.onSmartspaceMediaDataRemoved(SMARTSPACE_KEY) - verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), eq(dataCurrent), eq(true)) verify(listener).onSmartspaceMediaDataRemoved(SMARTSPACE_KEY) assertThat(mediaDataFilter.hasActiveMedia()).isFalse() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt index 3128db423a24..5b4e12463370 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt @@ -185,7 +185,8 @@ class MediaDataManagerTest : SysuiTestCase() { fun testOnMetaDataLoaded_callsListener() { mediaDataManager.onNotificationAdded(KEY, mediaNotification) mediaDataManager.onMediaDataLoaded(KEY, oldKey = null, data = mock(MediaData::class.java)) - verify(listener).onMediaDataLoaded(eq(KEY), eq(null), anyObject(), eq(true)) + verify(listener).onMediaDataLoaded(eq(KEY), eq(null), anyObject(), eq(true), + eq(false)) } @Test @@ -196,7 +197,8 @@ class MediaDataManagerTest : SysuiTestCase() { mediaDataManager.onNotificationAdded(KEY, mediaNotification) assertThat(backgroundExecutor.runAllReady()).isEqualTo(1) assertThat(foregroundExecutor.runAllReady()).isEqualTo(1) - verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true)) + verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true), + eq(false)) assertThat(mediaDataCaptor.value!!.active).isTrue() } @@ -215,7 +217,8 @@ class MediaDataManagerTest : SysuiTestCase() { mediaDataManager.onNotificationAdded(KEY, mediaNotification) assertThat(backgroundExecutor.runAllReady()).isEqualTo(1) assertThat(foregroundExecutor.runAllReady()).isEqualTo(1) - verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true)) + verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true), + eq(false)) val data = mediaDataCaptor.value assertThat(data.resumption).isFalse() mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {})) @@ -223,7 +226,8 @@ class MediaDataManagerTest : SysuiTestCase() { mediaDataManager.onNotificationRemoved(KEY) // THEN the media data indicates that it is for resumption verify(listener) - .onMediaDataLoaded(eq(PACKAGE_NAME), eq(KEY), capture(mediaDataCaptor), eq(true)) + .onMediaDataLoaded(eq(PACKAGE_NAME), eq(KEY), capture(mediaDataCaptor), eq(true), + eq(false)) assertThat(mediaDataCaptor.value.resumption).isTrue() } @@ -236,7 +240,8 @@ class MediaDataManagerTest : SysuiTestCase() { assertThat(backgroundExecutor.runAllReady()).isEqualTo(2) assertThat(foregroundExecutor.runAllReady()).isEqualTo(2) verify(listener) - .onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true)) + .onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true), + eq(false)) val data = mediaDataCaptor.value assertThat(data.resumption).isFalse() val resumableData = data.copy(resumeAction = Runnable {}) @@ -247,7 +252,8 @@ class MediaDataManagerTest : SysuiTestCase() { mediaDataManager.onNotificationRemoved(KEY) // THEN the data is for resumption and the key is migrated to the package name verify(listener) - .onMediaDataLoaded(eq(PACKAGE_NAME), eq(KEY), capture(mediaDataCaptor), eq(true)) + .onMediaDataLoaded(eq(PACKAGE_NAME), eq(KEY), capture(mediaDataCaptor), eq(true), + eq(false)) assertThat(mediaDataCaptor.value.resumption).isTrue() verify(listener, never()).onMediaDataRemoved(eq(KEY)) // WHEN the second is removed @@ -255,7 +261,8 @@ class MediaDataManagerTest : SysuiTestCase() { // THEN the data is for resumption and the second key is removed verify(listener) .onMediaDataLoaded( - eq(PACKAGE_NAME), eq(PACKAGE_NAME), capture(mediaDataCaptor), eq(true)) + eq(PACKAGE_NAME), eq(PACKAGE_NAME), capture(mediaDataCaptor), eq(true), + eq(false)) assertThat(mediaDataCaptor.value.resumption).isTrue() verify(listener).onMediaDataRemoved(eq(KEY_2)) } @@ -269,7 +276,8 @@ class MediaDataManagerTest : SysuiTestCase() { mediaDataManager.onNotificationAdded(KEY, mediaNotification) assertThat(backgroundExecutor.runAllReady()).isEqualTo(1) assertThat(foregroundExecutor.runAllReady()).isEqualTo(1) - verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true)) + verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true), + eq(false)) val data = mediaDataCaptor.value val dataRemoteWithResume = data.copy(resumeAction = Runnable {}, isLocalSession = false) mediaDataManager.onMediaDataLoaded(KEY, null, dataRemoteWithResume) @@ -295,7 +303,8 @@ class MediaDataManagerTest : SysuiTestCase() { assertThat(foregroundExecutor.runAllReady()).isEqualTo(1) // THEN the media data indicates that it is for resumption verify(listener) - .onMediaDataLoaded(eq(PACKAGE_NAME), eq(null), capture(mediaDataCaptor), eq(true)) + .onMediaDataLoaded(eq(PACKAGE_NAME), eq(null), capture(mediaDataCaptor), eq(true), + eq(false)) val data = mediaDataCaptor.value assertThat(data.resumption).isTrue() assertThat(data.song).isEqualTo(SESSION_TITLE) @@ -335,7 +344,8 @@ class MediaDataManagerTest : SysuiTestCase() { assertThat(backgroundExecutor.runAllReady()).isEqualTo(1) assertThat(foregroundExecutor.runAllReady()).isEqualTo(1) verify(listener) - .onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true)) + .onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true), + eq(false)) } @Test @@ -414,7 +424,8 @@ class MediaDataManagerTest : SysuiTestCase() { mediaDataManager.onNotificationAdded(KEY, mediaNotification) assertThat(backgroundExecutor.runAllReady()).isEqualTo(1) assertThat(foregroundExecutor.runAllReady()).isEqualTo(1) - verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true)) + verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true), + eq(false)) assertThat(mediaDataCaptor.value!!.lastActive).isAtLeast(currentTime) } @@ -431,7 +442,8 @@ class MediaDataManagerTest : SysuiTestCase() { mediaDataManager.setTimedOut(KEY, true, true) // THEN the last active time is not changed - verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), capture(mediaDataCaptor), eq(true)) + verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), capture(mediaDataCaptor), eq(true), + eq(false)) assertThat(mediaDataCaptor.value.lastActive).isLessThan(currentTime) } @@ -442,7 +454,8 @@ class MediaDataManagerTest : SysuiTestCase() { mediaDataManager.onNotificationAdded(KEY, mediaNotification) assertThat(backgroundExecutor.runAllReady()).isEqualTo(1) assertThat(foregroundExecutor.runAllReady()).isEqualTo(1) - verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true)) + verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true), + eq(false)) val data = mediaDataCaptor.value assertThat(data.resumption).isFalse() mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {})) @@ -454,7 +467,8 @@ class MediaDataManagerTest : SysuiTestCase() { // THEN the last active time is not changed verify(listener) - .onMediaDataLoaded(eq(PACKAGE_NAME), eq(KEY), capture(mediaDataCaptor), eq(true)) + .onMediaDataLoaded(eq(PACKAGE_NAME), eq(KEY), capture(mediaDataCaptor), eq(true), + eq(false)) assertThat(mediaDataCaptor.value.resumption).isTrue() assertThat(mediaDataCaptor.value.lastActive).isLessThan(currentTime) } @@ -480,7 +494,8 @@ class MediaDataManagerTest : SysuiTestCase() { assertThat(foregroundExecutor.runAllReady()).isEqualTo(1) // THEN only the first MAX_COMPACT_ACTIONS are actually set - verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true)) + verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true), + eq(false)) assertThat(mediaDataCaptor.value.actionsToShowInCompact.size).isEqualTo( MediaDataManager.MAX_COMPACT_ACTIONS) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaSessionBasedFilterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaSessionBasedFilterTest.kt index c6d7e92175eb..b9caab277c4c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaSessionBasedFilterTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaSessionBasedFilterTest.kt @@ -185,7 +185,8 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() { filter.onMediaDataLoaded(KEY, null, mediaData1) bgExecutor.runAllReady() fgExecutor.runAllReady() - verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true)) + verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true), + eq(false)) } @Test @@ -207,7 +208,8 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() { bgExecutor.runAllReady() fgExecutor.runAllReady() // THEN the event is not filtered - verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true)) + verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true), + eq(false)) } @Test @@ -236,7 +238,8 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() { bgExecutor.runAllReady() fgExecutor.runAllReady() // THEN the event is not filtered - verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true)) + verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true), + eq(false)) } @Test @@ -251,14 +254,15 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() { bgExecutor.runAllReady() fgExecutor.runAllReady() // THEN the event is not filtered - verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true)) + verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true), + eq(false)) // WHEN a loaded event is received that matches the local session filter.onMediaDataLoaded(KEY, null, mediaData2) bgExecutor.runAllReady() fgExecutor.runAllReady() // THEN the event is filtered verify(mediaListener, never()).onMediaDataLoaded( - eq(KEY), eq(null), eq(mediaData2), anyBoolean()) + eq(KEY), eq(null), eq(mediaData2), anyBoolean(), anyBoolean()) } @Test @@ -274,7 +278,8 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() { fgExecutor.runAllReady() // THEN the event is not filtered because there isn't a notification for the remote // session. - verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true)) + verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true), + eq(false)) } @Test @@ -291,14 +296,15 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() { bgExecutor.runAllReady() fgExecutor.runAllReady() // THEN the event is not filtered - verify(mediaListener).onMediaDataLoaded(eq(key1), eq(null), eq(mediaData1), eq(true)) + verify(mediaListener).onMediaDataLoaded(eq(key1), eq(null), eq(mediaData1), eq(true), + eq(false)) // WHEN a loaded event is received that matches the local session filter.onMediaDataLoaded(key2, null, mediaData2) bgExecutor.runAllReady() fgExecutor.runAllReady() // THEN the event is filtered verify(mediaListener, never()) - .onMediaDataLoaded(eq(key2), eq(null), eq(mediaData2), anyBoolean()) + .onMediaDataLoaded(eq(key2), eq(null), eq(mediaData2), anyBoolean(), anyBoolean()) // AND there should be a removed event for key2 verify(mediaListener).onMediaDataRemoved(eq(key2)) } @@ -317,13 +323,15 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() { bgExecutor.runAllReady() fgExecutor.runAllReady() // THEN the event is not filtered - verify(mediaListener).onMediaDataLoaded(eq(key1), eq(null), eq(mediaData1), eq(true)) + verify(mediaListener).onMediaDataLoaded(eq(key1), eq(null), eq(mediaData1), eq(true), + eq(false)) // WHEN a loaded event is received that matches the remote session filter.onMediaDataLoaded(key2, null, mediaData2) bgExecutor.runAllReady() fgExecutor.runAllReady() // THEN the event is not filtered - verify(mediaListener).onMediaDataLoaded(eq(key2), eq(null), eq(mediaData2), eq(true)) + verify(mediaListener).onMediaDataLoaded(eq(key2), eq(null), eq(mediaData2), eq(true), + eq(false)) } @Test @@ -339,13 +347,15 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() { bgExecutor.runAllReady() fgExecutor.runAllReady() // THEN the event is not filtered - verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true)) + verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true), + eq(false)) // WHEN a loaded event is received that matches the local session filter.onMediaDataLoaded(KEY, null, mediaData2) bgExecutor.runAllReady() fgExecutor.runAllReady() // THEN the event is not filtered - verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData2), eq(true)) + verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData2), eq(true), + eq(false)) } @Test @@ -363,7 +373,8 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() { bgExecutor.runAllReady() fgExecutor.runAllReady() // THEN the event is not filtered - verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true)) + verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true), + eq(false)) } @Test @@ -385,7 +396,8 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() { bgExecutor.runAllReady() fgExecutor.runAllReady() // THEN the key migration event is fired - verify(mediaListener).onMediaDataLoaded(eq(key2), eq(key1), eq(mediaData2), eq(true)) + verify(mediaListener).onMediaDataLoaded(eq(key2), eq(key1), eq(mediaData2), eq(true), + eq(false)) } @Test @@ -415,12 +427,13 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() { fgExecutor.runAllReady() // THEN the key migration event is filtered verify(mediaListener, never()) - .onMediaDataLoaded(eq(key2), eq(null), eq(mediaData2), anyBoolean()) + .onMediaDataLoaded(eq(key2), eq(null), eq(mediaData2), anyBoolean(), anyBoolean()) // WHEN a loaded event is received that matches the remote session filter.onMediaDataLoaded(key2, null, mediaData1) bgExecutor.runAllReady() fgExecutor.runAllReady() // THEN the key migration event is fired - verify(mediaListener).onMediaDataLoaded(eq(key2), eq(null), eq(mediaData1), eq(true)) + verify(mediaListener).onMediaDataLoaded(eq(key2), eq(null), eq(mediaData1), eq(true), + eq(false)) } } 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 e55361e750b1..678b193073c2 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 @@ -312,6 +312,8 @@ public class ScrimControllerTest extends SysuiTestCase { mScrimBehind, true, mScrimForBubble, false )); + + assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f); } @Test @@ -321,8 +323,9 @@ public class ScrimControllerTest extends SysuiTestCase { assertScrimAlpha(Map.of( mScrimInFront, TRANSPARENT, - mScrimBehind, OPAQUE, + mScrimBehind, TRANSPARENT, mNotificationsScrim, TRANSPARENT)); + assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f); assertScrimTinted(Map.of( mScrimInFront, true, @@ -340,6 +343,7 @@ public class ScrimControllerTest extends SysuiTestCase { assertScrimAlpha(Map.of( mScrimInFront, TRANSPARENT, mScrimBehind, TRANSPARENT)); + assertEquals(0f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f); // Pulsing notification should conserve AOD wallpaper. mScrimController.transitionTo(ScrimState.PULSING); @@ -348,6 +352,7 @@ public class ScrimControllerTest extends SysuiTestCase { assertScrimAlpha(Map.of( mScrimInFront, TRANSPARENT, mScrimBehind, TRANSPARENT)); + assertEquals(0f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f); } @Test @@ -359,7 +364,8 @@ public class ScrimControllerTest extends SysuiTestCase { assertScrimAlpha(Map.of( mScrimInFront, TRANSPARENT, - mScrimBehind, OPAQUE)); + mScrimBehind, TRANSPARENT)); + assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f); assertScrimTinted(Map.of( mScrimInFront, true, @@ -378,7 +384,8 @@ public class ScrimControllerTest extends SysuiTestCase { assertScrimAlpha(Map.of( mScrimInFront, TRANSPARENT, - mScrimBehind, OPAQUE)); + mScrimBehind, TRANSPARENT)); + assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f); assertScrimTinted(Map.of( mScrimInFront, true, @@ -403,13 +410,15 @@ public class ScrimControllerTest extends SysuiTestCase { finishAnimationsImmediately(); assertScrimAlpha(Map.of( mScrimInFront, SEMI_TRANSPARENT, - mScrimBehind, OPAQUE)); + mScrimBehind, TRANSPARENT)); + assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f); // ... and that if we set it while we're in AOD, it does take immediate effect. mScrimController.setAodFrontScrimAlpha(1f); assertScrimAlpha(Map.of( mScrimInFront, OPAQUE, - mScrimBehind, OPAQUE)); + mScrimBehind, TRANSPARENT)); + assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f); // ... and make sure we recall the previous front scrim alpha even if we transition away // for a bit. @@ -418,7 +427,8 @@ public class ScrimControllerTest extends SysuiTestCase { finishAnimationsImmediately(); assertScrimAlpha(Map.of( mScrimInFront, OPAQUE, - mScrimBehind, OPAQUE)); + mScrimBehind, TRANSPARENT)); + assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f); // ... and alpha updates should be completely ignored if always_on is off. // Passing it forward would mess up the wake-up transition. @@ -448,23 +458,28 @@ public class ScrimControllerTest extends SysuiTestCase { finishAnimationsImmediately(); assertScrimAlpha(Map.of( mScrimInFront, OPAQUE, - mScrimBehind, OPAQUE)); + mScrimBehind, TRANSPARENT)); + assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f); // ... but will take effect after docked when(mDockManager.isDocked()).thenReturn(true); mScrimController.transitionTo(ScrimState.KEYGUARD); mScrimController.setAodFrontScrimAlpha(0.5f); mScrimController.transitionTo(ScrimState.AOD); + finishAnimationsImmediately(); assertScrimAlpha(Map.of( mScrimInFront, SEMI_TRANSPARENT, - mScrimBehind, OPAQUE)); + mScrimBehind, TRANSPARENT)); + assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f); // ... and that if we set it while we're in AOD, it does take immediate effect after docked. mScrimController.setAodFrontScrimAlpha(1f); + finishAnimationsImmediately(); assertScrimAlpha(Map.of( mScrimInFront, OPAQUE, - mScrimBehind, OPAQUE)); + mScrimBehind, TRANSPARENT)); + assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f); // Reset value since enums are static. mScrimController.setAodFrontScrimAlpha(0f); @@ -480,7 +495,8 @@ public class ScrimControllerTest extends SysuiTestCase { finishAnimationsImmediately(); assertScrimAlpha(Map.of( mScrimInFront, TRANSPARENT, - mScrimBehind, OPAQUE)); + mScrimBehind, TRANSPARENT)); + assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f); mScrimController.transitionTo(ScrimState.PULSING); finishAnimationsImmediately(); @@ -489,7 +505,8 @@ public class ScrimControllerTest extends SysuiTestCase { // Pulse callback should have been invoked assertScrimAlpha(Map.of( mScrimInFront, TRANSPARENT, - mScrimBehind, OPAQUE)); + mScrimBehind, TRANSPARENT)); + assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f); assertScrimTinted(Map.of( mScrimInFront, true, @@ -503,13 +520,16 @@ public class ScrimControllerTest extends SysuiTestCase { // Front scrim should be semi-transparent assertScrimAlpha(Map.of( mScrimInFront, SEMI_TRANSPARENT, - mScrimBehind, OPAQUE)); + mScrimBehind, TRANSPARENT)); + assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f); mScrimController.setWakeLockScreenSensorActive(true); finishAnimationsImmediately(); assertScrimAlpha(Map.of( mScrimInFront, SEMI_TRANSPARENT, - mScrimBehind, SEMI_TRANSPARENT)); + mScrimBehind, TRANSPARENT)); + assertEquals(ScrimController.WAKE_SENSOR_SCRIM_ALPHA, + mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f); // Reset value since enums are static. mScrimController.setAodFrontScrimAlpha(0f); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java index 521b958ab891..bd9d1a7fd657 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java @@ -238,9 +238,7 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest { mNetworkController.setNoNetworksAvailable(false); setWifiStateForVcn(true, testSsid); setWifiLevelForVcn(0); - // Connected, but still not validated - does not show - //verifyLastWifiIcon(false, WifiIcons.WIFI_SIGNAL_STRENGTH[0][0]); - verifyLastMobileDataIndicatorsForVcn(false, 0, 0, false); + verifyLastMobileDataIndicatorsForVcn(true, 0, TelephonyIcons.ICON_CWF, false); mNetworkController.setNoNetworksAvailable(true); for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) { diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlConversionUtils.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlConversionUtils.java index f1f94564c35d..0ae2e381cf14 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlConversionUtils.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlConversionUtils.java @@ -80,8 +80,7 @@ final class AidlConversionUtils { // No framework constant available return BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_UNKNOWN; } else if (aidlAcquiredInfo == AcquiredInfo.IMMOBILE) { - // No framework constant available - return BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_UNKNOWN; + return BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_IMMOBILE; } else if (aidlAcquiredInfo == AcquiredInfo.RETRYING_CAPTURE) { // No framework constant available return BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_UNKNOWN; 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 160736433112..8d777e1c2787 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 @@ -124,10 +124,12 @@ class FingerprintDetectClient extends AcquisitionClient<IBiometricsFingerprint> final PerformanceTracker pm = PerformanceTracker.getInstanceForSensorId(getSensorId()); pm.incrementAuthForUser(getTargetUserId(), authenticated); - try { - getListener().onDetected(getSensorId(), getTargetUserId(), mIsStrongBiometric); - } catch (RemoteException e) { - Slog.e(TAG, "Remote exception when sending onDetected", e); + if (getListener() != null) { + try { + getListener().onDetected(getSensorId(), getTargetUserId(), mIsStrongBiometric); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception when sending onDetected", e); + } } } diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java index 184ddae9699d..88f88a8439cc 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java +++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java @@ -19,6 +19,8 @@ package com.android.server.display; import android.annotation.NonNull; import android.content.Context; import android.content.res.Resources; +import android.hardware.display.DisplayManagerInternal; +import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation; import android.os.Environment; import android.os.PowerManager; import android.text.TextUtils; @@ -86,6 +88,9 @@ public class DisplayDeviceConfig { // The details of the proximity sensor associated with this display. private final SensorData mProximitySensor = new SensorData(); + private final List<RefreshRateLimitation> mRefreshRateLimitations = + new ArrayList<>(2 /*initialCapacity*/); + // Nits and backlight values that are loaded from either the display device config file, or // config.xml. These are the raw values and just used for the dumpsys private float[] mRawNits; @@ -306,6 +311,10 @@ public class DisplayDeviceConfig { return hbmData; } + public List<RefreshRateLimitation> getRefreshRateLimitations() { + return mRefreshRateLimitations; + } + @Override public String toString() { String str = "DisplayDeviceConfig{" @@ -329,6 +338,7 @@ public class DisplayDeviceConfig { + ", mBrightnessRampSlowIncrease=" + mBrightnessRampSlowIncrease + ", mAmbientLightSensor=" + mAmbientLightSensor + ", mProximitySensor=" + mProximitySensor + + ", mRefreshRateLimitations= " + Arrays.toString(mRefreshRateLimitations.toArray()) + "}"; return str; } @@ -647,6 +657,13 @@ public class DisplayDeviceConfig { mHbmData.timeWindowMillis = hbmTiming.getTimeWindowSecs_all().longValue() * 1000; mHbmData.timeMaxMillis = hbmTiming.getTimeMaxSecs_all().longValue() * 1000; mHbmData.timeMinMillis = hbmTiming.getTimeMinSecs_all().longValue() * 1000; + final RefreshRateRange rr = hbm.getRefreshRate_all(); + if (rr != null) { + final float min = rr.getMinimum().floatValue(); + final float max = rr.getMaximum().floatValue(); + mRefreshRateLimitations.add(new RefreshRateLimitation( + DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE, min, max)); + } } } diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index bff39a932105..182a038d10f7 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -63,6 +63,7 @@ import android.hardware.display.DisplayManagerGlobal; import android.hardware.display.DisplayManagerInternal; import android.hardware.display.DisplayManagerInternal.DisplayGroupListener; import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener; +import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation; import android.hardware.display.DisplayManagerInternal.RefreshRateRange; import android.hardware.display.DisplayViewport; import android.hardware.display.DisplayedContentSample; @@ -130,6 +131,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.Optional; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicLong; @@ -2111,6 +2113,11 @@ public final class DisplayManagerService extends SystemService { DisplayManagerGlobal.EVENT_DISPLAY_BRIGHTNESS_CHANGED); } + private DisplayDevice getDeviceForDisplayLocked(int displayId) { + final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId); + return display == null ? null : display.getPrimaryDisplayDeviceLocked(); + } + private final class DisplayManagerHandler extends Handler { public DisplayManagerHandler(Looper looper) { super(looper, null, true /*async*/); @@ -3295,6 +3302,19 @@ public final class DisplayManagerService extends SystemService { } return null; } + + @Override + public List<RefreshRateLimitation> getRefreshRateLimitations(int displayId) { + final DisplayDeviceConfig config; + synchronized (mSyncRoot) { + final DisplayDevice device = getDeviceForDisplayLocked(displayId); + if (device == null) { + return null; + } + config = device.getDisplayDeviceConfig(); + } + return config.getRefreshRateLimitations(); + } } class DesiredDisplayModeSpecsObserver diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java index 2364a3c7c2ed..83fc9665f192 100644 --- a/services/core/java/com/android/server/display/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/DisplayModeDirector.java @@ -16,6 +16,8 @@ package com.android.server.display; +import static android.hardware.display.DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE; + import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ContentResolver; @@ -26,8 +28,10 @@ import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; +import android.hardware.display.BrightnessInfo; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManagerInternal; +import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation; import android.hardware.display.DisplayManagerInternal.RefreshRateRange; import android.hardware.fingerprint.IUdfpsHbmListener; import android.net.Uri; @@ -102,6 +106,7 @@ public class DisplayModeDirector { private final DisplayObserver mDisplayObserver; private final UdfpsObserver mUdfpsObserver; private final SensorObserver mSensorObserver; + private final HbmObserver mHbmObserver; private final DeviceConfigInterface mDeviceConfig; private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings; @@ -127,7 +132,7 @@ public class DisplayModeDirector { private int mModeSwitchingType = DisplayManager.SWITCHING_TYPE_WITHIN_GROUPS; public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler) { - this(context, handler, new RealInjector()); + this(context, handler, new RealInjector(context)); } public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler, @@ -143,11 +148,13 @@ public class DisplayModeDirector { mDisplayObserver = new DisplayObserver(context, handler); mBrightnessObserver = new BrightnessObserver(context, handler); mUdfpsObserver = new UdfpsObserver(); - mSensorObserver = new SensorObserver(context, (displayId, priority, vote) -> { + final BallotBox ballotBox = (displayId, priority, vote) -> { synchronized (mLock) { updateVoteLocked(displayId, priority, vote); } - }); + }; + mSensorObserver = new SensorObserver(context, ballotBox); + mHbmObserver = new HbmObserver(injector, ballotBox, BackgroundThread.getHandler()); mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings(); mDeviceConfig = injector.getDeviceConfig(); mAlwaysRespectAppRequest = false; @@ -165,6 +172,7 @@ public class DisplayModeDirector { mDisplayObserver.observe(); mBrightnessObserver.observe(sensorManager); mSensorObserver.observe(); + mHbmObserver.observe(); synchronized (mLock) { // We may have a listener already registered before the call to start, so go ahead and // notify them to pick up our newly initialized state. @@ -596,6 +604,7 @@ public class DisplayModeDirector { mBrightnessObserver.dumpLocked(pw); mUdfpsObserver.dumpLocked(pw); mSensorObserver.dumpLocked(pw); + mHbmObserver.dumpLocked(pw); } } @@ -938,13 +947,16 @@ public class DisplayModeDirector { // user seeing the display flickering when the switches occur. public static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 8; + // High-brightness-mode may need a specific range of refresh-rates to function properly. + public static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 9; + // The proximity sensor needs the refresh rate to be locked in order to function, so this is // set to a high priority. - public static final int PRIORITY_PROXIMITY = 9; + public static final int PRIORITY_PROXIMITY = 10; // The Under-Display Fingerprint Sensor (UDFPS) needs the refresh rate to be locked in order // to function, so this needs to be the highest priority of all votes. - public static final int PRIORITY_UDFPS = 10; + public static final int PRIORITY_UDFPS = 11; // Whenever a new priority is added, remember to update MIN_PRIORITY, MAX_PRIORITY, and // APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, as well as priorityToString. @@ -1021,29 +1033,30 @@ public class DisplayModeDirector { public static String priorityToString(int priority) { switch (priority) { + case PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE: + return "PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE"; + case PRIORITY_APP_REQUEST_MAX_REFRESH_RATE: + return "PRIORITY_APP_REQUEST_MAX_REFRESH_RATE"; + case PRIORITY_APP_REQUEST_SIZE: + return "PRIORITY_APP_REQUEST_SIZE"; case PRIORITY_DEFAULT_REFRESH_RATE: return "PRIORITY_DEFAULT_REFRESH_RATE"; case PRIORITY_FLICKER_REFRESH_RATE: return "PRIORITY_FLICKER_REFRESH_RATE"; case PRIORITY_FLICKER_REFRESH_RATE_SWITCH: return "PRIORITY_FLICKER_REFRESH_RATE_SWITCH"; - case PRIORITY_USER_SETTING_MIN_REFRESH_RATE: - return "PRIORITY_USER_SETTING_MIN_REFRESH_RATE"; - case PRIORITY_APP_REQUEST_MAX_REFRESH_RATE: - return "PRIORITY_APP_REQUEST_MAX_REFRESH_RATE"; - case PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE: - return "PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE"; - case PRIORITY_APP_REQUEST_SIZE: - return "PRIORITY_APP_REQUEST_SIZE"; - case PRIORITY_USER_SETTING_PEAK_REFRESH_RATE: - return "PRIORITY_USER_SETTING_PEAK_REFRESH_RATE"; + case PRIORITY_HIGH_BRIGHTNESS_MODE: + return "PRIORITY_HIGH_BRIGHTNESS_MODE"; + case PRIORITY_PROXIMITY: + return "PRIORITY_PROXIMITY"; case PRIORITY_LOW_POWER_MODE: return "PRIORITY_LOW_POWER_MODE"; case PRIORITY_UDFPS: return "PRIORITY_UDFPS"; - case PRIORITY_PROXIMITY: - return "PRIORITY_PROXIMITY"; - + case PRIORITY_USER_SETTING_MIN_REFRESH_RATE: + return "PRIORITY_USER_SETTING_MIN_REFRESH_RATE"; + case PRIORITY_USER_SETTING_PEAK_REFRESH_RATE: + return "PRIORITY_USER_SETTING_PEAK_REFRESH_RATE"; default: return Integer.toString(priority); } @@ -2155,6 +2168,75 @@ public class DisplayModeDirector { } } + /** + * Listens to DisplayManager for HBM status and applies any refresh-rate restrictions for + * HBM that are associated with that display. Restrictions are retrieved from + * DisplayManagerInternal but originate in the display-device-config file. + */ + private static class HbmObserver implements DisplayManager.DisplayListener { + private final BallotBox mBallotBox; + private final Handler mHandler; + private final SparseBooleanArray mHbmEnabled = new SparseBooleanArray(); + private final Injector mInjector; + + private DisplayManagerInternal mDisplayManagerInternal; + + HbmObserver(Injector injector, BallotBox ballotBox, Handler handler) { + mInjector = injector; + mBallotBox = ballotBox; + mHandler = handler; + } + + public void observe() { + mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); + mInjector.registerDisplayListener(this, mHandler, + DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS + | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED); + } + + @Override + public void onDisplayAdded(int displayId) {} + + @Override + public void onDisplayRemoved(int displayId) { + mBallotBox.vote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, null); + } + + @Override + public void onDisplayChanged(int displayId) { + final BrightnessInfo info = mInjector.getBrightnessInfo(displayId); + if (info == null) { + // Display no longer there. Assume we'll get an onDisplayRemoved very soon. + return; + } + final boolean isHbmEnabled = + info.highBrightnessMode != BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF; + if (isHbmEnabled == mHbmEnabled.get(displayId)) { + // no change, ignore. + return; + } + Vote vote = null; + mHbmEnabled.put(displayId, isHbmEnabled); + if (isHbmEnabled) { + final List<RefreshRateLimitation> limits = + mDisplayManagerInternal.getRefreshRateLimitations(displayId); + for (int i = 0; limits != null && i < limits.size(); i++) { + final RefreshRateLimitation limitation = limits.get(i); + if (limitation.type == REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE) { + vote = Vote.forRefreshRates(limitation.range.min, limitation.range.max); + break; + } + } + } + mBallotBox.vote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, vote); + } + + void dumpLocked(PrintWriter pw) { + pw.println(" HbmObserver"); + pw.println(" mHbmEnabled: " + mHbmEnabled); + } + } + private class DeviceConfigDisplaySettings implements DeviceConfig.OnPropertiesChangedListener { public DeviceConfigDisplaySettings() { } @@ -2309,10 +2391,21 @@ public class DisplayModeDirector { void registerPeakRefreshRateObserver(@NonNull ContentResolver cr, @NonNull ContentObserver observer); + + void registerDisplayListener(@NonNull DisplayManager.DisplayListener listener, + Handler handler, long flags); + + BrightnessInfo getBrightnessInfo(int displayId); } @VisibleForTesting static class RealInjector implements Injector { + private final Context mContext; + private DisplayManager mDisplayManager; + + RealInjector(Context context) { + mContext = context; + } @Override @NonNull @@ -2339,6 +2432,28 @@ public class DisplayModeDirector { cr.registerContentObserver(PEAK_REFRESH_RATE_URI, false /*notifyDescendants*/, observer, UserHandle.USER_SYSTEM); } + + @Override + public void registerDisplayListener(DisplayManager.DisplayListener listener, + Handler handler, long flags) { + getDisplayManager().registerDisplayListener(listener, handler, flags); + } + + @Override + public BrightnessInfo getBrightnessInfo(int displayId) { + final Display display = getDisplayManager().getDisplay(displayId); + if (display != null) { + return display.getBrightnessInfo(); + } + return null; + } + + private DisplayManager getDisplayManager() { + if (mDisplayManager == null) { + mDisplayManager = mContext.getSystemService(DisplayManager.class); + } + return mDisplayManager; + } } interface BallotBox { diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index 5fd8e3c6e302..44f7d8869322 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -177,8 +177,10 @@ public class PackageDexOptimizer { private int performDexOptLI(AndroidPackage pkg, @NonNull PackageSetting pkgSetting, String[] targetInstructionSets, CompilerStats.PackageStats packageStats, PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) { + // ClassLoader only refers non-native (jar) shared libraries and must ignore + // native (so) shared libraries. See also LoadedApk#createSharedLibraryLoader(). final List<SharedLibraryInfo> sharedLibraries = pkgSetting.getPkgState() - .getUsesLibraryInfos(); + .getNonNativeUsesLibraryInfos(); final String[] instructionSets = targetInstructionSets != null ? targetInstructionSets : getAppDexInstructionSets( AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting), diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 60a757118222..d2ed08f66944 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -157,6 +157,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements private volatile boolean mOkToSendBroadcasts = false; private volatile boolean mBypassNextStagedInstallerCheck = false; + private volatile boolean mBypassNextAllowedApexUpdateCheck = false; /** * File storing persisted {@link #mSessions} metadata. @@ -650,6 +651,13 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements throw new IllegalArgumentException( "Non-staged APEX session doesn't support INSTALL_ENABLE_ROLLBACK"); } + if (isCalledBySystemOrShell(callingUid) || mBypassNextAllowedApexUpdateCheck) { + params.installFlags |= PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK; + } else { + // Only specific APEX updates (installed through ADB, or for CTS tests) can disable + // allowed APEX update check. + params.installFlags &= ~PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK; + } } if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0 @@ -674,6 +682,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } mBypassNextStagedInstallerCheck = false; + mBypassNextAllowedApexUpdateCheck = false; + if (!params.isMultiPackage) { // Only system components can circumvent runtime permissions when installing. if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0 @@ -1106,6 +1116,14 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements mBypassNextStagedInstallerCheck = value; } + @Override + public void bypassNextAllowedApexUpdateCheck(boolean value) { + if (!isCalledBySystemOrShell(Binder.getCallingUid())) { + throw new SecurityException("Caller not allowed to bypass allowed apex update check"); + } + mBypassNextAllowedApexUpdateCheck = value; + } + /** * Set an installer to allow for the unlimited silent updates. */ diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 4b0eb6546888..c33130037027 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -147,6 +147,7 @@ import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.server.LocalServices; +import com.android.server.SystemConfig; import com.android.server.pm.Installer.InstallerException; import com.android.server.pm.dex.DexManager; import com.android.server.pm.parsing.pkg.AndroidPackage; @@ -2238,6 +2239,26 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { .setAdmin(mInstallSource.installerPackageName) .write(); } + + // Check if APEX update is allowed. We do this check in handleInstall, since this is one of + // the places that: + // * Shared between staged and non-staged APEX update flows. + // * Only is called after boot completes. + // The later is important, since isApexUpdateAllowed check depends on the + // ModuleInfoProvider, which is only populated after device has booted. + if (isApexSession()) { + boolean checkApexUpdateAllowed = + (params.installFlags & PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK) + == 0; + synchronized (mLock) { + if (checkApexUpdateAllowed && !isApexUpdateAllowed(mPackageName)) { + onSessionValidationFailure(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE, + "Update of APEX package " + mPackageName + " is not allowed"); + return; + } + } + } + if (params.isStaged) { mStagingManager.commitSession(mStagedSession); // TODO(b/136257624): CTS test fails if we don't send session finished broadcast, even @@ -2776,6 +2797,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return sessionContains((s) -> !s.isApexSession()); } + private boolean isApexUpdateAllowed(String apexPackageName) { + return mPm.getModuleInfo(apexPackageName, 0) != null + || SystemConfig.getInstance().getAllowedPartnerApexes().contains(apexPackageName); + } + /** * Validate apex install. * <p> diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 364ac42985f1..b0a662b3514d 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -436,8 +436,10 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; +import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.nio.charset.StandardCharsets; import java.security.DigestException; import java.security.DigestInputStream; @@ -1918,14 +1920,65 @@ public class PackageManagerService extends IPackageManager.Stub } /** - * A computer provides the functional interface to the snapshot. + * A {@link Computer} provides a set of functions that can operate on live data or snapshot + * data. At this time, the {@link Computer} is implemented by the + * {@link ComputerEngine}, which is in turn extended by {@link ComputerLocked}. + * + * New functions must be added carefully. + * <ol> + * <li> New functions must be true functions with respect to data collected in a + * {@link Snapshot}. Such data may never be modified from inside a {@link Computer} + * function. + * </li> + * + * <li> A new function must be implemented in {@link ComputerEngine}. + * </li> + * + * <li> A new function must be overridden in {@link ComputerLocked} if the function + * cannot safely access live data without holding the PackageManagerService lock. The + * form of the {@link ComputerLocked} function must be a single call to the + * {@link ComputerEngine} implementation, wrapped in a <code>synchronized</code> + * block. Functions in {@link ComputerLocked} should never include any other code. + * </li> + * + * Care must be taken when deciding if a function should be overridden in + * {@link ComputerLocked}. The complex lock relationships of PackageManagerService + * and other managers (like PermissionManager) mean deadlock is possible. On the + * other hand, not overriding in {@link ComputerLocked} may leave a function walking + * unstable data. + * + * To coax developers to consider such issues carefully, all methods in + * {@link Computer} must be annotated with <code>@LiveImplementation(override = + * MANDATORY)</code> or <code>LiveImplementation(locked = NOT_ALLOWED)</code>. A unit + * test verifies the annotation and that the annotation corresponds to the code in + * {@link ComputerEngine} and {@link ComputerLocked}. */ - private interface Computer { + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + protected interface Computer { + + /** + * Every method must be annotated. + */ + @Target({ ElementType.METHOD }) + @Retention(RetentionPolicy.RUNTIME) + public @interface LiveImplementation { + // A Computer method must be annotated with one of the following values: + // MANDATORY - the method must be overridden in ComputerEngineLive. The + // format of the override is a call to the super method, wrapped in a + // synchronization block. + // NOT_ALLOWED - the method may not appear in the live computer. It must + // be final in the ComputerEngine. + int MANDATORY = 1; + int NOT_ALLOWED = 2; + int override() default MANDATORY; + String rationale() default ""; + } /** * Administrative statistics: record that the snapshot has been used. Every call * to use() increments the usage counter. */ + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) default void use() { } @@ -1933,95 +1986,154 @@ public class PackageManagerService extends IPackageManager.Stub * Fetch the snapshot usage counter. * @return The number of times this snapshot was used. */ + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) default int getUsed() { return 0; } + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType, int flags, @PrivateResolveFlags int privateResolveFlags, int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType, int flags, int userId); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent, String resolvedType, int flags, int userId, int callingUid, boolean includeInstantApps); + @LiveImplementation(override = LiveImplementation.MANDATORY) @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(Intent intent, String resolvedType, int flags, int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits, String pkgName, String instantAppPkgName); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) ActivityInfo getActivityInfo(ComponentName component, int flags, int userId); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) ActivityInfo getActivityInfoInternal(ComponentName component, int flags, int filterCallingUid, int userId); + @LiveImplementation(override = LiveImplementation.MANDATORY) AndroidPackage getPackage(String packageName); + @LiveImplementation(override = LiveImplementation.MANDATORY) AndroidPackage getPackage(int uid); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags, int filterCallingUid, int userId); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) ApplicationInfo getApplicationInfo(String packageName, int flags, int userId); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) ApplicationInfo getApplicationInfoInternal(String packageName, int flags, int filterCallingUid, int userId); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) ComponentName getDefaultHomeActivity(int userId); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates, int userId); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent, String resolvedType, int flags, int sourceUserId, int parentUserId); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) Intent getHomeIntent(); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) List<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters(Intent intent, String resolvedType, int userId); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) List<ResolveInfo> applyPostResolutionFilter(@NonNull List<ResolveInfo> resolveInfos, String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid, boolean resolveForStart, int userId, Intent intent); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) PackageInfo getPackageInfo(String packageName, int flags, int userId); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) PackageInfo getPackageInfoInternal(String packageName, long versionCode, int flags, int filterCallingUid, int userId); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) PackageSetting getPackageSetting(String packageName); + @LiveImplementation(override = LiveImplementation.MANDATORY) PackageSetting getPackageSettingInternal(String packageName, int callingUid); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter, int sourceUserId, int targetUserId); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) ServiceInfo getServiceInfo(ComponentName component, int flags, int userId); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) SharedLibraryInfo getSharedLibraryInfoLPr(String name, long version); + @LiveImplementation(override = LiveImplementation.MANDATORY) String getInstantAppPackageName(int callingUid); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) String resolveExternalPackageNameLPr(AndroidPackage pkg); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) String resolveInternalPackageNameLPr(String packageName, long versionCode); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) String[] getPackagesForUid(int uid); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) UserInfo getProfileParent(int userId); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) boolean canViewInstantApps(int callingUid, int userId); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid, int userId, int flags); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) boolean isCallerSameApp(String packageName, int uid); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) boolean isComponentVisibleToInstantApp(@Nullable ComponentName component); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) boolean isComponentVisibleToInstantApp(@Nullable ComponentName component, @ComponentType int type); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent, int userId, String resolvedType, int flags); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) boolean isInstantApp(String packageName, int userId); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) boolean isInstantAppInternal(String packageName, @UserIdInt int userId, int callingUid); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps, int callingUid, @Nullable ComponentName component, @ComponentType int componentType, int userId); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps, int callingUid, int userId); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) boolean shouldFilterApplicationLocked(@NonNull SharedUserSetting sus, int callingUid, int userId); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) int checkUidPermission(String permName, int uid); + @LiveImplementation(override = LiveImplementation.MANDATORY) int getPackageUidInternal(String packageName, int flags, int userId, int callingUid); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) int updateFlagsForApplication(int flags, int userId); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) int updateFlagsForComponent(int flags, int userId); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) int updateFlagsForPackage(int flags, int userId); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) int updateFlagsForResolve(int flags, int userId, int callingUid, boolean wantInstantApps, boolean isImplicitImageCaptureIntentAndNotSetByDpc); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) int updateFlagsForResolve(int flags, int userId, int callingUid, boolean wantInstantApps, boolean onlyExposedExplicitly, boolean isImplicitImageCaptureIntentAndNotSetByDpc); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId, boolean requireFullPermission, boolean checkShell, String message); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) void enforceCrossUserPermission(int callingUid, @UserIdInt int userId, boolean requireFullPermission, boolean checkShell, String message); + @LiveImplementation(override = LiveImplementation.NOT_ALLOWED) void enforceCrossUserPermission(int callingUid, @UserIdInt int userId, boolean requireFullPermission, boolean checkShell, boolean requirePermissionWhenSameUser, String message); + @LiveImplementation(override = LiveImplementation.MANDATORY) SigningDetails getSigningDetails(@NonNull String packageName); + @LiveImplementation(override = LiveImplementation.MANDATORY) SigningDetails getSigningDetails(int uid); + @LiveImplementation(override = LiveImplementation.MANDATORY) boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId); + @LiveImplementation(override = LiveImplementation.MANDATORY) boolean filterAppAccess(String packageName, int callingUid, int userId); + @LiveImplementation(override = LiveImplementation.MANDATORY) void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState); } @@ -2030,7 +2142,8 @@ public class PackageManagerService extends IPackageManager.Stub * is entirely self-contained - it has no implicit access to * PackageManagerService. */ - private static class ComputerEngine implements Computer { + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + protected static class ComputerEngine implements Computer { // The administrative use counter. private int mUsed = 0; @@ -2076,7 +2189,7 @@ public class PackageManagerService extends IPackageManager.Stub // PackageManagerService attributes that are primitives are referenced through the // pms object directly. Primitives are the only attributes so referenced. protected final PackageManagerService mService; - protected boolean safeMode() { + private boolean safeMode() { return mService.mSafeMode; } protected ComponentName resolveComponentName() { @@ -2130,18 +2243,18 @@ public class PackageManagerService extends IPackageManager.Stub /** * Record that the snapshot was used. */ - public void use() { + public final void use() { mUsed++; } /** * Return the usage counter. */ - public int getUsed() { + public final int getUsed() { return mUsed; } - public @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, + public final @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType, int flags, @PrivateResolveFlags int privateResolveFlags, int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits) { @@ -2240,14 +2353,14 @@ public class PackageManagerService extends IPackageManager.Stub resolveForStart, userId, intent); } - public @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, + public final @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType, int flags, int userId) { return queryIntentActivitiesInternal( intent, resolvedType, flags, 0 /*privateResolveFlags*/, Binder.getCallingUid(), userId, false /*resolveForStart*/, true /*allowDynamicSplits*/); } - public @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent, + public final @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent, String resolvedType, int flags, int userId, int callingUid, boolean includeInstantApps) { if (!mUserManager.exists(userId)) return Collections.emptyList(); @@ -2471,7 +2584,7 @@ public class PackageManagerService extends IPackageManager.Stub return null; } - public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) { + public final ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) { return getActivityInfoInternal(component, flags, Binder.getCallingUid(), userId); } @@ -2481,7 +2594,7 @@ public class PackageManagerService extends IPackageManager.Stub * to clearing. Because it can only be provided by trusted code, its value can be * trusted and will be used as-is; unlike userId which will be validated by this method. */ - public ActivityInfo getActivityInfoInternal(ComponentName component, int flags, + public final ActivityInfo getActivityInfoInternal(ComponentName component, int flags, int filterCallingUid, int userId) { if (!mUserManager.exists(userId)) return null; flags = updateFlagsForComponent(flags, userId); @@ -2535,8 +2648,8 @@ public class PackageManagerService extends IPackageManager.Stub return pkg; } - public ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags, - int filterCallingUid, int userId) { + public final ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, + int flags, int filterCallingUid, int userId) { if (!mUserManager.exists(userId)) return null; PackageSetting ps = mSettings.getPackageLPr(packageName); if (ps != null) { @@ -2563,7 +2676,7 @@ public class PackageManagerService extends IPackageManager.Stub return null; } - public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) { + public final ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) { return getApplicationInfoInternal(packageName, flags, Binder.getCallingUid(), userId); } @@ -2573,7 +2686,7 @@ public class PackageManagerService extends IPackageManager.Stub * to clearing. Because it can only be provided by trusted code, its value can be * trusted and will be used as-is; unlike userId which will be validated by this method. */ - public ApplicationInfo getApplicationInfoInternal(String packageName, int flags, + public final ApplicationInfo getApplicationInfoInternal(String packageName, int flags, int filterCallingUid, int userId) { if (!mUserManager.exists(userId)) return null; flags = updateFlagsForApplication(flags, userId); @@ -2765,7 +2878,7 @@ public class PackageManagerService extends IPackageManager.Stub * Report the 'Home' activity which is currently set as "always use this one". If non is set * then reports the most likely home activity or null if there are more than one. */ - public ComponentName getDefaultHomeActivity(int userId) { + public final ComponentName getDefaultHomeActivity(int userId) { List<ResolveInfo> allHomeCandidates = new ArrayList<>(); ComponentName cn = getHomeActivitiesAsUser(allHomeCandidates, userId); if (cn != null) { @@ -2793,7 +2906,7 @@ public class PackageManagerService extends IPackageManager.Stub return lastComponent; } - public ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates, + public final ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates, int userId) { Intent intent = getHomeIntent(); List<ResolveInfo> resolveInfos = queryIntentActivitiesInternal(intent, null, @@ -2822,7 +2935,7 @@ public class PackageManagerService extends IPackageManager.Stub return null; } - public CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent, + public final CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent, String resolvedType, int flags, int sourceUserId, int parentUserId) { if (!mUserManager.hasUserRestriction(UserManager.ALLOW_PARENT_PROFILE_APP_LINKING, sourceUserId)) { @@ -2868,15 +2981,15 @@ public class PackageManagerService extends IPackageManager.Stub return result; } - public Intent getHomeIntent() { + public final Intent getHomeIntent() { Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_HOME); intent.addCategory(Intent.CATEGORY_DEFAULT); return intent; } - public List<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters(Intent intent, - String resolvedType, int userId) { + public final List<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters( + Intent intent, String resolvedType, int userId) { CrossProfileIntentResolver resolver = mSettings.getCrossProfileIntentResolver(userId); if (resolver != null) { return resolver.queryIntent(intent, resolvedType, false /*defaultOnly*/, userId); @@ -2895,7 +3008,8 @@ public class PackageManagerService extends IPackageManager.Stub * @param intent * @return A filtered list of resolved activities. */ - public List<ResolveInfo> applyPostResolutionFilter(@NonNull List<ResolveInfo> resolveInfos, + public final List<ResolveInfo> applyPostResolutionFilter( + @NonNull List<ResolveInfo> resolveInfos, String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid, boolean resolveForStart, int userId, Intent intent) { final boolean blockInstant = intent.isWebIntent() && areWebInstantAppsDisabled(userId); @@ -3041,7 +3155,7 @@ public class PackageManagerService extends IPackageManager.Stub return resolveInfos; } - public List<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPr(Intent intent, + private List<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPr(Intent intent, int matchFlags, List<ResolveInfo> candidates, CrossProfileDomainInfo xpDomainInfo, int userId) { final boolean debug = (intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0; @@ -3188,7 +3302,7 @@ public class PackageManagerService extends IPackageManager.Stub return result; } - public PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId) { + public final PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId) { if (!mUserManager.exists(userId)) return null; if (ps == null) { return null; @@ -3258,7 +3372,7 @@ public class PackageManagerService extends IPackageManager.Stub } } - public PackageInfo getPackageInfo(String packageName, int flags, int userId) { + public final PackageInfo getPackageInfo(String packageName, int flags, int userId) { return getPackageInfoInternal(packageName, PackageManager.VERSION_CODE_HIGHEST, flags, Binder.getCallingUid(), userId); } @@ -3269,7 +3383,7 @@ public class PackageManagerService extends IPackageManager.Stub * to clearing. Because it can only be provided by trusted code, its value can be * trusted and will be used as-is; unlike userId which will be validated by this method. */ - public PackageInfo getPackageInfoInternal(String packageName, long versionCode, + public final PackageInfo getPackageInfoInternal(String packageName, long versionCode, int flags, int filterCallingUid, int userId) { if (!mUserManager.exists(userId)) return null; flags = updateFlagsForPackage(flags, userId); @@ -3340,7 +3454,7 @@ public class PackageManagerService extends IPackageManager.Stub } @Nullable - public PackageSetting getPackageSetting(String packageName) { + public final PackageSetting getPackageSetting(String packageName) { return getPackageSettingInternal(packageName, Binder.getCallingUid()); } @@ -3350,7 +3464,7 @@ public class PackageManagerService extends IPackageManager.Stub return mSettings.getPackageLPr(packageName); } - public ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId) { + public final ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId) { final int callingUid = Binder.getCallingUid(); if (getInstantAppPackageName(callingUid) != null) { return ParceledListSlice.emptyList(); @@ -3489,7 +3603,7 @@ public class PackageManagerService extends IPackageManager.Stub return new CrossProfileDomainInfo(forwardingInfo, highestApprovalLevel); } - public ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter, + public final ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter, int sourceUserId, int targetUserId) { ResolveInfo forwardingResolveInfo = new ResolveInfo(); final long ident = Binder.clearCallingIdentity(); @@ -3601,7 +3715,7 @@ public class PackageManagerService extends IPackageManager.Stub return null; } - public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) { + public final ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) { if (!mUserManager.exists(userId)) return null; final int callingUid = Binder.getCallingUid(); flags = updateFlagsForComponent(flags, userId); @@ -3635,7 +3749,7 @@ public class PackageManagerService extends IPackageManager.Stub } @Nullable - public SharedLibraryInfo getSharedLibraryInfoLPr(String name, long version) { + public final SharedLibraryInfo getSharedLibraryInfoLPr(String name, long version) { return getSharedLibraryInfo(name, version, mSharedLibraries, null); } @@ -3671,7 +3785,7 @@ public class PackageManagerService extends IPackageManager.Stub return ownerUid; } - public String resolveExternalPackageNameLPr(AndroidPackage pkg) { + public final String resolveExternalPackageNameLPr(AndroidPackage pkg) { if (pkg.getStaticSharedLibName() != null) { return pkg.getManifestPackageName(); } @@ -3745,7 +3859,7 @@ public class PackageManagerService extends IPackageManager.Stub return packageName; } - public String resolveInternalPackageNameLPr(String packageName, long versionCode) { + public final String resolveInternalPackageNameLPr(String packageName, long versionCode) { final int callingUid = Binder.getCallingUid(); return resolveInternalPackageNameInternalLocked(packageName, versionCode, callingUid); @@ -3766,7 +3880,7 @@ public class PackageManagerService extends IPackageManager.Stub * calls to invalidateGetPackagesForUidCache() to locate the points at * which the cache is invalidated. */ - public String[] getPackagesForUid(int uid) { + public final String[] getPackagesForUid(int uid) { return getPackagesForUidInternal(uid, Binder.getCallingUid()); } @@ -3807,7 +3921,7 @@ public class PackageManagerService extends IPackageManager.Stub return null; } - public UserInfo getProfileParent(int userId) { + public final UserInfo getProfileParent(int userId) { final long identity = Binder.clearCallingIdentity(); try { return mUserManager.getProfileParent(userId); @@ -3837,7 +3951,7 @@ public class PackageManagerService extends IPackageManager.Stub * <li>The calling application is the default app prediction service.</li> * </ol> */ - public boolean canViewInstantApps(int callingUid, int userId) { + public final boolean canViewInstantApps(int callingUid, int userId) { if (callingUid < Process.FIRST_APPLICATION_UID) { return true; } @@ -3861,8 +3975,8 @@ public class PackageManagerService extends IPackageManager.Stub return false; } - public boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid, int userId, - int flags) { + public final boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid, + int userId, int flags) { // Callers can access only the libs they depend on, otherwise they need to explicitly // ask for the shared libraries given the caller is allowed to access all static libs. if ((flags & PackageManager.MATCH_STATIC_SHARED_LIBRARIES) != 0) { @@ -3945,13 +4059,13 @@ public class PackageManagerService extends IPackageManager.Stub == PackageManager.PERMISSION_GRANTED; } - public boolean isCallerSameApp(String packageName, int uid) { + public final boolean isCallerSameApp(String packageName, int uid) { AndroidPackage pkg = mPackages.get(packageName); return pkg != null && UserHandle.getAppId(uid) == pkg.getUid(); } - public boolean isComponentVisibleToInstantApp(@Nullable ComponentName component) { + public final boolean isComponentVisibleToInstantApp(@Nullable ComponentName component) { if (isComponentVisibleToInstantApp(component, TYPE_ACTIVITY)) { return true; } @@ -3964,7 +4078,7 @@ public class PackageManagerService extends IPackageManager.Stub return false; } - public boolean isComponentVisibleToInstantApp( + public final boolean isComponentVisibleToInstantApp( @Nullable ComponentName component, @ComponentType int type) { if (type == TYPE_ACTIVITY) { final ParsedActivity activity = mComponentResolver.getActivity(component); @@ -4012,13 +4126,13 @@ public class PackageManagerService extends IPackageManager.Stub * @return {@code true} if the intent is a camera intent and the persistent preferred * activity was not set by the DPC. */ - public boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent, int userId, - String resolvedType, int flags) { + public final boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent, + int userId, String resolvedType, int flags) { return intent.isImplicitImageCaptureIntent() && !isPersistentPreferredActivitySetByDpm( intent, userId, resolvedType, flags); } - public boolean isInstantApp(String packageName, int userId) { + public final boolean isInstantApp(String packageName, int userId) { final int callingUid = Binder.getCallingUid(); enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */, false /* checkShell */, "isInstantApp"); @@ -4026,7 +4140,7 @@ public class PackageManagerService extends IPackageManager.Stub return isInstantAppInternal(packageName, userId, callingUid); } - public boolean isInstantAppInternal(String packageName, @UserIdInt int userId, + public final boolean isInstantAppInternal(String packageName, @UserIdInt int userId, int callingUid) { if (HIDE_EPHEMERAL_APIS) { return false; @@ -4160,7 +4274,8 @@ public class PackageManagerService extends IPackageManager.Stub } } - public boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId) { + public final boolean isSameProfileGroup(@UserIdInt int callerUserId, + @UserIdInt int userId) { final long identity = Binder.clearCallingIdentity(); try { return UserManagerService.getInstance().isSameProfileGroup(callerUserId, userId); @@ -4187,7 +4302,8 @@ public class PackageManagerService extends IPackageManager.Stub * * @see #canViewInstantApps(int, int) */ - public boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps, int callingUid, + public final boolean shouldFilterApplicationLocked(@Nullable PackageSetting ps, + int callingUid, @Nullable ComponentName component, @ComponentType int componentType, int userId) { // if we're in an isolated process, get the real calling UID if (Process.isIsolated(callingUid)) { @@ -4247,7 +4363,7 @@ public class PackageManagerService extends IPackageManager.Stub /** * @see #shouldFilterApplicationLocked(PackageSetting, int, ComponentName, int, int) */ - public boolean shouldFilterApplicationLocked( + public final boolean shouldFilterApplicationLocked( @Nullable PackageSetting ps, int callingUid, int userId) { return shouldFilterApplicationLocked(ps, callingUid, null, TYPE_UNKNOWN, userId); } @@ -4255,8 +4371,8 @@ public class PackageManagerService extends IPackageManager.Stub /** * @see #shouldFilterApplicationLocked(PackageSetting, int, ComponentName, int, int) */ - public boolean shouldFilterApplicationLocked(@NonNull SharedUserSetting sus, int callingUid, - int userId) { + public final boolean shouldFilterApplicationLocked(@NonNull SharedUserSetting sus, + int callingUid, int userId) { boolean filterApp = true; for (int index = sus.packages.size() - 1; index >= 0 && filterApp; index--) { filterApp &= shouldFilterApplicationLocked(sus.packages.valueAt(index), @@ -4280,7 +4396,7 @@ public class PackageManagerService extends IPackageManager.Stub } // NOTE: Can't remove without a major refactor. Keep around for now. - public int checkUidPermission(String permName, int uid) { + public final int checkUidPermission(String permName, int uid) { return mPermissionManager.checkUidPermission(uid, permName); } @@ -4330,21 +4446,21 @@ public class PackageManagerService extends IPackageManager.Stub /** * Update given flags when being used to request {@link ApplicationInfo}. */ - public int updateFlagsForApplication(int flags, int userId) { + public final int updateFlagsForApplication(int flags, int userId) { return updateFlagsForPackage(flags, userId); } /** * Update given flags when being used to request {@link ComponentInfo}. */ - public int updateFlagsForComponent(int flags, int userId) { + public final int updateFlagsForComponent(int flags, int userId) { return updateFlags(flags, userId); } /** * Update given flags when being used to request {@link PackageInfo}. */ - public int updateFlagsForPackage(int flags, int userId) { + public final int updateFlagsForPackage(int flags, int userId) { final boolean isCallerSystemUser = UserHandle.getCallingUserId() == UserHandle.USER_SYSTEM; if ((flags & PackageManager.MATCH_ANY_USER) != 0) { @@ -4380,14 +4496,14 @@ public class PackageManagerService extends IPackageManager.Stub * action and a {@code android.intent.category.BROWSABLE} category</li> * </ul> */ - public int updateFlagsForResolve(int flags, int userId, int callingUid, + public final int updateFlagsForResolve(int flags, int userId, int callingUid, boolean wantInstantApps, boolean isImplicitImageCaptureIntentAndNotSetByDpc) { return updateFlagsForResolve(flags, userId, callingUid, wantInstantApps, false /*onlyExposedExplicitly*/, isImplicitImageCaptureIntentAndNotSetByDpc); } - public int updateFlagsForResolve(int flags, int userId, int callingUid, + public final int updateFlagsForResolve(int flags, int userId, int callingUid, boolean wantInstantApps, boolean onlyExposedExplicitly, boolean isImplicitImageCaptureIntentAndNotSetByDpc) { // Safe mode means we shouldn't match any third-party components @@ -4429,7 +4545,7 @@ public class PackageManagerService extends IPackageManager.Stub * @param checkShell whether to prevent shell from access if there's a debugging restriction * @param message the message to log on security exception */ - public void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId, + public final void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId, boolean requireFullPermission, boolean checkShell, String message) { if (userId < 0) { throw new IllegalArgumentException("Invalid userId " + userId); @@ -4467,7 +4583,7 @@ public class PackageManagerService extends IPackageManager.Stub * @param checkShell whether to prevent shell from access if there's a debugging restriction * @param message the message to log on security exception */ - public void enforceCrossUserPermission(int callingUid, @UserIdInt int userId, + public final void enforceCrossUserPermission(int callingUid, @UserIdInt int userId, boolean requireFullPermission, boolean checkShell, String message) { enforceCrossUserPermission(callingUid, userId, requireFullPermission, checkShell, false, message); @@ -4484,7 +4600,7 @@ public class PackageManagerService extends IPackageManager.Stub * reference the same user. * @param message the message to log on security exception */ - public void enforceCrossUserPermission(int callingUid, @UserIdInt int userId, + public final void enforceCrossUserPermission(int callingUid, @UserIdInt int userId, boolean requireFullPermission, boolean checkShell, boolean requirePermissionWhenSameUser, String message) { if (userId < 0) { @@ -4736,31 +4852,14 @@ public class PackageManagerService extends IPackageManager.Stub } /** - * The live computer differs from the ComputerEngine in the methods that fetch data - * from PackageManagerService. - **/ - private static class ComputerEngineLive extends ComputerEngine { - ComputerEngineLive(Snapshot args) { - super(args); - } - protected ComponentName resolveComponentName() { - return mService.mResolveComponentName; - } - protected ActivityInfo instantAppInstallerActivity() { - return mService.mInstantAppInstallerActivity; - } - protected ApplicationInfo androidApplication() { - return mService.mAndroidApplication; - } - } - - /** - * This subclass is the external interface to the live computer. For each - * interface, it takes the PM lock and then delegates to the live - * computer engine. This is required because there are no locks taken in - * the engine itself. + * This subclass is the external interface to the live computer. Some internal helper + * methods are overridden to fetch live data instead of snapshot data. For each + * Computer interface that is overridden in this class, the override takes the PM lock + * and then delegates to the live computer engine. This is required because there are + * no locks taken in the engine itself. */ - private static class ComputerLocked extends ComputerEngineLive { + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + protected static class ComputerLocked extends ComputerEngine { private final Object mLock; ComputerLocked(Snapshot args) { @@ -4768,18 +4867,17 @@ public class PackageManagerService extends IPackageManager.Stub mLock = mService.mLock; } - /** - * Explicilty snapshot {@link Settings#mPackages} for cases where the caller must not lock - * in order to get package data. It is expected that the caller locks itself to be able - * to block on changes to the package data and bring itself up to date once the change - * propagates to it. Use with heavy caution. - * @return - */ - private Map<String, PackageSetting> snapshotPackageSettings() { - return mSettings.snapshot().mPackages; + protected final ComponentName resolveComponentName() { + return mService.mResolveComponentName; + } + protected final ActivityInfo instantAppInstallerActivity() { + return mService.mInstantAppInstallerActivity; + } + protected final ApplicationInfo androidApplication() { + return mService.mAndroidApplication; } - public @NonNull List<ResolveInfo> queryIntentServicesInternalBody(Intent intent, + public final @NonNull List<ResolveInfo> queryIntentServicesInternalBody(Intent intent, String resolvedType, int flags, int userId, int callingUid, String instantAppPkgName) { synchronized (mLock) { @@ -4787,8 +4885,8 @@ public class PackageManagerService extends IPackageManager.Stub callingUid, instantAppPkgName); } } - public @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(Intent intent, - String resolvedType, int flags, int filterCallingUid, int userId, + public final @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody( + Intent intent, String resolvedType, int flags, int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits, String pkgName, String instantAppPkgName) { synchronized (mLock) { @@ -4797,31 +4895,31 @@ public class PackageManagerService extends IPackageManager.Stub instantAppPkgName); } } - public ActivityInfo getActivityInfoInternalBody(ComponentName component, int flags, + public final ActivityInfo getActivityInfoInternalBody(ComponentName component, int flags, int filterCallingUid, int userId) { synchronized (mLock) { return super.getActivityInfoInternalBody(component, flags, filterCallingUid, userId); } } - public AndroidPackage getPackage(String packageName) { + public final AndroidPackage getPackage(String packageName) { synchronized (mLock) { return super.getPackage(packageName); } } - public AndroidPackage getPackage(int uid) { + public final AndroidPackage getPackage(int uid) { synchronized (mLock) { return super.getPackage(uid); } } - public ApplicationInfo getApplicationInfoInternalBody(String packageName, int flags, + public final ApplicationInfo getApplicationInfoInternalBody(String packageName, int flags, int filterCallingUid, int userId) { synchronized (mLock) { return super.getApplicationInfoInternalBody(packageName, flags, filterCallingUid, userId); } } - public ArrayList<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPrBody( + public final ArrayList<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPrBody( Intent intent, int matchFlags, List<ResolveInfo> candidates, CrossProfileDomainInfo xpDomainInfo, int userId, boolean debug) { synchronized (mLock) { @@ -4829,49 +4927,49 @@ public class PackageManagerService extends IPackageManager.Stub matchFlags, candidates, xpDomainInfo, userId, debug); } } - public PackageInfo getPackageInfoInternalBody(String packageName, long versionCode, + public final PackageInfo getPackageInfoInternalBody(String packageName, long versionCode, int flags, int filterCallingUid, int userId) { synchronized (mLock) { return super.getPackageInfoInternalBody(packageName, versionCode, flags, filterCallingUid, userId); } } - public PackageSetting getPackageSettingInternal(String packageName, int callingUid) { + public final PackageSetting getPackageSettingInternal(String packageName, int callingUid) { synchronized (mLock) { return super.getPackageSettingInternal(packageName, callingUid); } } - public ParceledListSlice<PackageInfo> getInstalledPackagesBody(int flags, int userId, + public final ParceledListSlice<PackageInfo> getInstalledPackagesBody(int flags, int userId, int callingUid) { synchronized (mLock) { return super.getInstalledPackagesBody(flags, userId, callingUid); } } - public ServiceInfo getServiceInfoBody(ComponentName component, int flags, int userId, + public final ServiceInfo getServiceInfoBody(ComponentName component, int flags, int userId, int callingUid) { synchronized (mLock) { return super.getServiceInfoBody(component, flags, userId, callingUid); } } - public String getInstantAppPackageName(int callingUid) { + public final String getInstantAppPackageName(int callingUid) { synchronized (mLock) { return super.getInstantAppPackageName(callingUid); } } - public String[] getPackagesForUidInternalBody(int callingUid, int userId, int appId, + public final String[] getPackagesForUidInternalBody(int callingUid, int userId, int appId, boolean isCallerInstantApp) { synchronized (mLock) { return super.getPackagesForUidInternalBody(callingUid, userId, appId, isCallerInstantApp); } } - public boolean isInstantAppInternalBody(String packageName, @UserIdInt int userId, + public final boolean isInstantAppInternalBody(String packageName, @UserIdInt int userId, int callingUid) { synchronized (mLock) { return super.isInstantAppInternalBody(packageName, userId, callingUid); } } - public boolean isInstantAppResolutionAllowedBody(Intent intent, + public final boolean isInstantAppResolutionAllowedBody(Intent intent, List<ResolveInfo> resolvedActivities, int userId, boolean skipPackageCheck, int flags) { synchronized (mLock) { @@ -4879,33 +4977,33 @@ public class PackageManagerService extends IPackageManager.Stub skipPackageCheck, flags); } } - public int getPackageUidInternal(String packageName, int flags, int userId, + public final int getPackageUidInternal(String packageName, int flags, int userId, int callingUid) { synchronized (mLock) { return super.getPackageUidInternal(packageName, flags, userId, callingUid); } } - public SigningDetails getSigningDetails(@NonNull String packageName) { + public final SigningDetails getSigningDetails(@NonNull String packageName) { synchronized (mLock) { return super.getSigningDetails(packageName); } } - public SigningDetails getSigningDetails(int uid) { + public final SigningDetails getSigningDetails(int uid) { synchronized (mLock) { return super.getSigningDetails(uid); } } - public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) { + public final boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) { synchronized (mLock) { return super.filterAppAccess(pkg, callingUid, userId); } } - public boolean filterAppAccess(String packageName, int callingUid, int userId) { + public final boolean filterAppAccess(String packageName, int callingUid, int userId) { synchronized (mLock) { return super.filterAppAccess(packageName, callingUid, userId); } } - public void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) { + public final void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) { synchronized (mLock) { super.dump(type, fd, pw, dumpState); } @@ -12700,21 +12798,6 @@ public class PackageManagerService extends IPackageManager.Stub return performDexOpt(new DexoptOptions(packageName, compilerFilter, flags)); } - /** - * Ask the package manager to compile layouts in the given package. - */ - @Override - public boolean compileLayouts(String packageName) { - AndroidPackage pkg; - synchronized (mLock) { - pkg = mPackages.get(packageName); - if (pkg == null) { - return false; - } - } - return mViewCompiler.compileLayouts(pkg); - } - /*package*/ boolean performDexOpt(DexoptOptions options) { if (getInstantAppPackageName(Binder.getCallingUid()) != null) { return false; @@ -21397,6 +21480,8 @@ public class PackageManagerService extends IPackageManager.Stub // for the uninstall-updates case and restricted profiles, remember the per- // user handle installed state int[] allUsers; + final int freezeUser; + final SparseArray<Pair<Integer, String>> enabledStateAndCallerPerUser; /** enabled state of the uninstalled application */ synchronized (mLock) { uninstalledPs = mSettings.getPackageLPr(packageName); @@ -21441,16 +21526,23 @@ public class PackageManagerService extends IPackageManager.Stub } info.origUsers = uninstalledPs.queryInstalledUsers(allUsers, true); - } - final int freezeUser; - if (isUpdatedSystemApp(uninstalledPs) - && ((deleteFlags & PackageManager.DELETE_SYSTEM_APP) == 0)) { - // We're downgrading a system app, which will apply to all users, so - // freeze them all during the downgrade - freezeUser = UserHandle.USER_ALL; - } else { - freezeUser = removeUser; + if (isUpdatedSystemApp(uninstalledPs) + && ((deleteFlags & PackageManager.DELETE_SYSTEM_APP) == 0)) { + // We're downgrading a system app, which will apply to all users, so + // freeze them all during the downgrade + freezeUser = UserHandle.USER_ALL; + enabledStateAndCallerPerUser = new SparseArray<>(); + for (int i = 0; i < allUsers.length; i++) { + PackageUserState userState = uninstalledPs.readUserState(allUsers[i]); + Pair<Integer, String> enabledStateAndCaller = + new Pair<>(userState.enabled, userState.lastDisableAppCaller); + enabledStateAndCallerPerUser.put(allUsers[i], enabledStateAndCaller); + } + } else { + freezeUser = removeUser; + enabledStateAndCallerPerUser = null; + } } synchronized (mInstallLock) { @@ -21519,6 +21611,19 @@ public class PackageManagerService extends IPackageManager.Stub } } } + if (enabledStateAndCallerPerUser != null) { + synchronized (mLock) { + for (int i = 0; i < allUsers.length; i++) { + Pair<Integer, String> enabledStateAndCaller = + enabledStateAndCallerPerUser.get(allUsers[i]); + getPackageSetting(packageName) + .setEnabled(enabledStateAndCaller.first, + allUsers[i], + enabledStateAndCaller.second); + } + mSettings.writeAllUsersPackageRestrictionsLPr(); + } + } } return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR; diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 49559f299fa0..1aa80a953d6c 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -307,6 +307,8 @@ class PackageManagerShellCommand extends ShellCommand { return runLogVisibility(); case "bypass-staged-installer-check": return runBypassStagedInstallerCheck(); + case "bypass-allowed-apex-update-check": + return runBypassAllowedApexUpdateCheck(); case "set-silent-updates-policy": return runSetSilentUpdatesPolicy(); default: { @@ -424,6 +426,20 @@ class PackageManagerShellCommand extends ShellCommand { } } + private int runBypassAllowedApexUpdateCheck() { + final PrintWriter pw = getOutPrintWriter(); + try { + mInterface.getPackageInstaller() + .bypassNextAllowedApexUpdateCheck(Boolean.parseBoolean(getNextArg())); + return 0; + } catch (RemoteException e) { + pw.println("Failure [" + + e.getClass().getName() + " - " + + e.getMessage() + "]"); + return -1; + } + } + private int uninstallSystemUpdates(String packageName) { final PrintWriter pw = getOutPrintWriter(); boolean failedUninstalls = false; diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java b/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java index 05879ec9545e..fad0aefd3c0a 100644 --- a/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java +++ b/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java @@ -28,6 +28,7 @@ import com.android.server.pm.PackageSetting; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; /** * For use by {@link PackageSetting} to maintain functionality that used to exist in @@ -110,6 +111,10 @@ public class PackageStateUnserialized { this.overrideSeInfo = other.overrideSeInfo; } + public @NonNull List<SharedLibraryInfo> getNonNativeUsesLibraryInfos() { + return getUsesLibraryInfos().stream() + .filter((l) -> !l.isNative()).collect(Collectors.toList()); + } // Code below generated by codegen v1.0.14. diff --git a/services/core/java/com/android/server/policy/LegacyGlobalActions.java b/services/core/java/com/android/server/policy/LegacyGlobalActions.java index 5b48abb3e1f2..a5969a88008d 100644 --- a/services/core/java/com/android/server/policy/LegacyGlobalActions.java +++ b/services/core/java/com/android/server/policy/LegacyGlobalActions.java @@ -135,7 +135,10 @@ class LegacyGlobalActions implements DialogInterface.OnDismissListener, DialogIn filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); - context.registerReceiver(mBroadcastReceiver, filter); + // By default CLOSE_SYSTEM_DIALOGS broadcast is sent only for current user, which is user + // 10 on devices with headless system user enabled. + // In order to receive the broadcast, register the broadcast receiver with UserHandle.ALL. + context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null); mHasTelephony = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY); diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java index ed4a7bf107d1..f72adb609f6f 100644 --- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java +++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java @@ -961,11 +961,13 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo @Override public boolean allocateSpaceForUpdate(String packageFile) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null); if (!isUpdatableApexSupported()) { Log.i(TAG, "Updatable Apex not supported, " + "allocateSpaceForUpdate does nothing."); return true; } + final long token = Binder.clearCallingIdentity(); try { CompressedApexInfoList apexInfoList = getCompressedApexInfoList(packageFile); ApexManager apexManager = ApexManager.getInstance(); @@ -975,6 +977,8 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo e.rethrowAsRuntimeException(); } catch (IOException | UnsupportedOperationException e) { Slog.e(TAG, "Failed to reserve space for compressed apex: ", e); + } finally { + Binder.restoreCallingIdentity(token); } return false; } diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java index f7d61367c81e..95a06fcff734 100644 --- a/services/core/java/com/android/server/vcn/Vcn.java +++ b/services/core/java/com/android/server/vcn/Vcn.java @@ -453,6 +453,10 @@ public class Vcn extends Handler { for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) { gatewayConnection.updateSubscriptionSnapshot(mLastSnapshot); } + + // Update the mobile data state after updating the subscription snapshot as a change in + // subIds for a subGroup may affect the mobile data state. + handleMobileDataToggled(); } private void handleMobileDataToggled() { diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java index f756434e981a..885f0e4c78ab 100644 --- a/services/core/java/com/android/server/vibrator/VibrationSettings.java +++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java @@ -353,6 +353,7 @@ final class VibrationSettings { + ", mLowPowerMode=" + mLowPowerMode + ", mZenMode=" + Settings.Global.zenModeToString(mZenMode) + ", mProcStatesCache=" + mUidObserver.mProcStatesCache + + ", mHapticChannelMaxVibrationAmplitude=" + getHapticChannelMaxVibrationAmplitude() + ", mHapticFeedbackIntensity=" + intensityToString(getCurrentIntensity(VibrationAttributes.USAGE_TOUCH)) + ", mHapticFeedbackDefaultIntensity=" @@ -411,6 +412,12 @@ final class VibrationSettings { } } + private float getHapticChannelMaxVibrationAmplitude() { + synchronized (mLock) { + return mVibrator == null ? Float.NaN : mVibrator.getHapticChannelMaximumAmplitude(); + } + } + private int getSystemSetting(String settingName, int defaultValue) { return Settings.System.getIntForUser(mContext.getContentResolver(), settingName, defaultValue, UserHandle.USER_CURRENT); diff --git a/services/core/java/com/android/server/vibrator/VibrationThread.java b/services/core/java/com/android/server/vibrator/VibrationThread.java index 150fde99b706..45d511159e11 100644 --- a/services/core/java/com/android/server/vibrator/VibrationThread.java +++ b/services/core/java/com/android/server/vibrator/VibrationThread.java @@ -844,7 +844,12 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient { public List<Step> play() { Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "ComposePrimitivesStep"); try { - int segmentCount = effect.getSegments().size(); + // Load the next PrimitiveSegments to create a single compose call to the vibrator, + // limited to the vibrator composition maximum size. + int limit = controller.getVibratorInfo().getCompositionSizeMax(); + int segmentCount = limit > 0 + ? Math.min(effect.getSegments().size(), segmentIndex + limit) + : effect.getSegments().size(); List<PrimitiveSegment> primitives = new ArrayList<>(); for (int i = segmentIndex; i < segmentCount; i++) { VibrationEffectSegment segment = effect.getSegments().get(i); @@ -896,7 +901,12 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient { public List<Step> play() { Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "ComposePwleStep"); try { - int segmentCount = effect.getSegments().size(); + // Load the next RampSegments to create a single composePwle call to the vibrator, + // limited to the vibrator PWLE maximum size. + int limit = controller.getVibratorInfo().getPwleSizeMax(); + int segmentCount = limit > 0 + ? Math.min(effect.getSegments().size(), segmentIndex + limit) + : effect.getSegments().size(); List<RampSegment> pwles = new ArrayList<>(); for (int i = segmentIndex; i < segmentCount; i++) { VibrationEffectSegment segment = effect.getSegments().get(i); diff --git a/services/core/java/com/android/server/vibrator/VibratorController.java b/services/core/java/com/android/server/vibrator/VibratorController.java index 5dceac2d066c..001d5c440d58 100644 --- a/services/core/java/com/android/server/vibrator/VibratorController.java +++ b/services/core/java/com/android/server/vibrator/VibratorController.java @@ -30,19 +30,24 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.Preconditions; import libcore.util.NativeAllocationRegistry; /** Controls a single vibrator. */ final class VibratorController { private static final String TAG = "VibratorController"; + // TODO(b/167947076): load suggested range from config + private static final int SUGGESTED_FREQUENCY_SAFE_RANGE = 200; private final Object mLock = new Object(); private final NativeWrapper mNativeWrapper; - private final VibratorInfo mVibratorInfo; + private final VibratorInfo.Builder mVibratorInfoBuilder; @GuardedBy("mLock") + private VibratorInfo mVibratorInfo; + @GuardedBy("mLock") + private boolean mVibratorInfoLoaded; + @GuardedBy("mLock") private final RemoteCallbackList<IVibratorStateListener> mVibratorStateListeners = new RemoteCallbackList<>(); @GuardedBy("mLock") @@ -66,10 +71,10 @@ final class VibratorController { NativeWrapper nativeWrapper) { mNativeWrapper = nativeWrapper; mNativeWrapper.init(vibratorId, listener); - // TODO(b/167947076): load suggested range from config - mVibratorInfo = mNativeWrapper.getInfo(/* suggestedFrequencyRange= */ 200); - Preconditions.checkNotNull(mVibratorInfo, "Failed to retrieve data for vibrator %d", - vibratorId); + mVibratorInfoBuilder = new VibratorInfo.Builder(vibratorId); + mVibratorInfoLoaded = mNativeWrapper.getInfo(SUGGESTED_FREQUENCY_SAFE_RANGE, + mVibratorInfoBuilder); + mVibratorInfo = mVibratorInfoBuilder.build(); } /** Register state listener for this vibrator. */ @@ -103,7 +108,15 @@ final class VibratorController { /** Return the {@link VibratorInfo} representing the vibrator controlled by this instance. */ public VibratorInfo getVibratorInfo() { - return mVibratorInfo; + synchronized (mLock) { + if (!mVibratorInfoLoaded) { + // Try to load the vibrator metadata that has failed in the last attempt. + mVibratorInfoLoaded = mNativeWrapper.getInfo(SUGGESTED_FREQUENCY_SAFE_RANGE, + mVibratorInfoBuilder); + mVibratorInfo = mVibratorInfoBuilder.build(); + } + return mVibratorInfo; + } } /** @@ -361,7 +374,8 @@ final class VibratorController { private static native void alwaysOnDisable(long nativePtr, long id); - private static native VibratorInfo getInfo(long nativePtr, float suggestedFrequencyRange); + private static native boolean getInfo(long nativePtr, float suggestedFrequencyRange, + VibratorInfo.Builder infoBuilder); private long mNativePtr = 0; @@ -428,9 +442,11 @@ final class VibratorController { alwaysOnDisable(mNativePtr, id); } - /** Return device vibrator metadata. */ - public VibratorInfo getInfo(float suggestedFrequencyRange) { - return getInfo(mNativePtr, suggestedFrequencyRange); + /** + * Loads device vibrator metadata and returns true if all metadata was loaded successfully. + */ + public boolean getInfo(float suggestedFrequencyRange, VibratorInfo.Builder infoBuilder) { + return getInfo(mNativePtr, suggestedFrequencyRange, infoBuilder); } } } diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index 53f1035ee422..782e18b0250c 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -129,7 +129,9 @@ import java.io.InputStream; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.function.Consumer; import java.util.function.Predicate; @@ -3140,7 +3142,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } } - private void writeWallpaperAttributes(TypedXmlSerializer out, String tag, + + @VisibleForTesting + void writeWallpaperAttributes(TypedXmlSerializer out, String tag, WallpaperData wallpaper) throws IllegalArgumentException, IllegalStateException, IOException { if (DEBUG) { @@ -3179,6 +3183,19 @@ public class WallpaperManagerService extends IWallpaperManager.Stub out.attributeInt(null, "colorValue" + i, wc.toArgb()); } } + + int allColorsCount = wallpaper.primaryColors.getAllColors().size(); + out.attributeInt(null, "allColorsCount", allColorsCount); + if (allColorsCount > 0) { + int index = 0; + for (Map.Entry<Integer, Integer> entry : wallpaper.primaryColors.getAllColors() + .entrySet()) { + out.attributeInt(null, "allColorsValue" + index, entry.getKey()); + out.attributeInt(null, "allColorsPopulation" + index, entry.getValue()); + index++; + } + } + out.attributeInt(null, "colorHints", wallpaper.primaryColors.getColorHints()); } @@ -3410,7 +3427,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } } - private void parseWallpaperAttributes(TypedXmlPullParser parser, WallpaperData wallpaper, + @VisibleForTesting + void parseWallpaperAttributes(TypedXmlPullParser parser, WallpaperData wallpaper, boolean keepDimensionHints) throws XmlPullParserException { final int id = parser.getAttributeInt(null, "id", -1); if (id != -1) { @@ -3437,7 +3455,17 @@ public class WallpaperManagerService extends IWallpaperManager.Stub wpData.mPadding.right = getAttributeInt(parser, "paddingRight", 0); wpData.mPadding.bottom = getAttributeInt(parser, "paddingBottom", 0); int colorsCount = getAttributeInt(parser, "colorsCount", 0); - if (colorsCount > 0) { + int allColorsCount = getAttributeInt(parser, "allColorsCount", 0); + if (allColorsCount > 0) { + Map<Integer, Integer> allColors = new HashMap<>(allColorsCount); + for (int i = 0; i < allColorsCount; i++) { + int colorInt = getAttributeInt(parser, "allColorsValue" + i, 0); + int population = getAttributeInt(parser, "allColorsPopulation" + i, 0); + allColors.put(colorInt, population); + } + int colorHints = getAttributeInt(parser, "colorHints", 0); + wallpaper.primaryColors = new WallpaperColors(allColors, colorHints); + } else if (colorsCount > 0) { Color primary = null, secondary = null, tertiary = null; for (int i = 0; i < colorsCount; i++) { Color color = Color.valueOf(getAttributeInt(parser, "colorValue" + i, 0)); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 55d1920681c5..b156e12a1ce8 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -677,8 +677,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A private boolean mInSizeCompatModeForBounds = false; // Whether the aspect ratio restrictions applied to the activity bounds in applyAspectRatio(). - // TODO(b/182268157): Aspect ratio can also be applie in resolveFixedOrientationConfiguration - // but that isn't reflected in this boolean. private boolean mIsAspectRatioApplied = false; // Bounds populated in resolveFixedOrientationConfiguration when this activity is letterboxed @@ -7266,41 +7264,48 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } final Rect parentBounds = newParentConfig.windowConfiguration.getBounds(); - final int parentWidth = parentBounds.width(); - final int parentHeight = parentBounds.height(); - float aspect = Math.max(parentWidth, parentHeight) - / (float) Math.min(parentWidth, parentHeight); + final Rect parentAppBounds = newParentConfig.windowConfiguration.getAppBounds(); + final Rect containingBounds = new Rect(); + final Rect containingAppBounds = new Rect(); + // Need to shrink the containing bounds into a square because the parent orientation does + // not match the activity requested orientation. + if (forcedOrientation == ORIENTATION_LANDSCAPE) { + // Shrink height to match width. Position height within app bounds. + final int bottom = Math.min(parentAppBounds.top + parentBounds.width(), + parentAppBounds.bottom); + containingBounds.set(parentBounds.left, parentAppBounds.top, parentBounds.right, + bottom); + containingAppBounds.set(parentAppBounds.left, parentAppBounds.top, + parentAppBounds.right, bottom); + } else { + // Shrink width to match height. Position width within app bounds. + final int right = Math.min(parentAppBounds.left + parentBounds.height(), + parentAppBounds.right); + containingBounds.set(parentAppBounds.left, parentBounds.top, right, + parentBounds.bottom); + containingAppBounds.set(parentAppBounds.left, parentAppBounds.top, right, + parentAppBounds.bottom); + } + + Rect mTmpFullBounds = new Rect(resolvedBounds); + resolvedBounds.set(containingBounds); // Override from config_fixedOrientationLetterboxAspectRatio or via ADB with // set-fixed-orientation-letterbox-aspect-ratio. final float letterboxAspectRatioOverride = mWmService.mLetterboxConfiguration.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.getMaxAspectRatio(); - final float minAspectRatio = info.getMinAspectRatio(); - if (aspect > maxAspectRatio && maxAspectRatio != 0) { - aspect = maxAspectRatio; - } else if (aspect < minAspectRatio) { - aspect = minAspectRatio; - } - - // Store the current bounds to be able to revert to size compat mode values below if needed. - Rect mTmpFullBounds = new Rect(resolvedBounds); + final float desiredAspectRatio = + letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO + ? letterboxAspectRatioOverride : computeAspectRatio(parentBounds); + // Apply aspect ratio to resolved bounds + mIsAspectRatioApplied = applyAspectRatio(resolvedBounds, containingAppBounds, + containingBounds, desiredAspectRatio, true); + + // Vertically center if orientation is landscape. Bounds will later be horizontally centered + // in {@link updateResolvedBoundsHorizontalPosition()} regardless of orientation. if (forcedOrientation == ORIENTATION_LANDSCAPE) { - final int height = (int) Math.rint(parentWidth / aspect); - final int top = parentBounds.centerY() - height / 2; - resolvedBounds.set(parentBounds.left, top, parentBounds.right, top + height); - } else { - final int width = (int) Math.rint(parentHeight / aspect); - final Rect parentAppBounds = newParentConfig.windowConfiguration.getAppBounds(); - final int left = width <= parentAppBounds.width() - // Avoid overlapping with the horizontal decor area when possible. - ? parentAppBounds.left : parentBounds.centerX() - width / 2; - resolvedBounds.set(left, parentBounds.top, left + width, parentBounds.bottom); + final int offsetY = parentBounds.centerY() - resolvedBounds.centerY(); + resolvedBounds.offset(0, offsetY); } if (mCompatDisplayInsets != null) { @@ -7342,8 +7347,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // then they should be aligned later in #updateResolvedBoundsHorizontalPosition(). if (!mTmpBounds.isEmpty()) { resolvedBounds.set(mTmpBounds); - // Exclude the horizontal decor area. - resolvedBounds.left = parentAppBounds.left; } if (!resolvedBounds.isEmpty() && !resolvedBounds.equals(parentBounds)) { // Compute the configuration based on the resolved bounds. If aspect ratio doesn't @@ -7404,13 +7407,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mIsAspectRatioApplied = applyAspectRatio(resolvedBounds, containingAppBounds, containingBounds); } - // If the bounds are restricted by fixed aspect ratio, the resolved bounds should be put in - // the container app bounds. Otherwise the entire container bounds are available. - final boolean fillContainer = resolvedBounds.equals(containingBounds); - if (!fillContainer) { - // The horizontal position should not cover insets. - resolvedBounds.left = containingAppBounds.left; - } // Use resolvedBounds to compute other override configurations such as appBounds. The bounds // are calculated in compat container space. The actual position on screen will be applied @@ -7477,6 +7473,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // Align to top of parent (bounds) - this is a UX choice and exclude the horizontal decor // if needed. Horizontal position is adjusted in updateResolvedBoundsHorizontalPosition. // Above coordinates are in "@" space, now place "*" and "#" to screen space. + final boolean fillContainer = resolvedBounds.equals(containingBounds); final int screenPosX = fillContainer ? containerBounds.left : containerAppBounds.left; final int screenPosY = containerBounds.top; if (screenPosX != 0 || screenPosY != 0) { @@ -7713,6 +7710,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return true; } + private boolean applyAspectRatio(Rect outBounds, Rect containingAppBounds, + Rect containingBounds) { + return applyAspectRatio(outBounds, containingAppBounds, containingBounds, + 0 /* desiredAspectRatio */, false /* fixedOrientationLetterboxed */); + } + /** * Applies aspect ratio restrictions to outBounds. If no restrictions, then no change is * made to outBounds. @@ -7721,17 +7724,19 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A */ // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer. private boolean applyAspectRatio(Rect outBounds, Rect containingAppBounds, - Rect containingBounds) { + Rect containingBounds, float desiredAspectRatio, boolean fixedOrientationLetterboxed) { final float maxAspectRatio = info.getMaxAspectRatio(); final Task rootTask = getRootTask(); final float minAspectRatio = info.getMinAspectRatio(); if (task == null || rootTask == null - || (inMultiWindowMode() && !shouldCreateCompatDisplayInsets()) - || (maxAspectRatio == 0 && minAspectRatio == 0) + || (inMultiWindowMode() && !shouldCreateCompatDisplayInsets() + && !fixedOrientationLetterboxed) + || (maxAspectRatio < 1 && minAspectRatio < 1 && desiredAspectRatio < 1) || isInVrUiMode(getConfiguration())) { - // We don't enforce aspect ratio if the activity task is in multiwindow unless it - // is in size-compat mode. We also don't set it if we are in VR mode. + // We don't enforce aspect ratio if the activity task is in multiwindow unless it is in + // size-compat mode or is letterboxed from fixed orientation. We also don't set it if we + // are in VR mode. return false; } @@ -7739,20 +7744,30 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final int containingAppHeight = containingAppBounds.height(); final float containingRatio = computeAspectRatio(containingAppBounds); + if (desiredAspectRatio < 1) { + desiredAspectRatio = containingRatio; + } + + if (maxAspectRatio >= 1 && desiredAspectRatio > maxAspectRatio) { + desiredAspectRatio = maxAspectRatio; + } else if (minAspectRatio >= 1 && desiredAspectRatio < minAspectRatio) { + desiredAspectRatio = minAspectRatio; + } + int activityWidth = containingAppWidth; int activityHeight = containingAppHeight; - if (containingRatio > maxAspectRatio && maxAspectRatio != 0) { + if (containingRatio > desiredAspectRatio) { if (containingAppWidth < containingAppHeight) { // Width is the shorter side, so we use that to figure-out what the max. height // should be given the aspect ratio. - activityHeight = (int) ((activityWidth * maxAspectRatio) + 0.5f); + activityHeight = (int) ((activityWidth * desiredAspectRatio) + 0.5f); } else { // Height is the shorter side, so we use that to figure-out what the max. width // should be given the aspect ratio. - activityWidth = (int) ((activityHeight * maxAspectRatio) + 0.5f); + activityWidth = (int) ((activityHeight * desiredAspectRatio) + 0.5f); } - } else if (containingRatio < minAspectRatio) { + } else if (containingRatio < desiredAspectRatio) { boolean adjustWidth; switch (getRequestedConfigurationOrientation()) { case ORIENTATION_LANDSCAPE: @@ -7780,9 +7795,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A break; } if (adjustWidth) { - activityWidth = (int) ((activityHeight / minAspectRatio) + 0.5f); + activityWidth = (int) ((activityHeight / desiredAspectRatio) + 0.5f); } else { - activityHeight = (int) ((activityWidth / minAspectRatio) + 0.5f); + activityHeight = (int) ((activityWidth / desiredAspectRatio) + 0.5f); } } @@ -7806,6 +7821,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } outBounds.set(containingBounds.left, containingBounds.top, right, bottom); + // If the bounds are restricted by fixed aspect ratio, then out bounds should be put in the + // container app bounds. Otherwise the entire container bounds are available. + if (!outBounds.equals(containingBounds)) { + // The horizontal position should not cover insets. + outBounds.left = containingAppBounds.left; + } + return true; } diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index ea80b8bb5286..c510603d1d7d 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -17,6 +17,7 @@ package com.android.server.wm; import static android.app.ActivityTaskManager.INVALID_TASK_ID; +import static android.app.KeyguardManager.ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; @@ -3383,6 +3384,15 @@ class RootWindowContainer extends WindowContainer<DisplayContent> */ void lockAllProfileTasks(@UserIdInt int userId) { forAllLeafTasks(task -> { + final ActivityRecord top = task.topRunningActivity(); + if (top != null && !top.finishing + && ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER.equals(top.intent.getAction()) + && top.packageName.equals( + mService.getSysUiServiceComponentLocked().getPackageName())) { + // Do nothing since the task is already secure by sysui. + return; + } + if (task.getActivity(activity -> !activity.finishing && activity.mUserId == userId) != null) { mService.getTaskChangeNotificationController().notifyTaskProfileLocked( diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 565f99f80890..325f10f65af2 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -974,10 +974,7 @@ class Task extends WindowContainer<WindowContainer> { } void removeIfPossible(String reason) { - final boolean isRootTask = isRootTask(); - if (!isRootTask) { - mAtmService.getLockTaskController().clearLockedTask(this); - } + mAtmService.getLockTaskController().clearLockedTask(this); if (shouldDeferRemoval()) { if (DEBUG_ROOT_TASK) Slog.i(TAG, "removeTask:" + reason + " deferring removing taskId=" + mTaskId); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index e9dd521670a9..2c8fcebdd50f 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2463,6 +2463,17 @@ public class WindowManagerService extends IWindowManager.Stub configChanged = displayContent.updateOrientation(); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); + final DisplayInfo rotatedDisplayInfo = + win.mToken.getFixedRotationTransformDisplayInfo(); + if (rotatedDisplayInfo != null) { + outSurfaceControl.setTransformHint(rotatedDisplayInfo.rotation); + } else { + // We have to update the transform hint of display here, but we need to get if from + // SurfaceFlinger, so set it as rotation of display for most cases, then + // SurfaceFlinger would still update the transform hint of display in next frame. + outSurfaceControl.setTransformHint(displayContent.getDisplayInfo().rotation); + } + if (toBeDisplayed && win.mIsWallpaper) { displayContent.mWallpaperController.updateWallpaperOffset(win, false /* sync */); } diff --git a/services/core/jni/com_android_server_vibrator_VibratorController.cpp b/services/core/jni/com_android_server_vibrator_VibratorController.cpp index 698e3f75d0ed..9029fe7cca66 100644 --- a/services/core/jni/com_android_server_vibrator_VibratorController.cpp +++ b/services/core/jni/com_android_server_vibrator_VibratorController.cpp @@ -41,8 +41,18 @@ static JavaVM* sJvm = nullptr; static jmethodID sMethodIdOnComplete; static jclass sFrequencyMappingClass; static jmethodID sFrequencyMappingCtor; -static jclass sVibratorInfoClass; -static jmethodID sVibratorInfoCtor; +static struct { + jmethodID setCapabilities; + jmethodID setSupportedEffects; + jmethodID setSupportedBraking; + jmethodID setPwlePrimitiveDurationMax; + jmethodID setPwleSizeMax; + jmethodID setSupportedPrimitive; + jmethodID setPrimitiveDelayMax; + jmethodID setCompositionSizeMax; + jmethodID setQFactor; + jmethodID setFrequencyMapping; +} sVibratorInfoBuilderClassInfo; static struct { jfieldID id; jfieldID scale; @@ -352,68 +362,88 @@ static void vibratorAlwaysOnDisable(JNIEnv* env, jclass /* clazz */, jlong ptr, wrapper->halCall<void>(alwaysOnDisableFn, "alwaysOnDisable"); } -static jobject vibratorGetInfo(JNIEnv* env, jclass /* clazz */, jlong ptr, - jfloat suggestedSafeRange) { +static jboolean vibratorGetInfo(JNIEnv* env, jclass /* clazz */, jlong ptr, + jfloat suggestedSafeRange, jobject vibratorInfoBuilder) { VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr); if (wrapper == nullptr) { ALOGE("vibratorGetInfo failed because native wrapper was not initialized"); - return nullptr; + return JNI_FALSE; } vibrator::Info info = wrapper->getVibratorInfo(); - jlong capabilities = - static_cast<jlong>(info.capabilities.valueOr(vibrator::Capabilities::NONE)); - jfloat minFrequency = static_cast<jfloat>(info.minFrequency.valueOr(NAN)); - jfloat resonantFrequency = static_cast<jfloat>(info.resonantFrequency.valueOr(NAN)); - jfloat frequencyResolution = static_cast<jfloat>(info.frequencyResolution.valueOr(NAN)); - jfloat qFactor = static_cast<jfloat>(info.qFactor.valueOr(NAN)); - jintArray supportedEffects = nullptr; - jintArray supportedBraking = nullptr; - jintArray supportedPrimitives = nullptr; - jintArray primitiveDurations = nullptr; - jfloatArray maxAmplitudes = nullptr; - + if (info.capabilities.isOk()) { + env->CallObjectMethod(vibratorInfoBuilder, sVibratorInfoBuilderClassInfo.setCapabilities, + static_cast<jlong>(info.capabilities.value())); + } if (info.supportedEffects.isOk()) { std::vector<aidl::Effect> effects = info.supportedEffects.value(); - supportedEffects = env->NewIntArray(effects.size()); + jintArray supportedEffects = env->NewIntArray(effects.size()); env->SetIntArrayRegion(supportedEffects, 0, effects.size(), reinterpret_cast<jint*>(effects.data())); + env->CallObjectMethod(vibratorInfoBuilder, + sVibratorInfoBuilderClassInfo.setSupportedEffects, supportedEffects); } if (info.supportedBraking.isOk()) { std::vector<aidl::Braking> braking = info.supportedBraking.value(); - supportedBraking = env->NewIntArray(braking.size()); + jintArray supportedBraking = env->NewIntArray(braking.size()); env->SetIntArrayRegion(supportedBraking, 0, braking.size(), reinterpret_cast<jint*>(braking.data())); + env->CallObjectMethod(vibratorInfoBuilder, + sVibratorInfoBuilderClassInfo.setSupportedBraking, supportedBraking); } - if (info.supportedPrimitives.isOk()) { - std::vector<aidl::CompositePrimitive> primitives = info.supportedPrimitives.value(); - supportedPrimitives = env->NewIntArray(primitives.size()); - env->SetIntArrayRegion(supportedPrimitives, 0, primitives.size(), - reinterpret_cast<jint*>(primitives.data())); + if (info.pwlePrimitiveDurationMax.isOk()) { + env->CallObjectMethod(vibratorInfoBuilder, + sVibratorInfoBuilderClassInfo.setPwlePrimitiveDurationMax, + static_cast<jint>(info.pwlePrimitiveDurationMax.value().count())); + } + if (info.pwleSizeMax.isOk()) { + // Use (pwleMaxSize - 1) to account for a possible extra braking segment added by the + // vibratorPerformPwleEffect method. + env->CallObjectMethod(vibratorInfoBuilder, sVibratorInfoBuilderClassInfo.setPwleSizeMax, + static_cast<jint>(info.pwleSizeMax.value() - 1)); } - if (info.primitiveDurations.isOk()) { - std::vector<int32_t> durations; - for (auto duration : info.primitiveDurations.value()) { - durations.push_back(duration.count()); + if (info.supportedPrimitives.isOk()) { + auto durations = info.primitiveDurations.valueOr({}); + for (auto& primitive : info.supportedPrimitives.value()) { + auto primitiveIdx = static_cast<size_t>(primitive); + auto duration = durations.size() > primitiveIdx ? durations[primitiveIdx].count() : 0; + env->CallObjectMethod(vibratorInfoBuilder, + sVibratorInfoBuilderClassInfo.setSupportedPrimitive, + static_cast<jint>(primitive), static_cast<jint>(duration)); } - primitiveDurations = env->NewIntArray(durations.size()); - env->SetIntArrayRegion(primitiveDurations, 0, durations.size(), - reinterpret_cast<jint*>(durations.data())); } + if (info.primitiveDelayMax.isOk()) { + env->CallObjectMethod(vibratorInfoBuilder, + sVibratorInfoBuilderClassInfo.setPrimitiveDelayMax, + static_cast<jint>(info.primitiveDelayMax.value().count())); + } + if (info.compositionSizeMax.isOk()) { + env->CallObjectMethod(vibratorInfoBuilder, + sVibratorInfoBuilderClassInfo.setCompositionSizeMax, + static_cast<jint>(info.compositionSizeMax.value())); + } + if (info.qFactor.isOk()) { + env->CallObjectMethod(vibratorInfoBuilder, sVibratorInfoBuilderClassInfo.setQFactor, + static_cast<jfloat>(info.qFactor.value())); + } + + jfloat minFrequency = static_cast<jfloat>(info.minFrequency.valueOr(NAN)); + jfloat resonantFrequency = static_cast<jfloat>(info.resonantFrequency.valueOr(NAN)); + jfloat frequencyResolution = static_cast<jfloat>(info.frequencyResolution.valueOr(NAN)); + jfloatArray maxAmplitudes = nullptr; if (info.maxAmplitudes.isOk()) { std::vector<float> amplitudes = info.maxAmplitudes.value(); maxAmplitudes = env->NewFloatArray(amplitudes.size()); env->SetFloatArrayRegion(maxAmplitudes, 0, amplitudes.size(), reinterpret_cast<jfloat*>(amplitudes.data())); } - jobject frequencyMapping = env->NewObject(sFrequencyMappingClass, sFrequencyMappingCtor, minFrequency, resonantFrequency, frequencyResolution, suggestedSafeRange, maxAmplitudes); + env->CallObjectMethod(vibratorInfoBuilder, sVibratorInfoBuilderClassInfo.setFrequencyMapping, + frequencyMapping); - return env->NewObject(sVibratorInfoClass, sVibratorInfoCtor, wrapper->getVibratorId(), - capabilities, supportedEffects, supportedBraking, supportedPrimitives, - primitiveDurations, qFactor, frequencyMapping); + return info.checkAndLogFailure("vibratorGetInfo") ? JNI_FALSE : JNI_TRUE; } static const JNINativeMethod method_table[] = { @@ -433,7 +463,7 @@ static const JNINativeMethod method_table[] = { {"setExternalControl", "(JZ)V", (void*)vibratorSetExternalControl}, {"alwaysOnEnable", "(JJJJ)V", (void*)vibratorAlwaysOnEnable}, {"alwaysOnDisable", "(JJ)V", (void*)vibratorAlwaysOnDisable}, - {"getInfo", "(JF)Landroid/os/VibratorInfo;", (void*)vibratorGetInfo}, + {"getInfo", "(JFLandroid/os/VibratorInfo$Builder;)Z", (void*)vibratorGetInfo}, }; int register_android_server_vibrator_VibratorController(JavaVM* jvm, JNIEnv* env) { @@ -459,11 +489,38 @@ int register_android_server_vibrator_VibratorController(JavaVM* jvm, JNIEnv* env sFrequencyMappingClass = static_cast<jclass>(env->NewGlobalRef(frequencyMappingClass)); sFrequencyMappingCtor = GetMethodIDOrDie(env, sFrequencyMappingClass, "<init>", "(FFFF[F)V"); - jclass vibratorInfoClass = FindClassOrDie(env, "android/os/VibratorInfo"); - sVibratorInfoClass = (jclass)env->NewGlobalRef(vibratorInfoClass); - sVibratorInfoCtor = - GetMethodIDOrDie(env, sVibratorInfoClass, "<init>", - "(IJ[I[I[I[IFLandroid/os/VibratorInfo$FrequencyMapping;)V"); + jclass vibratorInfoBuilderClass = FindClassOrDie(env, "android/os/VibratorInfo$Builder"); + sVibratorInfoBuilderClassInfo.setCapabilities = + GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setCapabilities", + "(J)Landroid/os/VibratorInfo$Builder;"); + sVibratorInfoBuilderClassInfo.setSupportedEffects = + GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setSupportedEffects", + "([I)Landroid/os/VibratorInfo$Builder;"); + sVibratorInfoBuilderClassInfo.setSupportedBraking = + GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setSupportedBraking", + "([I)Landroid/os/VibratorInfo$Builder;"); + sVibratorInfoBuilderClassInfo.setPwlePrimitiveDurationMax = + GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setPwlePrimitiveDurationMax", + "(I)Landroid/os/VibratorInfo$Builder;"); + sVibratorInfoBuilderClassInfo.setPwleSizeMax = + GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setPwleSizeMax", + "(I)Landroid/os/VibratorInfo$Builder;"); + sVibratorInfoBuilderClassInfo.setSupportedPrimitive = + GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setSupportedPrimitive", + "(II)Landroid/os/VibratorInfo$Builder;"); + sVibratorInfoBuilderClassInfo.setPrimitiveDelayMax = + GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setPrimitiveDelayMax", + "(I)Landroid/os/VibratorInfo$Builder;"); + sVibratorInfoBuilderClassInfo.setCompositionSizeMax = + GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setCompositionSizeMax", + "(I)Landroid/os/VibratorInfo$Builder;"); + sVibratorInfoBuilderClassInfo.setQFactor = + GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setQFactor", + "(F)Landroid/os/VibratorInfo$Builder;"); + sVibratorInfoBuilderClassInfo.setFrequencyMapping = + GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setFrequencyMapping", + "(Landroid/os/VibratorInfo$FrequencyMapping;)" + "Landroid/os/VibratorInfo$Builder;"); return jniRegisterNativeMethods(env, "com/android/server/vibrator/VibratorController$NativeWrapper", diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd index 3e2e37c834f1..82aaa61527d1 100644 --- a/services/core/xsd/display-device-config/display-device-config.xsd +++ b/services/core/xsd/display-device-config/display-device-config.xsd @@ -77,6 +77,10 @@ <xs:annotation name="final"/> </xs:element> <xs:element name="timing" type="hbmTiming" minOccurs="1" maxOccurs="1"/> + <xs:element type="refreshRateRange" name="refreshRate" minOccurs="0" maxOccurs="1"> + <xs:annotation name="nullable"/> + <xs:annotation name="final"/> + </xs:element> </xs:all> <xs:attribute name="enabled" type="xs:boolean" use="optional"/> </xs:complexType> diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt index d40854a87453..6e2e3625f60c 100644 --- a/services/core/xsd/display-device-config/schema/current.txt +++ b/services/core/xsd/display-device-config/schema/current.txt @@ -44,10 +44,12 @@ package com.android.server.display.config { ctor public HighBrightnessMode(); method public boolean getEnabled(); method @NonNull public final java.math.BigDecimal getMinimumLux_all(); + method @Nullable public final com.android.server.display.config.RefreshRateRange getRefreshRate_all(); method public com.android.server.display.config.HbmTiming getTiming_all(); method @NonNull public final java.math.BigDecimal getTransitionPoint_all(); method public void setEnabled(boolean); method public final void setMinimumLux_all(@NonNull java.math.BigDecimal); + method public final void setRefreshRate_all(@Nullable com.android.server.display.config.RefreshRateRange); method public void setTiming_all(com.android.server.display.config.HbmTiming); method public final void setTransitionPoint_all(@NonNull java.math.BigDecimal); } diff --git a/services/net/Android.bp b/services/net/Android.bp index f92db86bb880..dd864aed4e8e 100644 --- a/services/net/Android.bp +++ b/services/net/Android.bp @@ -37,15 +37,7 @@ java_library { name: "services.net-module-wifi", srcs: [ ":framework-services-net-module-wifi-shared-srcs", - ":net-module-utils-srcs", ":net-utils-services-common-srcs", - "java/android/net/ip/IpClientCallbacks.java", - "java/android/net/ip/IpClientManager.java", - "java/android/net/ip/IpClientUtil.java", - "java/android/net/util/KeepalivePacketDataUtil.java", - "java/android/net/util/NetworkConstants.java", - "java/android/net/IpMemoryStore.java", - "java/android/net/NetworkMonitorManager.java", ], sdk_version: "module_current", min_sdk_version: "30", @@ -89,11 +81,7 @@ filegroup { filegroup { name: "services-connectivity-shared-srcs", srcs: [ - // TODO: move to networkstack-client - "java/android/net/IpMemoryStore.java", - "java/android/net/NetworkMonitorManager.java", // TODO: move to libs/net - "java/android/net/util/KeepalivePacketDataUtil.java", "java/android/net/util/NetworkConstants.java", ], } diff --git a/services/net/java/android/net/IpMemoryStore.java b/services/net/java/android/net/IpMemoryStore.java deleted file mode 100644 index 8df2e0d08e0e..000000000000 --- a/services/net/java/android/net/IpMemoryStore.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2019 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; - -import android.annotation.NonNull; -import android.content.Context; -import android.net.networkstack.ModuleNetworkStackClient; -import android.util.Log; - -import com.android.internal.annotations.VisibleForTesting; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Consumer; - -/** - * Manager class used to communicate with the ip memory store service in the network stack, - * which is running in a separate module. - * @hide -*/ -public class IpMemoryStore extends IpMemoryStoreClient { - private static final String TAG = IpMemoryStore.class.getSimpleName(); - @NonNull private final CompletableFuture<IIpMemoryStore> mService; - @NonNull private final AtomicReference<CompletableFuture<IIpMemoryStore>> mTailNode; - - public IpMemoryStore(@NonNull final Context context) { - super(context); - mService = new CompletableFuture<>(); - mTailNode = new AtomicReference<CompletableFuture<IIpMemoryStore>>(mService); - getModuleNetworkStackClient(context).fetchIpMemoryStore( - new IIpMemoryStoreCallbacks.Stub() { - @Override - public void onIpMemoryStoreFetched(@NonNull final IIpMemoryStore memoryStore) { - mService.complete(memoryStore); - } - - @Override - public int getInterfaceVersion() { - return this.VERSION; - } - - @Override - public String getInterfaceHash() { - return this.HASH; - } - }); - } - - /* - * If the IpMemoryStore is ready, this function will run the request synchronously. - * Otherwise, it will enqueue the requests for execution immediately after the - * service becomes ready. The requests are guaranteed to be executed in the order - * they are sumbitted. - */ - @Override - protected void runWhenServiceReady(Consumer<IIpMemoryStore> cb) throws ExecutionException { - mTailNode.getAndUpdate(future -> future.handle((store, exception) -> { - if (exception != null) { - // this should never happens since we also catch the exception below - Log.wtf(TAG, "Error fetching IpMemoryStore", exception); - return store; - } - - try { - cb.accept(store); - } catch (Exception e) { - Log.wtf(TAG, "Exception occured: " + e.getMessage()); - } - return store; - })); - } - - @VisibleForTesting - protected ModuleNetworkStackClient getModuleNetworkStackClient(Context context) { - return ModuleNetworkStackClient.getInstance(context); - } - - /** Gets an instance of the memory store */ - @NonNull - public static IpMemoryStore getMemoryStore(final Context context) { - return new IpMemoryStore(context); - } -} diff --git a/services/net/java/android/net/NetworkMonitorManager.java b/services/net/java/android/net/NetworkMonitorManager.java deleted file mode 100644 index 0f669817f52e..000000000000 --- a/services/net/java/android/net/NetworkMonitorManager.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (C) 2019 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; - -import android.annotation.Hide; -import android.annotation.NonNull; -import android.os.Binder; -import android.os.RemoteException; -import android.util.Log; - -/** - * A convenience wrapper for INetworkMonitor. - * - * Wraps INetworkMonitor calls, making them a bit more friendly to use. Currently handles: - * - Clearing calling identity - * - Ignoring RemoteExceptions - * - Converting to stable parcelables - * - * By design, all methods on INetworkMonitor are asynchronous oneway IPCs and are thus void. All the - * wrapper methods in this class return a boolean that callers can use to determine whether - * RemoteException was thrown. - */ -@Hide -public class NetworkMonitorManager { - - @NonNull private final INetworkMonitor mNetworkMonitor; - @NonNull private final String mTag; - - public NetworkMonitorManager(@NonNull INetworkMonitor networkMonitorManager, - @NonNull String tag) { - mNetworkMonitor = networkMonitorManager; - mTag = tag; - } - - public NetworkMonitorManager(@NonNull INetworkMonitor networkMonitorManager) { - this(networkMonitorManager, NetworkMonitorManager.class.getSimpleName()); - } - - private void log(String s, Throwable e) { - Log.e(mTag, s, e); - } - - // CHECKSTYLE:OFF Generated code - - public boolean start() { - final long token = Binder.clearCallingIdentity(); - try { - mNetworkMonitor.start(); - return true; - } catch (RemoteException e) { - log("Error in start", e); - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - public boolean launchCaptivePortalApp() { - final long token = Binder.clearCallingIdentity(); - try { - mNetworkMonitor.launchCaptivePortalApp(); - return true; - } catch (RemoteException e) { - log("Error in launchCaptivePortalApp", e); - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - public boolean notifyCaptivePortalAppFinished(int response) { - final long token = Binder.clearCallingIdentity(); - try { - mNetworkMonitor.notifyCaptivePortalAppFinished(response); - return true; - } catch (RemoteException e) { - log("Error in notifyCaptivePortalAppFinished", e); - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - public boolean setAcceptPartialConnectivity() { - final long token = Binder.clearCallingIdentity(); - try { - mNetworkMonitor.setAcceptPartialConnectivity(); - return true; - } catch (RemoteException e) { - log("Error in setAcceptPartialConnectivity", e); - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - public boolean forceReevaluation(int uid) { - final long token = Binder.clearCallingIdentity(); - try { - mNetworkMonitor.forceReevaluation(uid); - return true; - } catch (RemoteException e) { - log("Error in forceReevaluation", e); - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - public boolean notifyPrivateDnsChanged(PrivateDnsConfigParcel config) { - final long token = Binder.clearCallingIdentity(); - try { - mNetworkMonitor.notifyPrivateDnsChanged(config); - return true; - } catch (RemoteException e) { - log("Error in notifyPrivateDnsChanged", e); - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - public boolean notifyDnsResponse(int returnCode) { - final long token = Binder.clearCallingIdentity(); - try { - mNetworkMonitor.notifyDnsResponse(returnCode); - return true; - } catch (RemoteException e) { - log("Error in notifyDnsResponse", e); - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - public boolean notifyNetworkConnected(LinkProperties lp, NetworkCapabilities nc) { - final long token = Binder.clearCallingIdentity(); - try { - mNetworkMonitor.notifyNetworkConnected(lp, nc); - return true; - } catch (RemoteException e) { - log("Error in notifyNetworkConnected", e); - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - public boolean notifyNetworkDisconnected() { - final long token = Binder.clearCallingIdentity(); - try { - mNetworkMonitor.notifyNetworkDisconnected(); - return true; - } catch (RemoteException e) { - log("Error in notifyNetworkDisconnected", e); - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - public boolean notifyLinkPropertiesChanged(LinkProperties lp) { - final long token = Binder.clearCallingIdentity(); - try { - mNetworkMonitor.notifyLinkPropertiesChanged(lp); - return true; - } catch (RemoteException e) { - log("Error in notifyLinkPropertiesChanged", e); - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - public boolean notifyNetworkCapabilitiesChanged(NetworkCapabilities nc) { - final long token = Binder.clearCallingIdentity(); - try { - mNetworkMonitor.notifyNetworkCapabilitiesChanged(nc); - return true; - } catch (RemoteException e) { - log("Error in notifyNetworkCapabilitiesChanged", e); - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - // CHECKSTYLE:ON Generated code -} diff --git a/services/net/java/android/net/ip/IpClientCallbacks.java b/services/net/java/android/net/ip/IpClientCallbacks.java deleted file mode 100644 index b17fcaa132a1..000000000000 --- a/services/net/java/android/net/ip/IpClientCallbacks.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2019 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.ip; - -import android.net.DhcpResultsParcelable; -import android.net.Layer2PacketParcelable; -import android.net.LinkProperties; - -import java.util.List; - -/** - * Callbacks for handling IpClient events. - * - * This is a convenience class to allow clients not to override all methods of IIpClientCallbacks, - * and avoid unparceling arguments. - * These methods are called asynchronously on a Binder thread, as IpClient lives in a different - * process. - * @hide - */ -public class IpClientCallbacks { - - /** - * Callback called upon IpClient creation. - * - * @param ipClient The Binder token to communicate with IpClient. - */ - public void onIpClientCreated(IIpClient ipClient) {} - - /** - * Callback called prior to DHCP discovery/renewal. - * - * <p>In order to receive onPreDhcpAction(), call #withPreDhcpAction() when constructing a - * ProvisioningConfiguration. - * - * <p>Implementations of onPreDhcpAction() must call IpClient#completedPreDhcpAction() to - * indicate that DHCP is clear to proceed. - */ - public void onPreDhcpAction() {} - - /** - * Callback called after DHCP discovery/renewal. - */ - public void onPostDhcpAction() {} - - /** - * Callback called when new DHCP results are available. - * - * <p>This is purely advisory and not an indication of provisioning success or failure. This is - * only here for callers that want to expose DHCPv4 results to other APIs - * (e.g., WifiInfo#setInetAddress). - * - * <p>DHCPv4 or static IPv4 configuration failure or success can be determined by whether or not - * the passed-in DhcpResults object is null. - */ - public void onNewDhcpResults(DhcpResultsParcelable dhcpResults) { - // In general callbacks would not use a parcelable directly (DhcpResultsParcelable), and - // would use a wrapper instead, because of the lack of safety of stable parcelables. But - // there are already two classes in the tree for DHCP information: DhcpInfo and DhcpResults, - // and neither of them exposes an appropriate API (they are bags of mutable fields and can't - // be changed because they are public API and @UnsupportedAppUsage, being no better than the - // stable parcelable). Adding a third class would cost more than the gain considering that - // the only client of this callback is WiFi, which will end up converting the results to - // DhcpInfo anyway. - } - - /** - * Indicates that provisioning was successful. - */ - public void onProvisioningSuccess(LinkProperties newLp) {} - - /** - * Indicates that provisioning failed. - */ - public void onProvisioningFailure(LinkProperties newLp) {} - - /** - * Invoked on LinkProperties changes. - */ - public void onLinkPropertiesChange(LinkProperties newLp) {} - - /**Called when the internal IpReachabilityMonitor (if enabled) has - * detected the loss of a critical number of required neighbors. - */ - public void onReachabilityLost(String logMsg) {} - - /** - * Called when the IpClient state machine terminates. - */ - public void onQuit() {} - - /** - * Called to indicate that a new APF program must be installed to filter incoming packets. - */ - public void installPacketFilter(byte[] filter) {} - - /** - * Called to indicate that the APF Program & data buffer must be read asynchronously from the - * wifi driver. - * - * <p>Due to Wifi HAL limitations, the current implementation only supports dumping the entire - * buffer. In response to this request, the driver returns the data buffer asynchronously - * by sending an IpClient#EVENT_READ_PACKET_FILTER_COMPLETE message. - */ - public void startReadPacketFilter() {} - - /** - * If multicast filtering cannot be accomplished with APF, this function will be called to - * actuate multicast filtering using another means. - */ - public void setFallbackMulticastFilter(boolean enabled) {} - - /** - * Enabled/disable Neighbor Discover offload functionality. This is called, for example, - * whenever 464xlat is being started or stopped. - */ - public void setNeighborDiscoveryOffload(boolean enable) {} - - /** - * Invoked on starting preconnection process. - */ - public void onPreconnectionStart(List<Layer2PacketParcelable> packets) {} -} diff --git a/services/net/java/android/net/ip/IpClientManager.java b/services/net/java/android/net/ip/IpClientManager.java deleted file mode 100644 index b45405f39f0f..000000000000 --- a/services/net/java/android/net/ip/IpClientManager.java +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Copyright (C) 2019 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.ip; - -import android.annotation.Hide; -import android.annotation.NonNull; -import android.net.NattKeepalivePacketData; -import android.net.ProxyInfo; -import android.net.TcpKeepalivePacketData; -import android.net.TcpKeepalivePacketDataParcelable; -import android.net.shared.Layer2Information; -import android.net.shared.ProvisioningConfiguration; -import android.net.util.KeepalivePacketDataUtil; -import android.os.Binder; -import android.os.RemoteException; -import android.util.Log; - -/** - * A convenience wrapper for IpClient. - * - * Wraps IIpClient calls, making them a bit more friendly to use. Currently handles: - * - Clearing calling identity - * - Ignoring RemoteExceptions - * - Converting to stable parcelables - * - * By design, all methods on IIpClient are asynchronous oneway IPCs and are thus void. All the - * wrapper methods in this class return a boolean that callers can use to determine whether - * RemoteException was thrown. - */ -@Hide -public class IpClientManager { - @NonNull private final IIpClient mIpClient; - @NonNull private final String mTag; - - public IpClientManager(@NonNull IIpClient ipClient, @NonNull String tag) { - mIpClient = ipClient; - mTag = tag; - } - - public IpClientManager(@NonNull IIpClient ipClient) { - this(ipClient, IpClientManager.class.getSimpleName()); - } - - private void log(String s, Throwable e) { - Log.e(mTag, s, e); - } - - /** - * For clients using {@link ProvisioningConfiguration.Builder#withPreDhcpAction()}, must be - * called after {@link IIpClientCallbacks#onPreDhcpAction} to indicate that DHCP is clear to - * proceed. - */ - public boolean completedPreDhcpAction() { - final long token = Binder.clearCallingIdentity(); - try { - mIpClient.completedPreDhcpAction(); - return true; - } catch (RemoteException e) { - log("Error completing PreDhcpAction", e); - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - /** - * Confirm the provisioning configuration. - */ - public boolean confirmConfiguration() { - final long token = Binder.clearCallingIdentity(); - try { - mIpClient.confirmConfiguration(); - return true; - } catch (RemoteException e) { - log("Error confirming IpClient configuration", e); - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - /** - * Indicate that packet filter read is complete. - */ - public boolean readPacketFilterComplete(byte[] data) { - final long token = Binder.clearCallingIdentity(); - try { - mIpClient.readPacketFilterComplete(data); - return true; - } catch (RemoteException e) { - log("Error notifying IpClient of packet filter read", e); - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - /** - * Shut down this IpClient instance altogether. - */ - public boolean shutdown() { - final long token = Binder.clearCallingIdentity(); - try { - mIpClient.shutdown(); - return true; - } catch (RemoteException e) { - log("Error shutting down IpClient", e); - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - /** - * Start provisioning with the provided parameters. - */ - public boolean startProvisioning(ProvisioningConfiguration prov) { - final long token = Binder.clearCallingIdentity(); - try { - mIpClient.startProvisioning(prov.toStableParcelable()); - return true; - } catch (RemoteException e) { - log("Error starting IpClient provisioning", e); - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - /** - * Stop this IpClient. - * - * <p>This does not shut down the StateMachine itself, which is handled by {@link #shutdown()}. - */ - public boolean stop() { - final long token = Binder.clearCallingIdentity(); - try { - mIpClient.stop(); - return true; - } catch (RemoteException e) { - log("Error stopping IpClient", e); - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - /** - * Set the TCP buffer sizes to use. - * - * This may be called, repeatedly, at any time before or after a call to - * #startProvisioning(). The setting is cleared upon calling #stop(). - */ - public boolean setTcpBufferSizes(String tcpBufferSizes) { - final long token = Binder.clearCallingIdentity(); - try { - mIpClient.setTcpBufferSizes(tcpBufferSizes); - return true; - } catch (RemoteException e) { - log("Error setting IpClient TCP buffer sizes", e); - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - /** - * Set the HTTP Proxy configuration to use. - * - * This may be called, repeatedly, at any time before or after a call to - * #startProvisioning(). The setting is cleared upon calling #stop(). - */ - public boolean setHttpProxy(ProxyInfo proxyInfo) { - final long token = Binder.clearCallingIdentity(); - try { - mIpClient.setHttpProxy(proxyInfo); - return true; - } catch (RemoteException e) { - log("Error setting IpClient proxy", e); - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - /** - * Enable or disable the multicast filter. Attempts to use APF to accomplish the filtering, - * if not, Callback.setFallbackMulticastFilter() is called. - */ - public boolean setMulticastFilter(boolean enabled) { - final long token = Binder.clearCallingIdentity(); - try { - mIpClient.setMulticastFilter(enabled); - return true; - } catch (RemoteException e) { - log("Error setting multicast filter", e); - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - /** - * Add a TCP keepalive packet filter before setting up keepalive offload. - */ - public boolean addKeepalivePacketFilter(int slot, TcpKeepalivePacketData pkt) { - return addKeepalivePacketFilter(slot, KeepalivePacketDataUtil.toStableParcelable(pkt)); - } - - /** - * Add a TCP keepalive packet filter before setting up keepalive offload. - * @deprecated This method is for use on pre-S platforms where TcpKeepalivePacketData is not - * system API. On newer platforms use - * addKeepalivePacketFilter(int, TcpKeepalivePacketData) instead. - */ - @Deprecated - public boolean addKeepalivePacketFilter(int slot, TcpKeepalivePacketDataParcelable pkt) { - final long token = Binder.clearCallingIdentity(); - try { - mIpClient.addKeepalivePacketFilter(slot, pkt); - return true; - } catch (RemoteException e) { - log("Error adding Keepalive Packet Filter ", e); - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - /** - * Add a NAT-T keepalive packet filter before setting up keepalive offload. - */ - public boolean addKeepalivePacketFilter(int slot, NattKeepalivePacketData pkt) { - final long token = Binder.clearCallingIdentity(); - try { - mIpClient.addNattKeepalivePacketFilter( - slot, KeepalivePacketDataUtil.toStableParcelable(pkt)); - return true; - } catch (RemoteException e) { - log("Error adding NAT-T Keepalive Packet Filter ", e); - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - /** - * Remove a keepalive packet filter after stopping keepalive offload. - */ - public boolean removeKeepalivePacketFilter(int slot) { - final long token = Binder.clearCallingIdentity(); - try { - mIpClient.removeKeepalivePacketFilter(slot); - return true; - } catch (RemoteException e) { - log("Error removing Keepalive Packet Filter ", e); - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - /** - * Set the L2 key and group hint for storing info into the memory store. - */ - public boolean setL2KeyAndGroupHint(String l2Key, String groupHint) { - final long token = Binder.clearCallingIdentity(); - try { - mIpClient.setL2KeyAndGroupHint(l2Key, groupHint); - return true; - } catch (RemoteException e) { - log("Failed setL2KeyAndGroupHint", e); - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - /** - * Notify IpClient that preconnection is complete and that the link is ready for use. - * The success parameter indicates whether the packets passed in by 'onPreconnectionStart' - * were successfully sent to the network or not. - */ - public boolean notifyPreconnectionComplete(boolean success) { - final long token = Binder.clearCallingIdentity(); - try { - mIpClient.notifyPreconnectionComplete(success); - return true; - } catch (RemoteException e) { - log("Error notifying IpClient Preconnection completed", e); - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - /** - * Update the bssid, L2 key and group hint layer2 information. - */ - public boolean updateLayer2Information(Layer2Information info) { - final long token = Binder.clearCallingIdentity(); - try { - mIpClient.updateLayer2Information(info.toStableParcelable()); - return true; - } catch (RemoteException e) { - log("Error updating layer2 information", e); - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } -} diff --git a/services/net/java/android/net/ip/IpClientUtil.java b/services/net/java/android/net/ip/IpClientUtil.java deleted file mode 100644 index 426614ec2f53..000000000000 --- a/services/net/java/android/net/ip/IpClientUtil.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (C) 2019 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.ip; - -import android.content.Context; -import android.net.DhcpResultsParcelable; -import android.net.Layer2PacketParcelable; -import android.net.LinkProperties; -import android.net.networkstack.ModuleNetworkStackClient; -import android.os.ConditionVariable; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.List; - - -/** - * Utilities and wrappers to simplify communication with IpClient, which lives in the NetworkStack - * process. - * - * @hide - */ -public class IpClientUtil { - // TODO: remove with its callers - public static final String DUMP_ARG = "ipclient"; - - /** - * Subclass of {@link IpClientCallbacks} allowing clients to block until provisioning is - * complete with {@link WaitForProvisioningCallbacks#waitForProvisioning()}. - */ - public static class WaitForProvisioningCallbacks extends IpClientCallbacks { - private final ConditionVariable mCV = new ConditionVariable(); - private LinkProperties mCallbackLinkProperties; - - /** - * Block until either {@link #onProvisioningSuccess(LinkProperties)} or - * {@link #onProvisioningFailure(LinkProperties)} is called. - */ - public LinkProperties waitForProvisioning() { - mCV.block(); - return mCallbackLinkProperties; - } - - @Override - public void onProvisioningSuccess(LinkProperties newLp) { - mCallbackLinkProperties = newLp; - mCV.open(); - } - - @Override - public void onProvisioningFailure(LinkProperties newLp) { - mCallbackLinkProperties = null; - mCV.open(); - } - } - - /** - * Create a new IpClient. - * - * <p>This is a convenience method to allow clients to use {@link IpClientCallbacks} instead of - * {@link IIpClientCallbacks}. - * @see {@link ModuleNetworkStackClient#makeIpClient(String, IIpClientCallbacks)} - */ - public static void makeIpClient(Context context, String ifName, IpClientCallbacks callback) { - ModuleNetworkStackClient.getInstance(context) - .makeIpClient(ifName, new IpClientCallbacksProxy(callback)); - } - - /** - * Wrapper to relay calls from {@link IIpClientCallbacks} to {@link IpClientCallbacks}. - */ - private static class IpClientCallbacksProxy extends IIpClientCallbacks.Stub { - protected final IpClientCallbacks mCb; - - /** - * Create a new IpClientCallbacksProxy. - */ - public IpClientCallbacksProxy(IpClientCallbacks cb) { - mCb = cb; - } - - @Override - public void onIpClientCreated(IIpClient ipClient) { - mCb.onIpClientCreated(ipClient); - } - - @Override - public void onPreDhcpAction() { - mCb.onPreDhcpAction(); - } - - @Override - public void onPostDhcpAction() { - mCb.onPostDhcpAction(); - } - - // This is purely advisory and not an indication of provisioning - // success or failure. This is only here for callers that want to - // expose DHCPv4 results to other APIs (e.g., WifiInfo#setInetAddress). - // DHCPv4 or static IPv4 configuration failure or success can be - // determined by whether or not the passed-in DhcpResults object is - // null or not. - @Override - public void onNewDhcpResults(DhcpResultsParcelable dhcpResults) { - mCb.onNewDhcpResults(dhcpResults); - } - - @Override - public void onProvisioningSuccess(LinkProperties newLp) { - mCb.onProvisioningSuccess(newLp); - } - @Override - public void onProvisioningFailure(LinkProperties newLp) { - mCb.onProvisioningFailure(newLp); - } - - // Invoked on LinkProperties changes. - @Override - public void onLinkPropertiesChange(LinkProperties newLp) { - mCb.onLinkPropertiesChange(newLp); - } - - // Called when the internal IpReachabilityMonitor (if enabled) has - // detected the loss of a critical number of required neighbors. - @Override - public void onReachabilityLost(String logMsg) { - mCb.onReachabilityLost(logMsg); - } - - // Called when the IpClient state machine terminates. - @Override - public void onQuit() { - mCb.onQuit(); - } - - // Install an APF program to filter incoming packets. - @Override - public void installPacketFilter(byte[] filter) { - mCb.installPacketFilter(filter); - } - - // Asynchronously read back the APF program & data buffer from the wifi driver. - // Due to Wifi HAL limitations, the current implementation only supports dumping the entire - // buffer. In response to this request, the driver returns the data buffer asynchronously - // by sending an IpClient#EVENT_READ_PACKET_FILTER_COMPLETE message. - @Override - public void startReadPacketFilter() { - mCb.startReadPacketFilter(); - } - - // If multicast filtering cannot be accomplished with APF, this function will be called to - // actuate multicast filtering using another means. - @Override - public void setFallbackMulticastFilter(boolean enabled) { - mCb.setFallbackMulticastFilter(enabled); - } - - // Enabled/disable Neighbor Discover offload functionality. This is - // called, for example, whenever 464xlat is being started or stopped. - @Override - public void setNeighborDiscoveryOffload(boolean enable) { - mCb.setNeighborDiscoveryOffload(enable); - } - - // Invoked on starting preconnection process. - @Override - public void onPreconnectionStart(List<Layer2PacketParcelable> packets) { - mCb.onPreconnectionStart(packets); - } - - @Override - public int getInterfaceVersion() { - return this.VERSION; - } - - @Override - public String getInterfaceHash() { - return this.HASH; - } - } - - /** - * Dump logs for the specified IpClient. - * TODO: remove callers and delete - */ - public static void dumpIpClient( - IIpClient connector, FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println("IpClient logs have moved to dumpsys network_stack"); - } -} diff --git a/services/net/java/android/net/util/DhcpResultsCompatUtil.java b/services/net/java/android/net/util/DhcpResultsCompatUtil.java deleted file mode 100644 index fce0834c116e..000000000000 --- a/services/net/java/android/net/util/DhcpResultsCompatUtil.java +++ /dev/null @@ -1,54 +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.net.util; - -import static android.net.shared.IpConfigurationParcelableUtil.unparcelAddress; - -import android.annotation.Nullable; -import android.net.DhcpResults; -import android.net.DhcpResultsParcelable; - -import java.net.Inet4Address; - -/** - * Compatibility utility for code that still uses DhcpResults. - * - * TODO: remove this class when all usages of DhcpResults (including Wifi in AOSP) are removed. - */ -public class DhcpResultsCompatUtil { - - /** - * Convert a DhcpResultsParcelable to DhcpResults. - * - * contract { - * returns(null) implies p == null - * returnsNotNull() implies p != null - * } - */ - @Nullable - public static DhcpResults fromStableParcelable(@Nullable DhcpResultsParcelable p) { - if (p == null) return null; - final DhcpResults results = new DhcpResults(p.baseConfiguration); - results.leaseDuration = p.leaseDuration; - results.mtu = p.mtu; - results.serverAddress = (Inet4Address) unparcelAddress(p.serverAddress); - results.vendorInfo = p.vendorInfo; - results.serverHostName = p.serverHostName; - results.captivePortalApiUrl = p.captivePortalApiUrl; - return results; - } -} diff --git a/services/net/java/android/net/util/KeepalivePacketDataUtil.java b/services/net/java/android/net/util/KeepalivePacketDataUtil.java deleted file mode 100644 index 566698576026..000000000000 --- a/services/net/java/android/net/util/KeepalivePacketDataUtil.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (C) 2019 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.util; - -import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.net.InvalidPacketException; -import android.net.KeepalivePacketData; -import android.net.NattKeepalivePacketData; -import android.net.NattKeepalivePacketDataParcelable; -import android.net.TcpKeepalivePacketData; -import android.net.TcpKeepalivePacketDataParcelable; -import android.os.Build; -import android.system.OsConstants; -import android.util.Log; - -import com.android.net.module.util.IpUtils; - -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -/** - * Utility class to convert to/from keepalive data parcelables. - * - * TODO: move to networkstack-client library when it is moved to frameworks/libs/net. - * This class cannot go into other shared libraries as it depends on NetworkStack AIDLs. - * @hide - */ -public final class KeepalivePacketDataUtil { - private static final int IPV4_HEADER_LENGTH = 20; - private static final int IPV6_HEADER_LENGTH = 40; - private static final int TCP_HEADER_LENGTH = 20; - - private static final String TAG = KeepalivePacketDataUtil.class.getSimpleName(); - - /** - * Convert a NattKeepalivePacketData to a NattKeepalivePacketDataParcelable. - */ - @NonNull - public static NattKeepalivePacketDataParcelable toStableParcelable( - @NonNull NattKeepalivePacketData pkt) { - final NattKeepalivePacketDataParcelable parcel = new NattKeepalivePacketDataParcelable(); - final InetAddress srcAddress = pkt.getSrcAddress(); - final InetAddress dstAddress = pkt.getDstAddress(); - parcel.srcAddress = srcAddress.getAddress(); - parcel.srcPort = pkt.getSrcPort(); - parcel.dstAddress = dstAddress.getAddress(); - parcel.dstPort = pkt.getDstPort(); - return parcel; - } - - /** - * Convert a TcpKeepalivePacketData to a TcpKeepalivePacketDataParcelable. - */ - @NonNull - public static TcpKeepalivePacketDataParcelable toStableParcelable( - @NonNull TcpKeepalivePacketData pkt) { - final TcpKeepalivePacketDataParcelable parcel = new TcpKeepalivePacketDataParcelable(); - final InetAddress srcAddress = pkt.getSrcAddress(); - final InetAddress dstAddress = pkt.getDstAddress(); - parcel.srcAddress = srcAddress.getAddress(); - parcel.srcPort = pkt.getSrcPort(); - parcel.dstAddress = dstAddress.getAddress(); - parcel.dstPort = pkt.getDstPort(); - parcel.seq = pkt.getTcpSeq(); - parcel.ack = pkt.getTcpAck(); - parcel.rcvWnd = pkt.getTcpWindow(); - parcel.rcvWndScale = pkt.getTcpWindowScale(); - parcel.tos = pkt.getIpTos(); - parcel.ttl = pkt.getIpTtl(); - return parcel; - } - - /** - * Factory method to create tcp keepalive packet structure. - * @hide - */ - public static TcpKeepalivePacketData fromStableParcelable( - TcpKeepalivePacketDataParcelable tcpDetails) throws InvalidPacketException { - final byte[] packet; - try { - if ((tcpDetails.srcAddress != null) && (tcpDetails.dstAddress != null) - && (tcpDetails.srcAddress.length == 4 /* V4 IP length */) - && (tcpDetails.dstAddress.length == 4 /* V4 IP length */)) { - packet = buildV4Packet(tcpDetails); - } else { - // TODO: support ipv6 - throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS); - } - return new TcpKeepalivePacketData( - InetAddress.getByAddress(tcpDetails.srcAddress), - tcpDetails.srcPort, - InetAddress.getByAddress(tcpDetails.dstAddress), - tcpDetails.dstPort, - packet, - tcpDetails.seq, tcpDetails.ack, tcpDetails.rcvWnd, tcpDetails.rcvWndScale, - tcpDetails.tos, tcpDetails.ttl); - } catch (UnknownHostException e) { - throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS); - } - - } - - /** - * Build ipv4 tcp keepalive packet, not including the link-layer header. - */ - // TODO : if this code is ever moved to the network stack, factorize constants with the ones - // over there. - private static byte[] buildV4Packet(TcpKeepalivePacketDataParcelable tcpDetails) { - final int length = IPV4_HEADER_LENGTH + TCP_HEADER_LENGTH; - ByteBuffer buf = ByteBuffer.allocate(length); - buf.order(ByteOrder.BIG_ENDIAN); - buf.put((byte) 0x45); // IP version and IHL - buf.put((byte) tcpDetails.tos); // TOS - buf.putShort((short) length); - buf.putInt(0x00004000); // ID, flags=DF, offset - buf.put((byte) tcpDetails.ttl); // TTL - buf.put((byte) OsConstants.IPPROTO_TCP); - final int ipChecksumOffset = buf.position(); - buf.putShort((short) 0); // IP checksum - buf.put(tcpDetails.srcAddress); - buf.put(tcpDetails.dstAddress); - buf.putShort((short) tcpDetails.srcPort); - buf.putShort((short) tcpDetails.dstPort); - buf.putInt(tcpDetails.seq); // Sequence Number - buf.putInt(tcpDetails.ack); // ACK - buf.putShort((short) 0x5010); // TCP length=5, flags=ACK - buf.putShort((short) (tcpDetails.rcvWnd >> tcpDetails.rcvWndScale)); // Window size - final int tcpChecksumOffset = buf.position(); - buf.putShort((short) 0); // TCP checksum - // URG is not set therefore the urgent pointer is zero. - buf.putShort((short) 0); // Urgent pointer - - buf.putShort(ipChecksumOffset, com.android.net.module.util.IpUtils.ipChecksum(buf, 0)); - buf.putShort(tcpChecksumOffset, IpUtils.tcpChecksum( - buf, 0, IPV4_HEADER_LENGTH, TCP_HEADER_LENGTH)); - - return buf.array(); - } - - // TODO: add buildV6Packet. - - /** - * Get a {@link TcpKeepalivePacketDataParcelable} from {@link KeepalivePacketData}, if the - * generic class actually contains TCP keepalive data. - * - * @deprecated This method is used on R platforms where android.net.TcpKeepalivePacketData was - * not yet system API. Newer platforms should use android.net.TcpKeepalivePacketData directly. - * - * @param data A {@link KeepalivePacketData} that may contain TCP keepalive data. - * @return A parcelable containing TCP keepalive data, or null if the input data does not - * contain TCP keepalive data. - */ - @Deprecated - @SuppressWarnings("AndroidFrameworkCompatChange") // API version check used to Log.wtf - @Nullable - public static TcpKeepalivePacketDataParcelable parseTcpKeepalivePacketData( - @Nullable KeepalivePacketData data) { - if (data == null) return null; - - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) { - Log.wtf(TAG, "parseTcpKeepalivePacketData should not be used after R, use " - + "TcpKeepalivePacketData instead."); - } - - // Reconstruct TcpKeepalivePacketData from the packet contained in KeepalivePacketData - final ByteBuffer buffer = ByteBuffer.wrap(data.getPacket()); - buffer.order(ByteOrder.BIG_ENDIAN); - - // Most of the fields are accessible from the KeepalivePacketData superclass: instead of - // using Struct to parse everything, just extract the extra fields necessary for - // TcpKeepalivePacketData. - final int tcpSeq; - final int tcpAck; - final int wndSize; - final int ipTos; - final int ttl; - try { - // This only support IPv4, because TcpKeepalivePacketData only supports IPv4 for R and - // below, and this method should not be used on newer platforms. - tcpSeq = buffer.getInt(IPV4_HEADER_LENGTH + 4); - tcpAck = buffer.getInt(IPV4_HEADER_LENGTH + 8); - wndSize = buffer.getShort(IPV4_HEADER_LENGTH + 14); - ipTos = buffer.get(1); - ttl = buffer.get(8); - } catch (IndexOutOfBoundsException e) { - return null; - } - - final TcpKeepalivePacketDataParcelable p = new TcpKeepalivePacketDataParcelable(); - p.srcAddress = data.getSrcAddress().getAddress(); - p.srcPort = data.getSrcPort(); - p.dstAddress = data.getDstAddress().getAddress(); - p.dstPort = data.getDstPort(); - p.seq = tcpSeq; - p.ack = tcpAck; - // TcpKeepalivePacketData could actually use non-zero wndScale, but this does not affect - // actual functionality as generated packets will be the same (no wndScale option added) - p.rcvWnd = wndSize; - p.rcvWndScale = 0; - p.tos = ipTos; - p.ttl = ttl; - return p; - } -} diff --git a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java index 5a42c4bc7f3a..53483f6d70bc 100644 --- a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java @@ -31,6 +31,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.junit.Assume.assumeThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; @@ -57,6 +58,9 @@ import android.service.wallpaper.WallpaperService; import android.testing.TestableContext; import android.util.Log; import android.util.SparseArray; +import android.util.TypedXmlPullParser; +import android.util.TypedXmlSerializer; +import android.util.Xml; import android.view.Display; import androidx.test.filters.FlakyTest; @@ -82,9 +86,12 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.quality.Strictness; +import org.xmlpull.v1.XmlPullParserException; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; +import java.nio.charset.StandardCharsets; /** * Tests for the {@link WallpaperManagerService} class. @@ -355,6 +362,31 @@ public class WallpaperManagerServiceTests { verifyDisplayData(); } + @Test + public void testXmlSerializationRoundtrip() { + WallpaperData systemWallpaperData = mService.getCurrentWallpaperData(FLAG_SYSTEM, 0); + try { + TypedXmlSerializer serializer = Xml.newBinarySerializer(); + serializer.setOutput(new ByteArrayOutputStream(), StandardCharsets.UTF_8.name()); + serializer.startDocument(StandardCharsets.UTF_8.name(), true); + mService.writeWallpaperAttributes(serializer, "wp", systemWallpaperData); + } catch (IOException e) { + fail("exception occurred while writing system wallpaper attributes"); + } + + WallpaperData shouldMatchSystem = new WallpaperData(systemWallpaperData.userId, + systemWallpaperData.wallpaperFile.getParentFile(), + systemWallpaperData.wallpaperFile.getAbsolutePath(), + systemWallpaperData.cropFile.getAbsolutePath()); + try { + TypedXmlPullParser parser = Xml.newBinaryPullParser(); + mService.parseWallpaperAttributes(parser, shouldMatchSystem, true); + } catch (XmlPullParserException e) { + fail("exception occurred while parsing wallpaper"); + } + assertEquals(systemWallpaperData.primaryColors, shouldMatchSystem.primaryColors); + } + // Verify that after continue switch user from userId 0 to lastUserId, the wallpaper data for // non-current user must not bind to wallpaper service. private void verifyNoConnectionBeforeLastUser(int lastUserId) { diff --git a/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java b/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java index aadaba4d2fce..f4f907355aee 100644 --- a/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java +++ b/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java @@ -127,8 +127,8 @@ public class AppSearchImplPlatformTest { "database", Collections.singletonList(new AppSearchSchema.Builder("schema1").build()), mVisibilityStore, - /*schemasNotPlatformSurfaceable=*/ Collections.singletonList("schema1"), - /*schemasPackageAccessible=*/ ImmutableMap.of( + /*schemasNotDisplayedBySystem=*/ Collections.singletonList("schema1"), + /*schemasVisibleToPackages=*/ ImmutableMap.of( "schema1", ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))), /*forceOverride=*/ false, @@ -159,8 +159,8 @@ public class AppSearchImplPlatformTest { new AppSearchSchema.Builder("schema1").build(), new AppSearchSchema.Builder("schema2").build()), mVisibilityStore, - /*schemasNotPlatformSurfaceable=*/ Collections.singletonList("schema1"), - /*schemasPackageAccessible=*/ ImmutableMap.of( + /*schemasNotDisplayedBySystem=*/ Collections.singletonList("schema1"), + /*schemasVisibleToPackages=*/ ImmutableMap.of( "schema1", ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))), /*forceOverride=*/ false, @@ -233,8 +233,8 @@ public class AppSearchImplPlatformTest { "database", Collections.singletonList(new AppSearchSchema.Builder("schema1").build()), mVisibilityStore, - /*schemasNotPlatformSurfaceable=*/ Collections.singletonList("schema1"), - /*schemasPackageAccessible=*/ ImmutableMap.of( + /*schemasNotDisplayedBySystem=*/ Collections.singletonList("schema1"), + /*schemasVisibleToPackages=*/ ImmutableMap.of( "schema1", ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))), /*forceOverride=*/ false, @@ -263,8 +263,8 @@ public class AppSearchImplPlatformTest { "database", /*schemas=*/ Collections.emptyList(), mVisibilityStore, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ true, /*schemaVersion=*/ 0); @@ -292,8 +292,8 @@ public class AppSearchImplPlatformTest { "database", Collections.singletonList(new AppSearchSchema.Builder("schema1").build()), mVisibilityStore, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*schemaVersion=*/ 0); @@ -327,8 +327,8 @@ public class AppSearchImplPlatformTest { "database", Collections.singletonList(new AppSearchSchema.Builder("Schema").build()), mVisibilityStore, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*schemaVersion=*/ 0); @@ -355,8 +355,8 @@ public class AppSearchImplPlatformTest { "database", Collections.singletonList(new AppSearchSchema.Builder("Schema").build()), mVisibilityStore, - /*schemasNotPlatformSurfaceable=*/ Collections.singletonList("Schema"), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.singletonList("Schema"), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*schemaVersion=*/ 0); @@ -370,7 +370,7 @@ public class AppSearchImplPlatformTest { } @Test - public void testSetSchema_defaultNotPackageAccessible() throws Exception { + public void testSetSchema_defaultNotVisibleToPackages() throws Exception { String packageName = "com.package"; // Make sure package doesn't global query privileges @@ -384,8 +384,8 @@ public class AppSearchImplPlatformTest { "database", Collections.singletonList(new AppSearchSchema.Builder("Schema").build()), mVisibilityStore, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*schemaVersion=*/ 0); assertThat(mVisibilityStore @@ -399,7 +399,7 @@ public class AppSearchImplPlatformTest { } @Test - public void testSetSchema_packageAccessible() throws Exception { + public void testSetSchema_visibleToPackages() throws Exception { // Values for a "foo" client String packageNameFoo = "packageFoo"; byte[] sha256CertFoo = new byte[] {10}; @@ -423,8 +423,8 @@ public class AppSearchImplPlatformTest { "database", Collections.singletonList(new AppSearchSchema.Builder("Schema").build()), mVisibilityStore, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ ImmutableMap.of( + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ ImmutableMap.of( "Schema", ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))), /*forceOverride=*/ false, diff --git a/services/tests/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java b/services/tests/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java index b67ebe423eab..183cb8603c33 100644 --- a/services/tests/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java +++ b/services/tests/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java @@ -132,7 +132,7 @@ public class VisibilityStoreTest { } @Test - public void testSetVisibility_platformSurfaceable() throws Exception { + public void testSetVisibility_displayedBySystem() throws Exception { // Make sure we have global query privileges PackageManager mockPackageManager = getMockPackageManager(mContext.getUser()); when(mockPackageManager @@ -143,9 +143,9 @@ public class VisibilityStoreTest { mVisibilityStore.setVisibility( "package", "database", - /*schemasNotPlatformSurfaceable=*/ ImmutableSet.of( + /*schemasNotDisplayedBySystem=*/ ImmutableSet.of( "prefix/schema1", "prefix/schema2"), - /*schemasPackageAccessible=*/ Collections.emptyMap()); + /*schemasVisibleToPackages=*/ Collections.emptyMap()); assertThat( mVisibilityStore.isSchemaSearchableByCaller( "package", @@ -168,9 +168,9 @@ public class VisibilityStoreTest { mVisibilityStore.setVisibility( "package", "database", - /*schemasNotPlatformSurfaceable=*/ ImmutableSet.of( + /*schemasNotDisplayedBySystem=*/ ImmutableSet.of( "prefix/schema1", "prefix/schema3"), - /*schemasPackageAccessible=*/ Collections.emptyMap()); + /*schemasVisibleToPackages=*/ Collections.emptyMap()); assertThat( mVisibilityStore.isSchemaSearchableByCaller( "package", @@ -200,8 +200,8 @@ public class VisibilityStoreTest { mVisibilityStore.setVisibility( "package", "database", - /*schemasNotPlatformSurfaceable=*/ Collections.emptySet(), - /*schemasPackageAccessible=*/ Collections.emptyMap()); + /*schemasNotDisplayedBySystem=*/ Collections.emptySet(), + /*schemasVisibleToPackages=*/ Collections.emptyMap()); assertThat( mVisibilityStore.isSchemaSearchableByCaller( "package", @@ -229,7 +229,7 @@ public class VisibilityStoreTest { } @Test - public void testSetVisibility_packageAccessible() throws Exception { + public void testSetVisibility_visibleToPackages() throws Exception { // Values for a "foo" client String packageNameFoo = "packageFoo"; byte[] sha256CertFoo = new byte[] {10}; @@ -272,8 +272,8 @@ public class VisibilityStoreTest { mVisibilityStore.setVisibility( "package", "database", - /*schemasNotPlatformSurfaceable=*/ Collections.emptySet(), - /*schemasPackageAccessible=*/ ImmutableMap.of( + /*schemasNotDisplayedBySystem=*/ Collections.emptySet(), + /*schemasVisibleToPackages=*/ ImmutableMap.of( "prefix/schemaFoo", ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo)), "prefix/schemaBar", @@ -339,8 +339,8 @@ public class VisibilityStoreTest { mVisibilityStore.setVisibility( "package", "database", - /*schemasNotPlatformSurfaceable=*/ Collections.emptySet(), - /*schemasPackageAccessible=*/ ImmutableMap.of( + /*schemasNotDisplayedBySystem=*/ Collections.emptySet(), + /*schemasVisibleToPackages=*/ ImmutableMap.of( "prefix/schemaFoo", ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo)))); @@ -392,8 +392,8 @@ public class VisibilityStoreTest { mVisibilityStore.setVisibility( "package", "database", - /*schemasNotPlatformSurfaceable=*/ Collections.emptySet(), - /*schemasPackageAccessible=*/ ImmutableMap.of( + /*schemasNotDisplayedBySystem=*/ Collections.emptySet(), + /*schemasVisibleToPackages=*/ ImmutableMap.of( "prefix/schemaFoo", ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo)))); @@ -425,8 +425,8 @@ public class VisibilityStoreTest { mVisibilityStore.setVisibility( /*packageName=*/ "", /*databaseName=*/ "", - /*schemasNotPlatformSurfaceable=*/ Collections.emptySet(), - /*schemasPackageAccessible=*/ ImmutableMap.of( + /*schemasNotDisplayedBySystem=*/ Collections.emptySet(), + /*schemasVisibleToPackages=*/ ImmutableMap.of( "schema", ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo)))); diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java index f032402f47a0..02bb168dbde6 100644 --- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java +++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java @@ -22,7 +22,7 @@ import static com.android.server.appsearch.external.localstorage.util.PrefixUtil import static com.google.common.truth.Truth.assertThat; -import static org.testng.Assert.expectThrows; +import static org.junit.Assert.assertThrows; import android.app.appsearch.AppSearchResult; import android.app.appsearch.AppSearchSchema; @@ -34,6 +34,7 @@ import android.app.appsearch.SetSchemaResponse; import android.app.appsearch.StorageInfo; import android.app.appsearch.exceptions.AppSearchException; import android.content.Context; +import android.os.Process; import android.util.ArrayMap; import android.util.ArraySet; @@ -55,7 +56,6 @@ import com.android.server.appsearch.proto.SearchSpecProto; import com.android.server.appsearch.proto.StatusProto; import com.android.server.appsearch.proto.StringIndexingConfig; import com.android.server.appsearch.proto.TermMatchType; -import com.android.server.appsearch.visibilitystore.VisibilityStore; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -391,7 +391,7 @@ public class AppSearchImplTest { DocumentProto.Builder actualDocument = documentProto.toBuilder(); AppSearchException e = - expectThrows( + assertThrows( AppSearchException.class, () -> removePrefixesFromDocument(actualDocument)); assertThat(e).hasMessageThat().contains("Found unexpected multiple prefix names"); } @@ -416,7 +416,7 @@ public class AppSearchImplTest { DocumentProto.Builder actualDocument = documentProto.toBuilder(); AppSearchException e = - expectThrows( + assertThrows( AppSearchException.class, () -> removePrefixesFromDocument(actualDocument)); assertThat(e).hasMessageThat().contains("Found unexpected multiple prefix names"); } @@ -431,8 +431,8 @@ public class AppSearchImplTest { "database", schemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); @@ -480,8 +480,8 @@ public class AppSearchImplTest { "database1", schemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); @@ -499,7 +499,7 @@ public class AppSearchImplTest { new SearchSpec.Builder().addFilterSchemas("Type1").build(), context.getPackageName(), /*visibilityStore=*/ null, - VisibilityStore.NO_OP_UID, + Process.INVALID_UID, /*callerHasSystemAccess=*/ false, /*logger=*/ null); assertThat(results.getResults()).hasSize(1); @@ -513,7 +513,7 @@ public class AppSearchImplTest { .setSchema(context.getPackageName() + "$database1/Type1") .build(); AppSearchException e = - expectThrows( + assertThrows( AppSearchException.class, () -> PrefixUtil.getPrefix(invalidDoc.getNamespace())); assertThat(e) @@ -538,10 +538,8 @@ public class AppSearchImplTest { assertThat(initStats.hasDeSync()).isFalse(); assertThat(initStats.getDocumentStoreRecoveryCause()) .isEqualTo(InitializeStats.RECOVERY_CAUSE_NONE); - // TODO(b/187879464): There should not be a recovery here, but icing lib reports one if the - // doc had no tokens. Once the mentioned bug is fixed, uncomment this. - // assertThat(initStats.getIndexRestorationCause()) - // .isEqualTo(InitializeStats.RECOVERY_CAUSE_NONE); + assertThat(initStats.getIndexRestorationCause()) + .isEqualTo(InitializeStats.RECOVERY_CAUSE_NONE); assertThat(initStats.getSchemaStoreRecoveryCause()) .isEqualTo(InitializeStats.RECOVERY_CAUSE_NONE); assertThat(initStats.getDocumentStoreDataStatus()) @@ -558,7 +556,7 @@ public class AppSearchImplTest { new SearchSpec.Builder().addFilterSchemas("Type1").build(), context.getPackageName(), /*visibilityStore=*/ null, - VisibilityStore.NO_OP_UID, + Process.INVALID_UID, /*callerHasSystemAccess=*/ false, /*logger=*/ null); assertThat(results.getResults()).isEmpty(); @@ -569,8 +567,8 @@ public class AppSearchImplTest { "database1", Collections.singletonList(new AppSearchSchema.Builder("Type1").build()), /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); @@ -585,7 +583,7 @@ public class AppSearchImplTest { new SearchSpec.Builder().addFilterSchemas("Type1").build(), context.getPackageName(), /*visibilityStore=*/ null, - VisibilityStore.NO_OP_UID, + Process.INVALID_UID, /*callerHasSystemAccess=*/ false, /*logger=*/ null); assertThat(results.getResults()).hasSize(1); @@ -604,8 +602,8 @@ public class AppSearchImplTest { "database", schemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); @@ -638,8 +636,8 @@ public class AppSearchImplTest { "database1", schemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); mAppSearchImpl.setSchema( @@ -647,8 +645,8 @@ public class AppSearchImplTest { "database2", schemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); @@ -692,8 +690,8 @@ public class AppSearchImplTest { "database", schemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); @@ -734,8 +732,8 @@ public class AppSearchImplTest { "database1", schema1, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); @@ -747,8 +745,8 @@ public class AppSearchImplTest { "database2", schema2, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); @@ -790,8 +788,8 @@ public class AppSearchImplTest { "database1", schema1, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); @@ -803,8 +801,8 @@ public class AppSearchImplTest { "database2", schema2, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); @@ -851,7 +849,7 @@ public class AppSearchImplTest { searchSpec, /*callerPackageName=*/ "", /*visibilityStore=*/ null, - VisibilityStore.NO_OP_UID, + Process.INVALID_UID, /*callerHasSystemAccess=*/ false, /*logger=*/ null); assertThat(searchResultPage.getResults()).isEmpty(); @@ -893,8 +891,8 @@ public class AppSearchImplTest { "database1", schemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); @@ -938,8 +936,8 @@ public class AppSearchImplTest { "database1", oldSchemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); @@ -954,8 +952,8 @@ public class AppSearchImplTest { "database1", newSchemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ true, /*version=*/ 0); assertThat(setSchemaResponse.getDeletedTypes()).containsExactly("Text"); @@ -977,8 +975,8 @@ public class AppSearchImplTest { "database1", schemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); @@ -1010,8 +1008,8 @@ public class AppSearchImplTest { "database1", finalSchemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); @@ -1024,8 +1022,8 @@ public class AppSearchImplTest { "database1", finalSchemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ true, /*version=*/ 0); @@ -1062,8 +1060,8 @@ public class AppSearchImplTest { "database1", schemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); mAppSearchImpl.setSchema( @@ -1071,8 +1069,8 @@ public class AppSearchImplTest { "database2", schemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); @@ -1111,8 +1109,8 @@ public class AppSearchImplTest { "database1", schemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ true, /*version=*/ 0); @@ -1156,8 +1154,8 @@ public class AppSearchImplTest { "database", schema, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); @@ -1218,8 +1216,8 @@ public class AppSearchImplTest { "database", schema, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); mAppSearchImpl.setSchema( @@ -1227,8 +1225,8 @@ public class AppSearchImplTest { "database", schema, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); @@ -1273,8 +1271,8 @@ public class AppSearchImplTest { "database1", Collections.singletonList(new AppSearchSchema.Builder("schema").build()), /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); assertThat(mAppSearchImpl.getPackageToDatabases()) @@ -1287,8 +1285,8 @@ public class AppSearchImplTest { "database2", Collections.singletonList(new AppSearchSchema.Builder("schema").build()), /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); assertThat(mAppSearchImpl.getPackageToDatabases()) @@ -1301,8 +1299,8 @@ public class AppSearchImplTest { "database1", Collections.singletonList(new AppSearchSchema.Builder("schema").build()), /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); assertThat(mAppSearchImpl.getPackageToDatabases()) @@ -1360,8 +1358,8 @@ public class AppSearchImplTest { "database", schemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); @@ -1511,8 +1509,8 @@ public class AppSearchImplTest { "database", schemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); @@ -1534,8 +1532,8 @@ public class AppSearchImplTest { "database", schemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); @@ -1550,8 +1548,8 @@ public class AppSearchImplTest { "database", schemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); @@ -1599,8 +1597,8 @@ public class AppSearchImplTest { "database", schemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); @@ -1622,8 +1620,8 @@ public class AppSearchImplTest { "database1", schemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); @@ -1644,8 +1642,8 @@ public class AppSearchImplTest { "database1", schemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); mAppSearchImpl.setSchema( @@ -1653,8 +1651,8 @@ public class AppSearchImplTest { "database2", schemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); @@ -1700,15 +1698,15 @@ public class AppSearchImplTest { "database", schemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); appSearchImpl.close(); // Check all our public APIs - expectThrows( + assertThrows( IllegalStateException.class, () -> appSearchImpl.setSchema( @@ -1716,15 +1714,15 @@ public class AppSearchImplTest { "database", schemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0)); - expectThrows( + assertThrows( IllegalStateException.class, () -> appSearchImpl.getSchema("package", "database")); - expectThrows( + assertThrows( IllegalStateException.class, () -> appSearchImpl.putDocument( @@ -1733,13 +1731,13 @@ public class AppSearchImplTest { new GenericDocument.Builder<>("namespace", "id", "type").build(), /*logger=*/ null)); - expectThrows( + assertThrows( IllegalStateException.class, () -> appSearchImpl.getDocument( "package", "database", "namespace", "id", Collections.emptyMap())); - expectThrows( + assertThrows( IllegalStateException.class, () -> appSearchImpl.query( @@ -1749,7 +1747,7 @@ public class AppSearchImplTest { new SearchSpec.Builder().build(), /*logger=*/ null)); - expectThrows( + assertThrows( IllegalStateException.class, () -> appSearchImpl.globalQuery( @@ -1757,19 +1755,19 @@ public class AppSearchImplTest { new SearchSpec.Builder().build(), "package", /*visibilityStore=*/ null, - VisibilityStore.NO_OP_UID, + Process.INVALID_UID, /*callerHasSystemAccess=*/ false, /*logger=*/ null)); - expectThrows( + assertThrows( IllegalStateException.class, () -> appSearchImpl.getNextPage(/*nextPageToken=*/ 1L)); - expectThrows( + assertThrows( IllegalStateException.class, () -> appSearchImpl.invalidateNextPageToken(/*nextPageToken=*/ 1L)); - expectThrows( + assertThrows( IllegalStateException.class, () -> appSearchImpl.reportUsage( @@ -1780,7 +1778,7 @@ public class AppSearchImplTest { /*usageTimestampMillis=*/ 1000L, /*systemUsage=*/ false)); - expectThrows( + assertThrows( IllegalStateException.class, () -> appSearchImpl.remove( @@ -1790,7 +1788,7 @@ public class AppSearchImplTest { "id", /*removeStatsBuilder=*/ null)); - expectThrows( + assertThrows( IllegalStateException.class, () -> appSearchImpl.removeByQuery( @@ -1800,15 +1798,15 @@ public class AppSearchImplTest { new SearchSpec.Builder().build(), /*removeStatsBuilder=*/ null)); - expectThrows( + assertThrows( IllegalStateException.class, () -> appSearchImpl.getStorageInfoForPackage("package")); - expectThrows( + assertThrows( IllegalStateException.class, () -> appSearchImpl.getStorageInfoForDatabase("package", "database")); - expectThrows( + assertThrows( IllegalStateException.class, () -> appSearchImpl.persistToDisk(PersistType.Code.FULL)); } @@ -1827,8 +1825,8 @@ public class AppSearchImplTest { "database", schemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); @@ -1866,8 +1864,8 @@ public class AppSearchImplTest { "database", schemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); @@ -1892,7 +1890,7 @@ public class AppSearchImplTest { // Delete the first document appSearchImpl.remove("package", "database", "namespace1", "id1", /*statsBuilder=*/ null); appSearchImpl.persistToDisk(PersistType.Code.LITE); - expectThrows( + assertThrows( AppSearchException.class, () -> appSearchImpl.getDocument( @@ -1909,7 +1907,7 @@ public class AppSearchImplTest { // Only the second document should be retrievable from another instance. AppSearchImpl appSearchImpl2 = AppSearchImpl.create(appsearchDir, /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE); - expectThrows( + assertThrows( AppSearchException.class, () -> appSearchImpl2.getDocument( @@ -1938,8 +1936,8 @@ public class AppSearchImplTest { "database", schemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); @@ -1972,7 +1970,7 @@ public class AppSearchImplTest { .build(), /*statsBuilder=*/ null); appSearchImpl.persistToDisk(PersistType.Code.LITE); - expectThrows( + assertThrows( AppSearchException.class, () -> appSearchImpl.getDocument( @@ -1989,7 +1987,7 @@ public class AppSearchImplTest { // Only the second document should be retrievable from another instance. AppSearchImpl appSearchImpl2 = AppSearchImpl.create(appsearchDir, /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE); - expectThrows( + assertThrows( AppSearchException.class, () -> appSearchImpl2.getDocument( diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java index f20e8c6d13a9..9b75561fd2ec 100644 --- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java +++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java @@ -25,6 +25,7 @@ import android.app.appsearch.AppSearchSchema; import android.app.appsearch.GenericDocument; import android.app.appsearch.SearchResultPage; import android.app.appsearch.SearchSpec; +import android.app.appsearch.exceptions.AppSearchException; import com.android.server.appsearch.external.localstorage.stats.CallStats; import com.android.server.appsearch.external.localstorage.stats.InitializeStats; @@ -32,17 +33,24 @@ import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats import com.android.server.appsearch.external.localstorage.stats.RemoveStats; import com.android.server.appsearch.external.localstorage.stats.SearchStats; import com.android.server.appsearch.proto.DeleteStatsProto; +import com.android.server.appsearch.proto.DocumentProto; import com.android.server.appsearch.proto.InitializeStatsProto; import com.android.server.appsearch.proto.PutDocumentStatsProto; +import com.android.server.appsearch.proto.PutResultProto; import com.android.server.appsearch.proto.QueryStatsProto; import com.android.server.appsearch.proto.ScoringSpecProto; +import com.android.server.appsearch.proto.StatusProto; import com.android.server.appsearch.proto.TermMatchType; +import com.google.common.collect.ImmutableList; + +import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; +import java.io.File; import java.util.Collections; import java.util.List; @@ -279,7 +287,7 @@ public class AppSearchLoggerTest { // Testing actual logging // @Test - public void testLoggingStats_initialize() throws Exception { + public void testLoggingStats_initializeWithoutDocuments_success() throws Exception { // Create an unused AppSearchImpl to generated an InitializeStats. InitializeStats.Builder initStatsBuilder = new InitializeStats.Builder(); AppSearchImpl.create(mTemporaryFolder.newFolder(), initStatsBuilder, ALWAYS_OPTIMIZE); @@ -295,25 +303,139 @@ public class AppSearchLoggerTest { .isEqualTo(InitializeStatsProto.DocumentStoreDataStatus.NO_DATA_LOSS_VALUE); assertThat(iStats.getDocumentCount()).isEqualTo(0); assertThat(iStats.getSchemaTypeCount()).isEqualTo(0); + assertThat(iStats.hasReset()).isEqualTo(false); + assertThat(iStats.getResetStatusCode()).isEqualTo(AppSearchResult.RESULT_OK); } @Test - public void testLoggingStats_putDocument() throws Exception { - // Insert schema + public void testLoggingStats_initializeWithDocuments_success() throws Exception { final String testPackageName = "testPackage"; final String testDatabase = "testDatabase"; + final File folder = mTemporaryFolder.newFolder(); + + AppSearchImpl appSearchImpl = + AppSearchImpl.create(folder, /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE); List<AppSearchSchema> schemas = - Collections.singletonList(new AppSearchSchema.Builder("type").build()); + ImmutableList.of( + new AppSearchSchema.Builder("Type1").build(), + new AppSearchSchema.Builder("Type2").build()); + appSearchImpl.setSchema( + testPackageName, + testDatabase, + schemas, + /*visibilityStore=*/ null, + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), + /*forceOverride=*/ false, + /*version=*/ 0); + GenericDocument doc1 = new GenericDocument.Builder<>("namespace", "id1", "Type1").build(); + GenericDocument doc2 = new GenericDocument.Builder<>("namespace", "id2", "Type1").build(); + appSearchImpl.putDocument(testPackageName, testDatabase, doc1, mLogger); + appSearchImpl.putDocument(testPackageName, testDatabase, doc2, mLogger); + appSearchImpl.close(); + + // Create another appsearchImpl on the same folder + InitializeStats.Builder initStatsBuilder = new InitializeStats.Builder(); + AppSearchImpl.create(folder, initStatsBuilder, ALWAYS_OPTIMIZE); + InitializeStats iStats = initStatsBuilder.build(); + + assertThat(iStats).isNotNull(); + assertThat(iStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK); + // Total latency captured in LocalStorage + assertThat(iStats.getTotalLatencyMillis()).isEqualTo(0); + assertThat(iStats.hasDeSync()).isFalse(); + assertThat(iStats.getNativeLatencyMillis()).isGreaterThan(0); + assertThat(iStats.getDocumentStoreDataStatus()) + .isEqualTo(InitializeStatsProto.DocumentStoreDataStatus.NO_DATA_LOSS_VALUE); + assertThat(iStats.getDocumentCount()).isEqualTo(2); + assertThat(iStats.getSchemaTypeCount()).isEqualTo(2); + assertThat(iStats.hasReset()).isEqualTo(false); + assertThat(iStats.getResetStatusCode()).isEqualTo(AppSearchResult.RESULT_OK); + } + + @Test + public void testLoggingStats_initialize_failure() throws Exception { + final String testPackageName = "testPackage"; + final String testDatabase = "testDatabase"; + final File folder = mTemporaryFolder.newFolder(); + + AppSearchImpl appSearchImpl = + AppSearchImpl.create(folder, /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE); + + List<AppSearchSchema> schemas = + ImmutableList.of( + new AppSearchSchema.Builder("Type1").build(), + new AppSearchSchema.Builder("Type2").build()); + appSearchImpl.setSchema( + testPackageName, + testDatabase, + schemas, + /*visibilityStore=*/ null, + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), + /*forceOverride=*/ false, + /*version=*/ 0); + + // Insert a valid doc + GenericDocument doc1 = new GenericDocument.Builder<>("namespace", "id1", "Type1").build(); + appSearchImpl.putDocument(testPackageName, testDatabase, doc1, mLogger); + + // Insert the invalid doc with an invalid namespace right into icing + DocumentProto invalidDoc = + DocumentProto.newBuilder() + .setNamespace("invalidNamespace") + .setUri("id2") + .setSchema(String.format("%s$%s/Type1", testPackageName, testDatabase)) + .build(); + PutResultProto putResultProto = appSearchImpl.mIcingSearchEngineLocked.put(invalidDoc); + assertThat(putResultProto.getStatus().getCode()).isEqualTo(StatusProto.Code.OK); + appSearchImpl.close(); + + // Create another appsearchImpl on the same folder + InitializeStats.Builder initStatsBuilder = new InitializeStats.Builder(); + AppSearchImpl.create(folder, initStatsBuilder, ALWAYS_OPTIMIZE); + InitializeStats iStats = initStatsBuilder.build(); + + // Some of other fields are already covered by AppSearchImplTest#testReset() + assertThat(iStats).isNotNull(); + assertThat(iStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_INTERNAL_ERROR); + assertThat(iStats.hasReset()).isTrue(); + } + + @Test + public void testLoggingStats_putDocument_success() throws Exception { + // Insert schema + final String testPackageName = "testPackage"; + final String testDatabase = "testDatabase"; + AppSearchSchema testSchema = + new AppSearchSchema.Builder("type") + .addProperty( + new AppSearchSchema.StringPropertyConfig.Builder("subject") + .setCardinality( + AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL) + .setIndexingType( + AppSearchSchema.StringPropertyConfig + .INDEXING_TYPE_PREFIXES) + .setTokenizerType( + AppSearchSchema.StringPropertyConfig + .TOKENIZER_TYPE_PLAIN) + .build()) + .build(); + List<AppSearchSchema> schemas = Collections.singletonList(testSchema); mAppSearchImpl.setSchema( testPackageName, testDatabase, schemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); - GenericDocument document = new GenericDocument.Builder<>("namespace", "id", "type").build(); + + GenericDocument document = + new GenericDocument.Builder<>("namespace", "id", "type") + .setPropertyString("subject", "testPut example1") + .build(); mAppSearchImpl.putDocument(testPackageName, testDatabase, document, mLogger); @@ -322,43 +444,119 @@ public class AppSearchLoggerTest { assertThat(pStats.getPackageName()).isEqualTo(testPackageName); assertThat(pStats.getDatabase()).isEqualTo(testDatabase); assertThat(pStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK); - // The rest of native stats have been tested in testCopyNativeStats + // The latency related native stats have been tested in testCopyNativeStats assertThat(pStats.getNativeDocumentSizeBytes()).isGreaterThan(0); + assertThat(pStats.getNativeNumTokensIndexed()).isGreaterThan(0); } @Test - public void testLoggingStats_search() throws Exception { + public void testLoggingStats_putDocument_failure() throws Exception { // Insert schema final String testPackageName = "testPackage"; final String testDatabase = "testDatabase"; - List<AppSearchSchema> schemas = - Collections.singletonList(new AppSearchSchema.Builder("type").build()); + AppSearchSchema testSchema = + new AppSearchSchema.Builder("type") + .addProperty( + new AppSearchSchema.StringPropertyConfig.Builder("subject") + .setCardinality( + AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL) + .setIndexingType( + AppSearchSchema.StringPropertyConfig + .INDEXING_TYPE_PREFIXES) + .setTokenizerType( + AppSearchSchema.StringPropertyConfig + .TOKENIZER_TYPE_PLAIN) + .build()) + .build(); + List<AppSearchSchema> schemas = Collections.singletonList(testSchema); mAppSearchImpl.setSchema( testPackageName, testDatabase, schemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); - GenericDocument document = new GenericDocument.Builder<>("namespace", "id", "type").build(); - mAppSearchImpl.putDocument(testPackageName, testDatabase, document, mLogger); + GenericDocument document = + new GenericDocument.Builder<>("namespace", "id", "type") + .setPropertyString("nonExist", "testPut example1") + .build(); + + // We mainly want to check the status code in stats. So we don't need to inspect the + // exception here. + Assert.assertThrows( + AppSearchException.class, + () -> mAppSearchImpl.putDocument(testPackageName, testDatabase, document, mLogger)); + + PutDocumentStats pStats = mLogger.mPutDocumentStats; + assertThat(pStats).isNotNull(); + assertThat(pStats.getPackageName()).isEqualTo(testPackageName); + assertThat(pStats.getDatabase()).isEqualTo(testDatabase); + assertThat(pStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_NOT_FOUND); + } + + @Test + public void testLoggingStats_search_success() throws Exception { + // Insert schema + final String testPackageName = "testPackage"; + final String testDatabase = "testDatabase"; + AppSearchSchema testSchema = + new AppSearchSchema.Builder("type") + .addProperty( + new AppSearchSchema.StringPropertyConfig.Builder("subject") + .setCardinality( + AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL) + .setIndexingType( + AppSearchSchema.StringPropertyConfig + .INDEXING_TYPE_PREFIXES) + .setTokenizerType( + AppSearchSchema.StringPropertyConfig + .TOKENIZER_TYPE_PLAIN) + .build()) + .build(); + List<AppSearchSchema> schemas = Collections.singletonList(testSchema); + mAppSearchImpl.setSchema( + testPackageName, + testDatabase, + schemas, + /*visibilityStore=*/ null, + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), + /*forceOverride=*/ false, + /*version=*/ 0); + GenericDocument document1 = + new GenericDocument.Builder<>("namespace", "id1", "type") + .setPropertyString("subject", "testPut example1") + .build(); + GenericDocument document2 = + new GenericDocument.Builder<>("namespace", "id2", "type") + .setPropertyString("subject", "testPut example2") + .build(); + GenericDocument document3 = + new GenericDocument.Builder<>("namespace", "id3", "type") + .setPropertyString("subject", "testPut 3") + .build(); + mAppSearchImpl.putDocument(testPackageName, testDatabase, document1, mLogger); + mAppSearchImpl.putDocument(testPackageName, testDatabase, document2, mLogger); + mAppSearchImpl.putDocument(testPackageName, testDatabase, document3, mLogger); // No query filters specified. package2 should only get its own documents back. SearchSpec searchSpec = - new SearchSpec.Builder().setTermMatch(TermMatchType.Code.PREFIX_VALUE).build(); + new SearchSpec.Builder() + .setTermMatch(TermMatchType.Code.PREFIX_VALUE) + .setRankingStrategy(SearchSpec.RANKING_STRATEGY_CREATION_TIMESTAMP) + .build(); + String queryStr = "testPut e"; SearchResultPage searchResultPage = mAppSearchImpl.query( - testPackageName, - testDatabase, - /*QueryExpression=*/ "", - searchSpec, - /*logger=*/ mLogger); + testPackageName, testDatabase, queryStr, searchSpec, /*logger=*/ mLogger); - assertThat(searchResultPage.getResults()).hasSize(1); - assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document); + assertThat(searchResultPage.getResults()).hasSize(2); + // The ranking strategy is LIFO + assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document2); + assertThat(searchResultPage.getResults().get(1).getGenericDocument()).isEqualTo(document1); SearchStats sStats = mLogger.mSearchStats; @@ -368,17 +566,59 @@ public class AppSearchLoggerTest { assertThat(sStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK); assertThat(sStats.getTotalLatencyMillis()).isGreaterThan(0); assertThat(sStats.getVisibilityScope()).isEqualTo(SearchStats.VISIBILITY_SCOPE_LOCAL); - assertThat(sStats.getTermCount()).isEqualTo(0); - // assertThat(sStats.getNativeQueryLength()).isEqualTo(0); + assertThat(sStats.getTermCount()).isEqualTo(2); + assertThat(sStats.getQueryLength()).isEqualTo(queryStr.length()); assertThat(sStats.getFilteredNamespaceCount()).isEqualTo(1); assertThat(sStats.getFilteredSchemaTypeCount()).isEqualTo(1); - assertThat(sStats.getCurrentPageReturnedResultCount()).isEqualTo(1); + assertThat(sStats.getCurrentPageReturnedResultCount()).isEqualTo(2); assertThat(sStats.isFirstPage()).isTrue(); - assertThat(sStats.getScoredDocumentCount()).isEqualTo(1); + assertThat(sStats.getRankingStrategy()) + .isEqualTo(SearchSpec.RANKING_STRATEGY_CREATION_TIMESTAMP); + assertThat(sStats.getScoredDocumentCount()).isEqualTo(2); + assertThat(sStats.getResultWithSnippetsCount()).isEqualTo(0); + } + + @Test + public void testLoggingStats_search_failure() throws Exception { + final String testPackageName = "testPackage"; + final String testDatabase = "testDatabase"; + List<AppSearchSchema> schemas = + ImmutableList.of( + new AppSearchSchema.Builder("Type1").build(), + new AppSearchSchema.Builder("Type2").build()); + mAppSearchImpl.setSchema( + testPackageName, + testDatabase, + schemas, + /*visibilityStore=*/ null, + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), + /*forceOverride=*/ false, + /*version=*/ 0); + + SearchSpec searchSpec = + new SearchSpec.Builder() + .setTermMatch(TermMatchType.Code.PREFIX_VALUE) + .setRankingStrategy(SearchSpec.RANKING_STRATEGY_CREATION_TIMESTAMP) + .addFilterPackageNames("anotherPackage") + .build(); + + mAppSearchImpl.query( + testPackageName, + testPackageName, + /* queryExpression= */ "", + searchSpec, + /*logger=*/ mLogger); + + SearchStats sStats = mLogger.mSearchStats; + assertThat(sStats).isNotNull(); + assertThat(sStats.getPackageName()).isEqualTo(testPackageName); + assertThat(sStats.getDatabase()).isEqualTo(testPackageName); + assertThat(sStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_SECURITY_ERROR); } @Test - public void testLoggingStats_remove() throws Exception { + public void testLoggingStats_remove_success() throws Exception { // Insert schema final String testPackageName = "testPackage"; final String testDatabase = "testDatabase"; @@ -391,8 +631,8 @@ public class AppSearchLoggerTest { testDatabase, schemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); GenericDocument document = @@ -406,12 +646,59 @@ public class AppSearchLoggerTest { assertThat(rStats.getPackageName()).isEqualTo(testPackageName); assertThat(rStats.getDatabase()).isEqualTo(testDatabase); // delete by namespace + id + assertThat(rStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK); assertThat(rStats.getDeleteType()).isEqualTo(DeleteStatsProto.DeleteType.Code.SINGLE_VALUE); assertThat(rStats.getDeletedDocumentCount()).isEqualTo(1); } @Test - public void testLoggingStats_removeByQuery() throws Exception { + public void testLoggingStats_remove_failure() throws Exception { + // Insert schema + final String testPackageName = "testPackage"; + final String testDatabase = "testDatabase"; + final String testNamespace = "testNameSpace"; + final String testId = "id"; + List<AppSearchSchema> schemas = + Collections.singletonList(new AppSearchSchema.Builder("type").build()); + mAppSearchImpl.setSchema( + testPackageName, + testDatabase, + schemas, + /*visibilityStore=*/ null, + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), + /*forceOverride=*/ false, + /*version=*/ 0); + + GenericDocument document = + new GenericDocument.Builder<>(testNamespace, testId, "type").build(); + mAppSearchImpl.putDocument(testPackageName, testDatabase, document, /*logger=*/ null); + + RemoveStats.Builder rStatsBuilder = new RemoveStats.Builder(testPackageName, testDatabase); + + // We mainly want to check the status code in stats. So we don't need to inspect the + // exception here. + Assert.assertThrows( + AppSearchException.class, + () -> + mAppSearchImpl.remove( + testPackageName, + testDatabase, + testNamespace, + "invalidId", + rStatsBuilder)); + + RemoveStats rStats = rStatsBuilder.build(); + assertThat(rStats.getPackageName()).isEqualTo(testPackageName); + assertThat(rStats.getDatabase()).isEqualTo(testDatabase); + assertThat(rStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_NOT_FOUND); + // delete by namespace + id + assertThat(rStats.getDeleteType()).isEqualTo(DeleteStatsProto.DeleteType.Code.SINGLE_VALUE); + assertThat(rStats.getDeletedDocumentCount()).isEqualTo(0); + } + + @Test + public void testLoggingStats_removeByQuery_success() throws Exception { // Insert schema final String testPackageName = "testPackage"; final String testDatabase = "testDatabase"; @@ -423,8 +710,8 @@ public class AppSearchLoggerTest { testDatabase, schemas, /*visibilityStore=*/ null, - /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(), - /*schemasPackageAccessible=*/ Collections.emptyMap(), + /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), + /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, /*version=*/ 0); GenericDocument document1 = @@ -444,6 +731,7 @@ public class AppSearchLoggerTest { assertThat(rStats.getPackageName()).isEqualTo(testPackageName); assertThat(rStats.getDatabase()).isEqualTo(testDatabase); + assertThat(rStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK); // delete by query assertThat(rStats.getDeleteType()).isEqualTo(DeleteStatsProto.DeleteType.Code.QUERY_VALUE); assertThat(rStats.getDeletedDocumentCount()).isEqualTo(2); 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 d3feb12912ad..64a670dcdb38 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 @@ -46,7 +46,6 @@ public class SnippetTest { PREFIX, Collections.singletonMap(PREFIX + SCHEMA_TYPE, SCHEMA_TYPE_CONFIG_PROTO)); - // TODO(tytytyww): Add tests for Double and Long Snippets. @Test public void testSingleStringSnippet() { final String propertyKeyString = "content"; @@ -112,7 +111,6 @@ public class SnippetTest { assertThat(match.getSnippet()).isEqualTo(window); } - // TODO(tytytyww): Add tests for Double and Long Snippets. @Test public void testNoSnippets() { final String propertyKeyString = "content"; diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java index 6d9068675a72..57d994155d5b 100644 --- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java +++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java @@ -254,14 +254,25 @@ public class AppSearchStatsTest { @Test public void testAppSearchStats_SetSchemaStats() { + SchemaMigrationStats schemaMigrationStats = + new SchemaMigrationStats.Builder() + .setGetSchemaLatencyMillis(1) + .setQueryAndTransformLatencyMillis(2) + .setFirstSetSchemaLatencyMillis(3) + .setSecondSetSchemaLatencyMillis(4) + .setSaveDocumentLatencyMillis(5) + .setMigratedDocumentCount(6) + .setSavedDocumentCount(7) + .build(); int nativeLatencyMillis = 1; int newTypeCount = 2; int compatibleTypeChangeCount = 3; int indexIncompatibleTypeChangeCount = 4; int backwardsIncompatibleTypeChangeCount = 5; - final SetSchemaStats sStats = + SetSchemaStats sStats = new SetSchemaStats.Builder(TEST_PACKAGE_NAME, TEST_DATA_BASE) .setStatusCode(TEST_STATUS_CODE) + .setSchemaMigrationStats(schemaMigrationStats) .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS) .setNativeLatencyMillis(nativeLatencyMillis) .setNewTypeCount(newTypeCount) @@ -274,6 +285,7 @@ public class AppSearchStatsTest { assertThat(sStats.getPackageName()).isEqualTo(TEST_PACKAGE_NAME); assertThat(sStats.getDatabase()).isEqualTo(TEST_DATA_BASE); assertThat(sStats.getStatusCode()).isEqualTo(TEST_STATUS_CODE); + assertThat(sStats.getSchemaMigrationStats()).isEqualTo(schemaMigrationStats); assertThat(sStats.getTotalLatencyMillis()).isEqualTo(TEST_TOTAL_LATENCY_MILLIS); assertThat(sStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis); assertThat(sStats.getNewTypeCount()).isEqualTo(newTypeCount); @@ -285,6 +297,35 @@ public class AppSearchStatsTest { } @Test + public void testAppSearchStats_SchemaMigrationStats() { + int getSchemaLatency = 1; + int queryAndTransformLatency = 2; + int firstSetSchemaLatency = 3; + int secondSetSchemaLatency = 4; + int saveDocumentLatency = 5; + int migratedDocumentCount = 6; + int savedDocumentCount = 7; + SchemaMigrationStats sStats = + new SchemaMigrationStats.Builder() + .setGetSchemaLatencyMillis(getSchemaLatency) + .setQueryAndTransformLatencyMillis(queryAndTransformLatency) + .setFirstSetSchemaLatencyMillis(firstSetSchemaLatency) + .setSecondSetSchemaLatencyMillis(secondSetSchemaLatency) + .setSaveDocumentLatencyMillis(saveDocumentLatency) + .setMigratedDocumentCount(migratedDocumentCount) + .setSavedDocumentCount(savedDocumentCount) + .build(); + + assertThat(sStats.getGetSchemaLatencyMillis()).isEqualTo(getSchemaLatency); + assertThat(sStats.getQueryAndTransformLatencyMillis()).isEqualTo(queryAndTransformLatency); + assertThat(sStats.getFirstSetSchemaLatencyMillis()).isEqualTo(firstSetSchemaLatency); + assertThat(sStats.getSecondSetSchemaLatencyMillis()).isEqualTo(secondSetSchemaLatency); + assertThat(sStats.getSaveDocumentLatencyMillis()).isEqualTo(saveDocumentLatency); + assertThat(sStats.getMigratedDocumentCount()).isEqualTo(migratedDocumentCount); + assertThat(sStats.getSavedDocumentCount()).isEqualTo(savedDocumentCount); + } + + @Test public void testAppSearchStats_RemoveStats() { int nativeLatencyMillis = 1; @RemoveStats.DeleteType int deleteType = 2; diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java index c0df2e33ffed..cae6c863ab02 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java @@ -48,8 +48,11 @@ import android.database.ContentObserver; import android.hardware.Sensor; import android.hardware.SensorEventListener; import android.hardware.SensorManager; +import android.hardware.display.BrightnessInfo; import android.hardware.display.DisplayManager; +import android.hardware.display.DisplayManager.DisplayListener; import android.hardware.display.DisplayManagerInternal; +import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation; import android.hardware.display.DisplayManagerInternal.RefreshRateRange; import android.hardware.fingerprint.IUdfpsHbmListener; import android.os.Handler; @@ -120,7 +123,7 @@ public class DisplayModeDirectorTest { mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext())); final MockContentResolver resolver = mSettingsProviderRule.mockContentResolver(mContext); when(mContext.getContentResolver()).thenReturn(resolver); - mInjector = new FakesInjector(); + mInjector = spy(new FakesInjector()); mHandler = new Handler(Looper.getMainLooper()); LocalServices.removeServiceForTest(StatusBarManagerInternal.class); @@ -1256,13 +1259,163 @@ public class DisplayModeDirectorTest { assertNull(vote); } + @Test + public void testHbmVoting_forHdr() { + DisplayModeDirector director = + createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0); + director.start(createMockSensorManager()); + + ArgumentCaptor<DisplayListener> captor = + ArgumentCaptor.forClass(DisplayListener.class); + verify(mInjector).registerDisplayListener(captor.capture(), any(Handler.class), + eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS + | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED)); + DisplayListener listener = captor.getValue(); + + // Specify Limitation + when(mDisplayManagerInternalMock.getRefreshRateLimitations(DISPLAY_ID)).thenReturn( + List.of(new RefreshRateLimitation( + DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE, + 60.f, 60.f))); + + // Verify that there is no HBM vote initially + Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); + assertNull(vote); + + // Turn on HBM + when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( + new BrightnessInfo(0.45f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR)); + listener.onDisplayChanged(DISPLAY_ID); + vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); + assertVoteForRefreshRate(vote, 60.f); + + // Turn off HBM + when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( + new BrightnessInfo(0.45f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF)); + listener.onDisplayChanged(DISPLAY_ID); + vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); + assertNull(vote); + } + + @Test + public void testHbmVoting_forSunlight() { + DisplayModeDirector director = + createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0); + director.start(createMockSensorManager()); + + ArgumentCaptor<DisplayListener> captor = + ArgumentCaptor.forClass(DisplayListener.class); + verify(mInjector).registerDisplayListener(captor.capture(), any(Handler.class), + eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS + | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED)); + DisplayListener listener = captor.getValue(); + + // Specify Limitation + when(mDisplayManagerInternalMock.getRefreshRateLimitations(DISPLAY_ID)).thenReturn( + List.of(new RefreshRateLimitation( + DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE, + 60.f, 60.f))); + + // Verify that there is no HBM vote initially + Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); + assertNull(vote); + + // Turn on HBM + when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( + new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT)); + listener.onDisplayChanged(DISPLAY_ID); + vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); + assertVoteForRefreshRate(vote, 60.f); + + // Turn off HBM + when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( + new BrightnessInfo(0.43f, 0.1f, 0.8f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF)); + listener.onDisplayChanged(DISPLAY_ID); + vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); + assertNull(vote); + } + + @Test + public void testHbmVoting_forSunlight_NoLimitation() { + DisplayModeDirector director = + createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0); + director.start(createMockSensorManager()); + + ArgumentCaptor<DisplayListener> captor = + ArgumentCaptor.forClass(DisplayListener.class); + verify(mInjector).registerDisplayListener(captor.capture(), any(Handler.class), + eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS + | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED)); + DisplayListener listener = captor.getValue(); + + // Specify Limitation for different display + when(mDisplayManagerInternalMock.getRefreshRateLimitations(DISPLAY_ID + 1)).thenReturn( + List.of(new RefreshRateLimitation( + DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE, + 60.f, 60.f))); + + // Verify that there is no HBM vote initially + Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); + assertNull(vote); + + // Turn on HBM + when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( + new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT)); + listener.onDisplayChanged(DISPLAY_ID); + vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); + assertNull(vote); + + // Turn off HBM + when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( + new BrightnessInfo(0.43f, 0.1f, 0.8f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF)); + listener.onDisplayChanged(DISPLAY_ID); + vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); + assertNull(vote); + } + + @Test + public void testHbmVoting_RemovedDisplay() { + DisplayModeDirector director = + createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0); + director.start(createMockSensorManager()); + + ArgumentCaptor<DisplayListener> captor = + ArgumentCaptor.forClass(DisplayListener.class); + verify(mInjector).registerDisplayListener(captor.capture(), any(Handler.class), + eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS + | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED)); + DisplayListener listener = captor.getValue(); + + // Specify Limitation for different display + when(mDisplayManagerInternalMock.getRefreshRateLimitations(DISPLAY_ID)).thenReturn( + List.of(new RefreshRateLimitation( + DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE, + 60.f, 60.f))); + + // Verify that there is no HBM vote initially + Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); + assertNull(vote); + + // Turn on HBM + when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( + new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT)); + listener.onDisplayChanged(DISPLAY_ID); + vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); + assertVoteForRefreshRate(vote, 60.f); + + // Turn off HBM + listener.onDisplayRemoved(DISPLAY_ID); + vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); + assertNull(vote); + } + private void assertVoteForRefreshRate(Vote vote, float refreshRate) { assertThat(vote).isNotNull(); final RefreshRateRange expectedRange = new RefreshRateRange(refreshRate, refreshRate); assertThat(vote.refreshRateRange).isEqualTo(expectedRange); } - private static class FakeDeviceConfig extends FakeDeviceConfigInterface { + public static class FakeDeviceConfig extends FakeDeviceConfigInterface { @Override public String getProperty(String namespace, String name) { Preconditions.checkArgument(DeviceConfig.NAMESPACE_DISPLAY_MANAGER.equals(namespace)); @@ -1403,7 +1556,7 @@ public class DisplayModeDirectorTest { mHandler.runWithScissors(() -> { }, 500 /*timeout*/); } - static class FakesInjector implements DisplayModeDirector.Injector { + public static class FakesInjector implements DisplayModeDirector.Injector { private final FakeDeviceConfig mDeviceConfig; private ContentObserver mBrightnessObserver; private ContentObserver mPeakRefreshRateObserver; @@ -1444,6 +1597,14 @@ public class DisplayModeDirectorTest { mPeakRefreshRateObserver = observer; } + @Override + public void registerDisplayListener(DisplayListener listener, Handler handler, long flag) {} + + @Override + public BrightnessInfo getBrightnessInfo(int displayId) { + return null; + } + void notifyPeakRefreshRateChanged() { if (mPeakRefreshRateObserver != null) { mPeakRefreshRateObserver.dispatchChange(false /*selfChange*/, diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java index 7df2dd6988bf..019254d542b2 100644 --- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java @@ -649,7 +649,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { protected class MockAppSearchManager implements IAppSearchManager { - protected Map<String, List<PackageIdentifier>> mSchemasPackageAccessible = + protected Map<String, List<PackageIdentifier>> mSchemasVisibleToPackages = new ArrayMap<>(1); private Map<String, Map<String, GenericDocument>> mDocumentMap = new ArrayMap<>(1); @@ -659,19 +659,19 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { @Override public void setSchema(String packageName, String databaseName, List<Bundle> schemaBundles, - List<String> schemasNotPlatformSurfaceable, - Map<String, List<Bundle>> schemasPackageAccessibleBundles, boolean forceOverride, + List<String> schemasNotDisplayedBySystem, + Map<String, List<Bundle>> schemasVisibleToPackagesBundles, boolean forceOverride, int version, UserHandle userHandle, long binderCallStartTimeMillis, IAppSearchResultCallback callback) throws RemoteException { for (Map.Entry<String, List<Bundle>> entry : - schemasPackageAccessibleBundles.entrySet()) { + schemasVisibleToPackagesBundles.entrySet()) { final String key = entry.getKey(); final List<PackageIdentifier> packageIdentifiers; - if (!mSchemasPackageAccessible.containsKey(key)) { + if (!mSchemasVisibleToPackages.containsKey(key)) { packageIdentifiers = new ArrayList<>(entry.getValue().size()); - mSchemasPackageAccessible.put(key, packageIdentifiers); + mSchemasVisibleToPackages.put(key, packageIdentifiers); } else { - packageIdentifiers = mSchemasPackageAccessible.get(key); + packageIdentifiers = mSchemasVisibleToPackages.get(key); } for (int i = 0; i < entry.getValue().size(); i++) { packageIdentifiers.add(new PackageIdentifier(entry.getValue().get(i))); diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java index 558fb309ad98..976a588273a7 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java @@ -18,7 +18,11 @@ package com.android.server.pm; import static com.google.common.truth.Truth.assertWithMessage; +import static org.junit.Assert.fail; + import static java.lang.reflect.Modifier.isFinal; +import static java.lang.reflect.Modifier.isPrivate; +import static java.lang.reflect.Modifier.isProtected; import static java.lang.reflect.Modifier.isPublic; import static java.lang.reflect.Modifier.isStatic; @@ -44,9 +48,12 @@ import org.junit.runner.RunWith; import java.io.File; import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.regex.Pattern; @@ -393,6 +400,178 @@ public class PackageManagerServiceTest { Assert.assertEquals(3600000003L, multiPackage[1].timeouts.maxPendingTimeUs); } + // Report an error from the Computer structure validation test. + private void flag(String name, String msg) { + fail(name + " " + msg); + } + + // Return a string that identifies a Method. This is not very efficient but it is not + // called very often. + private String displayName(Method m) { + String r = m.getName(); + String p = Arrays.toString(m.getGenericParameterTypes()) + .replaceAll("([a-zA-Z0-9]+\\.)+", "") + .replace("class ", "") + .replaceAll("^\\[", "(") + .replaceAll("\\]$", ")"); + return r + p; + } + + // Match a method to an array of Methods. Matching is on method signature: name and + // parameter types. If a method in the declared array matches, return it. Otherwise + // return null. + private Method matchMethod(Method m, Method[] declared) { + String n = m.getName(); + Type[] t = m.getGenericParameterTypes(); + for (int i = 0; i < declared.length; i++) { + Method l = declared[i]; + if (l != null && l.getName().equals(n) + && Arrays.equals(l.getGenericParameterTypes(), t)) { + Method result = l; + // Set the method to null since it has been visited already. + declared[i] = null; + return result; + } + } + return null; + } + + // Return the boolean locked value. A null return means the annotation was not + // found. This method will fail if the annotation is found but is not one of the + // known constants. + private Boolean getOverride(Method m) { + final String name = "Computer." + displayName(m); + final PackageManagerService.Computer.LiveImplementation annotation = + m.getAnnotation(PackageManagerService.Computer.LiveImplementation.class); + if (annotation == null) { + return null; + } + final int override = annotation.override(); + if (override == PackageManagerService.Computer.LiveImplementation.MANDATORY) { + return true; + } else if (override == PackageManagerService.Computer.LiveImplementation.NOT_ALLOWED) { + return false; + } else { + flag(name, "invalid Live value: " + override); + return null; + } + } + + @Test + public void testComputerStructure() { + // Verify that Copmuter methods are properly annotated and that ComputerLocked is + // properly populated per annotations. + // Call PackageManagerService.validateComputer(); + Class base = PackageManagerService.Computer.class; + + HashMap<Method, Boolean> methodType = new HashMap<>(); + + // Verify that all Computer methods are annotated and that the annotation + // parameter locked() is valid. + for (Method m : base.getDeclaredMethods()) { + final String name = "Computer." + displayName(m); + Boolean override = getOverride(m); + if (override == null) { + flag(name, "missing required Live annotation"); + } + methodType.put(m, override); + } + + Class coreClass = PackageManagerService.ComputerEngine.class; + final Method[] coreMethods = coreClass.getDeclaredMethods(); + + // Examine every method in the core. If it inherits from a base method it must be + // "public final" if the base is NOT_ALLOWED or "public" if the base is MANDATORY. + // If the core method does not inherit from the base then it must be either + // private or protected. + for (Method m : base.getDeclaredMethods()) { + String name = "Computer." + displayName(m); + final boolean locked = methodType.get(m); + final Method core = matchMethod(m, coreMethods); + if (core == null) { + flag(name, "not overridden in ComputerEngine"); + continue; + } + name = "ComputerEngine." + displayName(m); + final int modifiers = core.getModifiers(); + if (!locked) { + if (!isPublic(modifiers)) { + flag(name, "is not public"); + } + if (!isFinal(modifiers)) { + flag(name, "is not final"); + } + } + } + // Any methods left in the coreMethods array must be private or protected. + // Protected methods must be overridden (and final) in the live list. + Method[] coreHelpers = new Method[coreMethods.length]; + int coreIndex = 0; + for (Method m : coreMethods) { + if (m != null) { + final String name = "ComputerEngine." + displayName(m); + final int modifiers = m.getModifiers(); + if (isPrivate(modifiers)) { + // Okay + } else if (isProtected(modifiers)) { + coreHelpers[coreIndex++] = m; + } else { + flag(name, "is neither private nor protected"); + } + } + } + + Class liveClass = PackageManagerService.ComputerLocked.class; + final Method[] liveMethods = liveClass.getDeclaredMethods(); + + // Examine every method in the live list. Every method must be final and must + // inherit either from base or core. If the method inherits from a base method + // then the base must be MANDATORY. + for (Method m : base.getDeclaredMethods()) { + String name = "Computer." + displayName(m); + final boolean locked = methodType.get(m); + final Method live = matchMethod(m, liveMethods); + if (live == null) { + if (locked) { + flag(name, "not overridden in ComputerLocked"); + } + continue; + } + if (!locked) { + flag(name, "improperly overridden in ComputerLocked"); + continue; + } + + name = "ComputerLocked." + displayName(m); + final int modifiers = live.getModifiers(); + if (!locked) { + if (!isPublic(modifiers)) { + flag(name, "is not public"); + } + if (!isFinal(modifiers)) { + flag(name, "is not final"); + } + } + } + for (Method m : coreHelpers) { + if (m == null) { + continue; + } + String name = "ComputerLocked." + displayName(m); + final Method live = matchMethod(m, liveMethods); + if (live == null) { + flag(name, "is not overridden in ComputerLocked"); + continue; + } + } + for (Method m : liveMethods) { + if (m != null) { + String name = "ComputerLocked." + displayName(m); + flag(name, "illegal local method"); + } + } + } + private static PerPackageReadTimeouts[] getPerPackageReadTimeouts(String knownDigestersList) { final String defaultTimeouts = "3600000001:3600000002:3600000003"; List<PerPackageReadTimeouts> result = PerPackageReadTimeouts.parseDigestersList( diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java index 17d99e652726..f880563e2880 100644 --- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java +++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java @@ -222,6 +222,64 @@ public class SystemConfigTest { } /** + * Tests that readPermissions works correctly with {@link SystemConfig#ALLOW_APP_CONFIGS} + * permission flag for the tag: {@code allowed-partner-apex}. + */ + @Test + public void readPermissions_allowAppConfigs_parsesPartnerApexAllowList() + throws IOException { + final String contents = + "<config>\n" + + " <allowed-partner-apex package=\"com.android.apex1\" />\n" + + "</config>"; + final File folder = createTempSubfolder("folder"); + createTempFile(folder, "partner-apex-allowlist.xml", contents); + + mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0); + + assertThat(mSysConfig.getAllowedPartnerApexes()).containsExactly("com.android.apex1"); + } + + /** + * Tests that readPermissions works correctly with {@link SystemConfig#ALLOW_APP_CONFIGS} + * permission flag for the tag: {@code allowed-partner-apex}. + */ + @Test + public void readPermissions_allowAppConfigs_parsesPartnerApexAllowList_noPackage() + throws IOException { + final String contents = + "<config>\n" + + " <allowed-partner-apex/>\n" + + "</config>"; + final File folder = createTempSubfolder("folder"); + createTempFile(folder, "partner-apex-allowlist.xml", contents); + + mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0); + + assertThat(mSysConfig.getAllowedPartnerApexes()).isEmpty(); + } + + + /** + * Tests that readPermissions works correctly without {@link SystemConfig#ALLOW_APP_CONFIGS} + * permission flag for the tag: {@code allowed-partner-apex}. + */ + @Test + public void readPermissions_notAllowAppConfigs_doesNotParsePartnerApexAllowList() + throws IOException { + final String contents = + "<config>\n" + + " <allowed-partner-apex package=\"com.android.apex1\" />\n" + + "</config>"; + final File folder = createTempSubfolder("folder"); + createTempFile(folder, "partner-apex-allowlist.xml", contents); + + mSysConfig.readPermissions(folder, /* Grant all but ALLOW_APP_CONFIGS flag */ ~0x08); + + assertThat(mSysConfig.getAllowedPartnerApexes()).isEmpty(); + } + + /** * Creates folderName/fileName in the mTemporaryFolder and fills it with the contents. * * @param folderName subdirectory of mTemporaryFolder to put the file, creating if needed 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 058575817acf..0449e4450d06 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java @@ -56,6 +56,8 @@ final class FakeVibratorControllerProvider { private int[] mSupportedEffects; private int[] mSupportedBraking; private int[] mSupportedPrimitives; + private int mCompositionSizeMax; + private int mPwleSizeMax; private float mMinFrequency = Float.NaN; private float mResonantFrequency = Float.NaN; private float mFrequencyResolution = Float.NaN; @@ -151,12 +153,22 @@ final class FakeVibratorControllerProvider { } @Override - public VibratorInfo getInfo(float suggestedFrequencyRange) { - VibratorInfo.FrequencyMapping frequencyMapping = new VibratorInfo.FrequencyMapping( - mMinFrequency, mResonantFrequency, mFrequencyResolution, - suggestedFrequencyRange, mMaxAmplitudes); - return new VibratorInfo(vibratorId, mCapabilities, mSupportedEffects, mSupportedBraking, - mSupportedPrimitives, null, mQFactor, frequencyMapping); + public boolean getInfo(float suggestedFrequencyRange, VibratorInfo.Builder infoBuilder) { + infoBuilder.setCapabilities(mCapabilities); + infoBuilder.setSupportedBraking(mSupportedBraking); + infoBuilder.setPwleSizeMax(mPwleSizeMax); + infoBuilder.setSupportedEffects(mSupportedEffects); + if (mSupportedPrimitives != null) { + for (int primitive : mSupportedPrimitives) { + infoBuilder.setSupportedPrimitive(primitive, EFFECT_DURATION); + } + } + infoBuilder.setCompositionSizeMax(mCompositionSizeMax); + infoBuilder.setQFactor(mQFactor); + infoBuilder.setFrequencyMapping(new VibratorInfo.FrequencyMapping(mMinFrequency, + mResonantFrequency, mFrequencyResolution, suggestedFrequencyRange, + mMaxAmplitudes)); + return true; } private void applyLatency() { @@ -236,6 +248,16 @@ final class FakeVibratorControllerProvider { mSupportedPrimitives = primitives; } + /** Set the max number of primitives allowed in a composition by the fake vibrator hardware. */ + public void setCompositionSizeMax(int compositionSizeMax) { + mCompositionSizeMax = compositionSizeMax; + } + + /** Set the max number of PWLEs allowed in a composition by the fake vibrator hardware. */ + public void setPwleSizeMax(int pwleSizeMax) { + mPwleSizeMax = pwleSizeMax; + } + /** Set the resonant frequency of the fake vibrator hardware. */ public void setResonantFrequency(float frequencyHz) { mResonantFrequency = frequencyHz; diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java index f02e2f081e3b..b8fdb552e453 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java @@ -356,7 +356,8 @@ public class VibrationThreadTest { @Test public void vibrate_singleVibratorComposed_runsVibration() throws Exception { - mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS); + FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID); + fakeVibrator.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS); long vibrationId = 1; VibrationEffect effect = VibrationEffect.startComposition() @@ -374,7 +375,7 @@ public class VibrationThreadTest { assertEquals(Arrays.asList( expectedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 0), expectedPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0.5f, 0)), - mVibratorProviders.get(VIBRATOR_ID).getEffectSegments()); + fakeVibrator.getEffectSegments()); } @Test @@ -395,6 +396,27 @@ public class VibrationThreadTest { } @Test + public void vibrate_singleVibratorLargeComposition_splitsVibratorComposeCalls() { + FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID); + fakeVibrator.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS); + fakeVibrator.setCompositionSizeMax(2); + + long vibrationId = 1; + VibrationEffect effect = VibrationEffect.startComposition() + .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f) + .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0.5f) + .addPrimitive(VibrationEffect.Composition.PRIMITIVE_SPIN, 0.8f) + .compose(); + VibrationThread thread = startThreadAndDispatcher(vibrationId, effect); + waitForCompletion(thread); + + verify(mThreadCallbacks).onVibrationEnded(eq(vibrationId), eq(Vibration.Status.FINISHED)); + // Vibrator compose called twice. + verify(mControllerCallbacks, times(2)).onComplete(eq(VIBRATOR_ID), eq(vibrationId)); + assertEquals(3, fakeVibrator.getEffectSegments().size()); + } + + @Test public void vibrate_singleVibratorComposedEffects_runsDifferentVibrations() throws Exception { mVibratorProviders.get(VIBRATOR_ID).setSupportedEffects(VibrationEffect.EFFECT_CLICK); mVibratorProviders.get(VIBRATOR_ID).setSupportedPrimitives( @@ -432,12 +454,13 @@ public class VibrationThreadTest { @Test public void vibrate_singleVibratorPwle_runsComposePwle() throws Exception { - mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_COMPOSE_PWLE_EFFECTS); - mVibratorProviders.get(VIBRATOR_ID).setSupportedBraking(Braking.CLAB); - mVibratorProviders.get(VIBRATOR_ID).setMinFrequency(100); - mVibratorProviders.get(VIBRATOR_ID).setResonantFrequency(150); - mVibratorProviders.get(VIBRATOR_ID).setFrequencyResolution(50); - mVibratorProviders.get(VIBRATOR_ID).setMaxAmplitudes( + FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID); + fakeVibrator.setCapabilities(IVibrator.CAP_COMPOSE_PWLE_EFFECTS); + fakeVibrator.setSupportedBraking(Braking.CLAB); + fakeVibrator.setMinFrequency(100); + fakeVibrator.setResonantFrequency(150); + fakeVibrator.setFrequencyResolution(50); + fakeVibrator.setMaxAmplitudes( 0.5f /* 100Hz*/, 1 /* 150Hz */, 0.6f /* 200Hz */); long vibrationId = 1; @@ -462,8 +485,34 @@ public class VibrationThreadTest { expectedRamp(/* amplitude= */ 0.6f, /* frequency= */ 200, /* duration= */ 30), expectedRamp(/* StartAmplitude= */ 0.6f, /* endAmplitude= */ 0.5f, /* startFrequency= */ 200, /* endFrequency= */ 100, /* duration= */ 40)), - mVibratorProviders.get(VIBRATOR_ID).getEffectSegments()); - assertEquals(Arrays.asList(Braking.CLAB), mVibratorProviders.get(VIBRATOR_ID).getBraking()); + fakeVibrator.getEffectSegments()); + assertEquals(Arrays.asList(Braking.CLAB), fakeVibrator.getBraking()); + } + + @Test + public void vibrate_singleVibratorLargePwle_splitsVibratorComposeCalls() { + FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID); + fakeVibrator.setCapabilities(IVibrator.CAP_COMPOSE_PWLE_EFFECTS); + fakeVibrator.setMinFrequency(100); + fakeVibrator.setResonantFrequency(150); + fakeVibrator.setFrequencyResolution(50); + fakeVibrator.setMaxAmplitudes(1, 1, 1); + fakeVibrator.setPwleSizeMax(2); + + long vibrationId = 1; + VibrationEffect effect = VibrationEffect.startWaveform() + .addStep(1, 10) + .addRamp(0, 20) + .addStep(0.8f, 1, 30) + .addRamp(0.6f, -1, 40) + .build(); + VibrationThread thread = startThreadAndDispatcher(vibrationId, effect); + waitForCompletion(thread); + + verify(mThreadCallbacks).onVibrationEnded(eq(vibrationId), eq(Vibration.Status.FINISHED)); + // Vibrator compose called twice. + verify(mControllerCallbacks, times(2)).onComplete(eq(VIBRATOR_ID), eq(vibrationId)); + assertEquals(4, fakeVibrator.getEffectSegments().size()); } @Test 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 9e98e7d0410c..a732bd18676a 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorControllerTest.java @@ -298,11 +298,13 @@ public class VibratorControllerTest { private void mockVibratorCapabilities(int capabilities) { VibratorInfo.FrequencyMapping frequencyMapping = new VibratorInfo.FrequencyMapping( Float.NaN, Float.NaN, Float.NaN, Float.NaN, null); - when(mNativeWrapperMock.getInfo(anyFloat())).thenReturn( - new VibratorInfo.Builder(VIBRATOR_ID) - .setCapabilities(capabilities) - .setFrequencyMapping(frequencyMapping) - .build()); + when(mNativeWrapperMock.getInfo(anyFloat(), any(VibratorInfo.Builder.class))) + .then(invocation -> { + ((VibratorInfo.Builder) invocation.getArgument(1)) + .setCapabilities(capabilities) + .setFrequencyMapping(frequencyMapping); + return true; + }); } private PrebakedSegment createPrebaked(int effectId, int effectStrength) { diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java index 9267285b446b..9cf29d4dcc50 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.app.KeyguardManager.ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; @@ -53,6 +54,7 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.contains; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.refEq; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; @@ -1012,12 +1014,26 @@ public class RootWindowContainerTests extends WindowTestsBase { // Create another activity on top and the user id is 1 final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task) .setUid(UserHandle.PER_USER_RANGE + 1).build(); + doReturn(true).when(topActivity).okToShowLocked(); + topActivity.intent.setAction(Intent.ACTION_MAIN); // Make sure the listeners will be notified for putting the task to locked state TaskChangeNotificationController controller = mAtm.getTaskChangeNotificationController(); spyOn(controller); mWm.mRoot.lockAllProfileTasks(0); verify(controller).notifyTaskProfileLocked(eq(taskId), eq(0)); + + // Create the work lock activity on top of the task + final ActivityRecord workLockActivity = new ActivityBuilder(mAtm).setTask(task) + .setUid(UserHandle.PER_USER_RANGE + 1).build(); + doReturn(true).when(workLockActivity).okToShowLocked(); + workLockActivity.intent.setAction(ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER); + doReturn(workLockActivity.mActivityComponent).when(mAtm).getSysUiServiceComponentLocked(); + + // Make sure the listener won't be notified again. + clearInvocations(controller); + mWm.mRoot.lockAllProfileTasks(0); + verify(controller, never()).notifyTaskProfileLocked(anyInt(), anyInt()); } /** 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 4e261deb67f6..4872ec511ccc 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -401,6 +401,7 @@ public class SizeCompatTests extends WindowTestsBase { assertFitted(); final Rect currentBounds = mActivity.getWindowConfiguration().getBounds(); + final Rect currentAppBounds = mActivity.getWindowConfiguration().getAppBounds(); final Rect originalBounds = new Rect(mActivity.getWindowConfiguration().getBounds()); final int notchHeight = 100; @@ -428,8 +429,8 @@ public class SizeCompatTests extends WindowTestsBase { // Because the display cannot rotate, the portrait activity will fit the short side of // display with keeping portrait bounds [200, 0 - 700, 1000] in center. assertEquals(newDisplayBounds.height(), currentBounds.height()); - assertEquals(currentBounds.height() * newDisplayBounds.height() / newDisplayBounds.width(), - currentBounds.width()); + assertEquals(currentAppBounds.height() * newDisplayBounds.height() + / newDisplayBounds.width(), currentAppBounds.width()); assertFitted(); // The appBounds should be [200, 100 - 700, 1000]. final Rect appBounds = mActivity.getWindowConfiguration().getAppBounds(); 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 d93ebb383b3b..0ebff1d253ef 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java @@ -60,6 +60,7 @@ import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.same; +import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.never; @@ -121,8 +122,8 @@ public class TaskTests extends WindowTestsBase { @Test public void testRemoveContainer() { - final Task taskController1 = createTask(mDisplayContent); - final Task task = createTaskInRootTask(taskController1, 0 /* userId */); + final Task rootTask = createTask(mDisplayContent); + final Task task = createTaskInRootTask(rootTask, 0 /* userId */); final ActivityRecord activity = createActivityRecord(mDisplayContent, task); task.removeIfPossible(); @@ -130,12 +131,14 @@ public class TaskTests extends WindowTestsBase { assertNull(task.getParent()); assertEquals(0, task.getChildCount()); assertNull(activity.getParent()); + verify(mAtm.getLockTaskController(), atLeast(1)).clearLockedTask(task); + verify(mAtm.getLockTaskController(), atLeast(1)).clearLockedTask(rootTask); } @Test public void testRemoveContainer_deferRemoval() { - final Task taskController1 = createTask(mDisplayContent); - final Task task = createTaskInRootTask(taskController1, 0 /* userId */); + final Task rootTask = createTask(mDisplayContent); + final Task task = createTaskInRootTask(rootTask, 0 /* userId */); final ActivityRecord activity = createActivityRecord(mDisplayContent, task); doReturn(true).when(task).shouldDeferRemoval(); diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java index 17303a4aa7e1..beaca68b9a37 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java @@ -29,11 +29,7 @@ import android.content.Context; import android.content.Intent; import android.hardware.soundtrigger.IRecognitionStatusCallback; import android.hardware.soundtrigger.SoundTrigger; -import android.media.AudioAttributes; import android.media.AudioFormat; -import android.media.AudioManager; -import android.media.AudioRecord; -import android.media.MediaRecorder; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; @@ -66,12 +62,16 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; +import java.time.Duration; +import java.time.Instant; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Function; /** * A class that provides the communication with the HotwordDetectionService. @@ -81,33 +81,38 @@ final class HotwordDetectionConnection { // TODO (b/177502877): Set the Debug flag to false before shipping. private static final boolean DEBUG = true; - // Number of bytes per sample of audio (which is a short). - private static final int BYTES_PER_SAMPLE = 2; // TODO: These constants need to be refined. private static final long VALIDATION_TIMEOUT_MILLIS = 3000; - private static final long VOICE_INTERACTION_TIMEOUT_TO_OPEN_MIC_MILLIS = 2000; - private static final int MAX_STREAMING_SECONDS = 10; - private static final int MICROPHONE_BUFFER_LENGTH_SECONDS = 8; - private static final int HOTWORD_AUDIO_LENGTH_SECONDS = 3; private static final long MAX_UPDATE_TIMEOUT_MILLIS = 6000; + private static final Duration MAX_UPDATE_TIMEOUT_DURATION = + Duration.ofMillis(MAX_UPDATE_TIMEOUT_MILLIS); private final Executor mAudioCopyExecutor = Executors.newCachedThreadPool(); // TODO: This may need to be a Handler(looper) private final ScheduledExecutorService mScheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); - private final AtomicBoolean mUpdateStateFinish = new AtomicBoolean(false); + private final AtomicBoolean mUpdateStateAfterStartFinished = new AtomicBoolean(false); + private final @NonNull ServiceConnectionFactory mServiceConnectionFactory; final Object mLock; final int mVoiceInteractionServiceUid; final ComponentName mDetectionComponentName; final int mUser; final Context mContext; - final @NonNull ServiceConnector<IHotwordDetectionService> mRemoteHotwordDetectionService; - boolean mBound; volatile HotwordDetectionServiceIdentity mIdentity; + private IHotwordRecognitionStatusCallback mCallback; + private IMicrophoneHotwordDetectionVoiceInteractionCallback mSoftwareCallback; + private Instant mLastRestartInstant; + + private ScheduledFuture<?> mCancellationTaskFuture; @GuardedBy("mLock") private ParcelFileDescriptor mCurrentAudioSink; + @GuardedBy("mLock") + private boolean mValidatingDspTrigger = false; + @GuardedBy("mLock") + private boolean mPerformingSoftwareHotwordDetection; + private @NonNull ServiceConnection mRemoteHotwordDetectionService; HotwordDetectionConnection(Object lock, Context context, int voiceInteractionServiceUid, ComponentName serviceName, int userId, boolean bindInstantServiceAllowed, @@ -121,50 +126,36 @@ final class HotwordDetectionConnection { final Intent intent = new Intent(HotwordDetectionService.SERVICE_INTERFACE); intent.setComponent(mDetectionComponentName); - mRemoteHotwordDetectionService = new ServiceConnector.Impl<IHotwordDetectionService>( - mContext, intent, bindInstantServiceAllowed ? Context.BIND_ALLOW_INSTANT : 0, mUser, - IHotwordDetectionService.Stub::asInterface) { - @Override // from ServiceConnector.Impl - protected void onServiceConnectionStatusChanged(IHotwordDetectionService service, - boolean connected) { - if (DEBUG) { - Slog.d(TAG, "onServiceConnectionStatusChanged connected = " + connected); - } - synchronized (mLock) { - mBound = connected; - } - } + mServiceConnectionFactory = new ServiceConnectionFactory(intent, bindInstantServiceAllowed); - @Override - protected long getAutoDisconnectTimeoutMs() { - return -1; - } + mRemoteHotwordDetectionService = mServiceConnectionFactory.create(); - @Override - public void binderDied() { - super.binderDied(); - Slog.w(TAG, "binderDied"); - try { - callback.onError(-1); - } catch (RemoteException e) { - Slog.w(TAG, "Failed to report onError status: " + e); - } - } - }; - mRemoteHotwordDetectionService.connect(); if (callback == null) { updateStateLocked(options, sharedMemory); return; } - updateAudioFlinger(); - updateContentCaptureManager(); - updateStateWithCallbackLocked(options, sharedMemory, callback); + mCallback = callback; + + mLastRestartInstant = Instant.now(); + updateStateAfterProcessStart(options, sharedMemory); + + // TODO(volnov): we need to be smarter here, e.g. schedule it a bit more often, but wait + // until the current session is closed. + mCancellationTaskFuture = mScheduledExecutorService.scheduleAtFixedRate(() -> { + if (DEBUG) { + Slog.i(TAG, "Time to restart the process, TTL has passed"); + } + + synchronized (mLock) { + restartProcessLocked(); + } + }, 30, 30, TimeUnit.MINUTES); } - private void updateStateWithCallbackLocked(PersistableBundle options, - SharedMemory sharedMemory, IHotwordRecognitionStatusCallback callback) { + private void updateStateAfterProcessStart( + PersistableBundle options, SharedMemory sharedMemory) { if (DEBUG) { - Slog.d(TAG, "updateStateWithCallbackLocked"); + Slog.d(TAG, "updateStateAfterProcessStart"); } mRemoteHotwordDetectionService.postAsync(service -> { AndroidFuture<Void> future = new AndroidFuture<>(); @@ -183,21 +174,21 @@ final class HotwordDetectionConnection { mIdentity = new HotwordDetectionServiceIdentity(uid, mVoiceInteractionServiceUid); future.complete(null); + if (mUpdateStateAfterStartFinished.getAndSet(true)) { + Slog.w(TAG, "call callback after timeout"); + return; + } + int status = bundle != null ? bundle.getInt( + KEY_INITIALIZATION_STATUS, + INITIALIZATION_STATUS_UNKNOWN) + : INITIALIZATION_STATUS_UNKNOWN; + // Add the protection to avoid unexpected status + if (status > HotwordDetectionService.getMaxCustomInitializationStatus() + && status != INITIALIZATION_STATUS_UNKNOWN) { + status = INITIALIZATION_STATUS_UNKNOWN; + } try { - if (mUpdateStateFinish.getAndSet(true)) { - Slog.w(TAG, "call callback after timeout"); - return; - } - int status = bundle != null ? bundle.getInt( - KEY_INITIALIZATION_STATUS, - INITIALIZATION_STATUS_UNKNOWN) - : INITIALIZATION_STATUS_UNKNOWN; - // Add the protection to avoid unexpected status - if (status > HotwordDetectionService.getMaxCustomInitializationStatus() - && status != INITIALIZATION_STATUS_UNKNOWN) { - status = INITIALIZATION_STATUS_UNKNOWN; - } - callback.onStatusReported(status); + mCallback.onStatusReported(status); } catch (RemoteException e) { Slog.w(TAG, "Failed to report initialization status: " + e); } @@ -214,13 +205,13 @@ final class HotwordDetectionConnection { .whenComplete((res, err) -> { if (err instanceof TimeoutException) { Slog.w(TAG, "updateState timed out"); + if (mUpdateStateAfterStartFinished.getAndSet(true)) { + return; + } try { - if (mUpdateStateFinish.getAndSet(true)) { - return; - } - callback.onStatusReported(INITIALIZATION_STATUS_UNKNOWN); + mCallback.onStatusReported(INITIALIZATION_STATUS_UNKNOWN); } catch (RemoteException e) { - Slog.w(TAG, "Failed to report initialization status: " + e); + Slog.w(TAG, "Failed to report initialization status UNKNOWN", e); } } else if (err != null) { Slog.w(TAG, "Failed to update state: " + err); @@ -230,27 +221,9 @@ final class HotwordDetectionConnection { }); } - private void updateAudioFlinger() { - // TODO: Consider using a proxy that limits the exposed API surface. - IBinder audioFlinger = ServiceManager.getService("media.audio_flinger"); - if (audioFlinger == null) { - throw new IllegalStateException("Service media.audio_flinger wasn't found."); - } - mRemoteHotwordDetectionService.post(service -> service.updateAudioFlinger(audioFlinger)); - } - - private void updateContentCaptureManager() { - IBinder b = ServiceManager - .getService(Context.CONTENT_CAPTURE_MANAGER_SERVICE); - IContentCaptureManager binderService = IContentCaptureManager.Stub.asInterface(b); - mRemoteHotwordDetectionService.post( - service -> service.updateContentCaptureManager(binderService, - new ContentCaptureOptions(null))); - } - private boolean isBound() { synchronized (mLock) { - return mBound; + return mRemoteHotwordDetectionService.isBound(); } } @@ -258,18 +231,25 @@ final class HotwordDetectionConnection { if (DEBUG) { Slog.d(TAG, "cancelLocked"); } - if (mBound) { + if (mRemoteHotwordDetectionService.isBound()) { mRemoteHotwordDetectionService.unbind(); - mBound = false; LocalServices.getService(PermissionManagerServiceInternal.class) .setHotwordDetectionServiceProvider(null); mIdentity = null; } + mCancellationTaskFuture.cancel(/* may interrupt */ true); } void updateStateLocked(PersistableBundle options, SharedMemory sharedMemory) { - mRemoteHotwordDetectionService.run( - service -> service.updateState(options, sharedMemory, null /* callback */)); + // Prevent doing the init late, so restart is handled equally to a clean process start. + // TODO(b/191742511): this logic needs a test + if (!mUpdateStateAfterStartFinished.get() + && Instant.now().minus(MAX_UPDATE_TIMEOUT_DURATION).isBefore(mLastRestartInstant)) { + updateStateAfterProcessStart(options, sharedMemory); + } else { + mRemoteHotwordDetectionService.run( + service -> service.updateState(options, sharedMemory, null /* callback */)); + } } void startListeningFromMic( @@ -278,7 +258,20 @@ final class HotwordDetectionConnection { if (DEBUG) { Slog.d(TAG, "startListeningFromMic"); } + mSoftwareCallback = callback; + + synchronized (mLock) { + if (mPerformingSoftwareHotwordDetection) { + Slog.i(TAG, "Hotword validation is already in progress, ignoring."); + return; + } + mPerformingSoftwareHotwordDetection = true; + + startListeningFromMicLocked(); + } + } + private void startListeningFromMicLocked() { // TODO: consider making this a non-anonymous class. IDspHotwordDetectionCallback internalCallback = new IDspHotwordDetectionCallback.Stub() { @Override @@ -286,15 +279,22 @@ final class HotwordDetectionConnection { if (DEBUG) { Slog.d(TAG, "onDetected"); } - callback.onDetected(result, null, null); + synchronized (mLock) { + if (mPerformingSoftwareHotwordDetection) { + mSoftwareCallback.onDetected(result, null, null); + mPerformingSoftwareHotwordDetection = false; + } else { + Slog.i(TAG, "Hotword detection has already completed"); + } + } } @Override public void onRejected(HotwordRejectedResult result) throws RemoteException { if (DEBUG) { - Slog.d(TAG, "onRejected"); + Slog.wtf(TAG, "onRejected"); } - // onRejected isn't allowed here + // onRejected isn't allowed here, and we are not expecting it. } }; @@ -315,6 +315,7 @@ final class HotwordDetectionConnection { if (DEBUG) { Slog.d(TAG, "startListeningFromExternalSource"); } + handleExternalSourceHotwordDetection( audioStream, audioFormat, @@ -326,16 +327,25 @@ final class HotwordDetectionConnection { if (DEBUG) { Slog.d(TAG, "stopListening"); } + synchronized (mLock) { + stopListeningLocked(); + } + } - mRemoteHotwordDetectionService.run(service -> service.stopDetection()); + private void stopListeningLocked() { + if (!mPerformingSoftwareHotwordDetection) { + Slog.i(TAG, "Hotword detection is not running"); + return; + } + mPerformingSoftwareHotwordDetection = false; - synchronized (mLock) { - if (mCurrentAudioSink != null) { - Slog.i(TAG, "Closing audio stream to hotword detector: stopping requested"); - bestEffortClose(mCurrentAudioSink); - } - mCurrentAudioSink = null; + mRemoteHotwordDetectionService.run(IHotwordDetectionService::stopDetection); + + if (mCurrentAudioSink != null) { + Slog.i(TAG, "Closing audio stream to hotword detector: stopping requested"); + bestEffortClose(mCurrentAudioSink); } + mCurrentAudioSink = null; } void triggerHardwareRecognitionEventForTestLocked( @@ -358,7 +368,14 @@ final class HotwordDetectionConnection { if (DEBUG) { Slog.d(TAG, "onDetected"); } - externalCallback.onKeyphraseDetected(recognitionEvent, result); + synchronized (mLock) { + if (mValidatingDspTrigger) { + mValidatingDspTrigger = false; + externalCallback.onKeyphraseDetected(recognitionEvent, result); + } else { + Slog.i(TAG, "Ignored hotword detected since trigger has been handled"); + } + } } @Override @@ -366,16 +383,26 @@ final class HotwordDetectionConnection { if (DEBUG) { Slog.d(TAG, "onRejected"); } - externalCallback.onRejected(result); + synchronized (mLock) { + if (mValidatingDspTrigger) { + mValidatingDspTrigger = false; + externalCallback.onRejected(result); + } else { + Slog.i(TAG, "Ignored hotword rejected since trigger has been handled"); + } + } } }; - mRemoteHotwordDetectionService.run( - service -> service.detectFromDspSource( - recognitionEvent, - recognitionEvent.getCaptureFormat(), - VALIDATION_TIMEOUT_MILLIS, - internalCallback)); + synchronized (mLock) { + mValidatingDspTrigger = true; + mRemoteHotwordDetectionService.run( + service -> service.detectFromDspSource( + recognitionEvent, + recognitionEvent.getCaptureFormat(), + VALIDATION_TIMEOUT_MILLIS, + internalCallback)); + } } private void detectFromDspSource(SoundTrigger.KeyphraseRecognitionEvent recognitionEvent, @@ -391,7 +418,14 @@ final class HotwordDetectionConnection { if (DEBUG) { Slog.d(TAG, "onDetected"); } - externalCallback.onKeyphraseDetected(recognitionEvent, result); + synchronized (mLock) { + if (!mValidatingDspTrigger) { + Slog.i(TAG, "Ignoring #onDetected due to a process restart"); + return; + } + mValidatingDspTrigger = false; + externalCallback.onKeyphraseDetected(recognitionEvent, result); + } } @Override @@ -399,16 +433,88 @@ final class HotwordDetectionConnection { if (DEBUG) { Slog.d(TAG, "onRejected"); } - externalCallback.onRejected(result); + synchronized (mLock) { + if (!mValidatingDspTrigger) { + Slog.i(TAG, "Ignoring #onRejected due to a process restart"); + return; + } + mValidatingDspTrigger = false; + externalCallback.onRejected(result); + } } }; - mRemoteHotwordDetectionService.run( - service -> service.detectFromDspSource( - recognitionEvent, - recognitionEvent.getCaptureFormat(), - VALIDATION_TIMEOUT_MILLIS, - internalCallback)); + synchronized (mLock) { + mValidatingDspTrigger = true; + mRemoteHotwordDetectionService.run( + service -> service.detectFromDspSource( + recognitionEvent, + recognitionEvent.getCaptureFormat(), + VALIDATION_TIMEOUT_MILLIS, + internalCallback)); + } + } + + void forceRestart() { + if (DEBUG) { + Slog.i(TAG, "Requested to restart the service internally. Performing the restart"); + } + synchronized (mLock) { + restartProcessLocked(); + } + } + + private void restartProcessLocked() { + if (DEBUG) { + Slog.i(TAG, "Restarting hotword detection process"); + } + + ServiceConnection oldConnection = mRemoteHotwordDetectionService; + + // TODO(volnov): this can be done after connect() has been successful. + if (mValidatingDspTrigger) { + // We're restarting the process while it's processing a DSP trigger, so report a + // rejection. This also allows the Interactor to startReco again + try { + mCallback.onRejected(new HotwordRejectedResult.Builder().build()); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to call #rejected"); + } + mValidatingDspTrigger = false; + } + + mUpdateStateAfterStartFinished.set(false); + mLastRestartInstant = Instant.now(); + + // Recreate connection to reset the cache. + mRemoteHotwordDetectionService = mServiceConnectionFactory.create(); + + if (DEBUG) { + Slog.i(TAG, "Started the new process, issuing #onProcessRestarted"); + } + try { + mCallback.onProcessRestarted(); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to communicate #onProcessRestarted", e); + } + + // Restart listening from microphone if the hotword process has been restarted. + if (mPerformingSoftwareHotwordDetection) { + Slog.i(TAG, "Process restarted: calling startRecognition() again"); + startListeningFromMicLocked(); + } + + if (mCurrentAudioSink != null) { + Slog.i(TAG, "Closing external audio stream to hotword detector: process restarted"); + bestEffortClose(mCurrentAudioSink); + mCurrentAudioSink = null; + } + + if (DEBUG) { + Slog.i(TAG, "#onProcessRestarted called, unbinding from the old process"); + } + oldConnection.ignoreConnectionStatusEvents(); + oldConnection.unbind(); } static final class SoundTriggerCallback extends IRecognitionStatusCallback.Stub { @@ -462,139 +568,13 @@ final class HotwordDetectionConnection { } } - // TODO: figure out if we need to let the client configure some of the parameters. - private static AudioRecord createAudioRecord( - @NonNull SoundTrigger.KeyphraseRecognitionEvent recognitionEvent) { - int sampleRate = recognitionEvent.getCaptureFormat().getSampleRate(); - return new AudioRecord( - new AudioAttributes.Builder() - .setInternalCapturePreset(MediaRecorder.AudioSource.HOTWORD).build(), - recognitionEvent.getCaptureFormat(), - getBufferSizeInBytes( - sampleRate, - MAX_STREAMING_SECONDS, - recognitionEvent.getCaptureFormat().getChannelCount()), - recognitionEvent.getCaptureSession()); - } - - @Nullable - private AudioRecord createMicAudioRecord(AudioFormat audioFormat) { - if (DEBUG) { - Slog.i(TAG, "#createAudioRecord"); - } - try { - AudioRecord audioRecord = new AudioRecord( - new AudioAttributes.Builder() - .setInternalCapturePreset(MediaRecorder.AudioSource.HOTWORD).build(), - audioFormat, - getBufferSizeInBytes( - audioFormat.getSampleRate(), - MICROPHONE_BUFFER_LENGTH_SECONDS, - audioFormat.getChannelCount()), - AudioManager.AUDIO_SESSION_ID_GENERATE); - - if (audioRecord.getState() != AudioRecord.STATE_INITIALIZED) { - Slog.w(TAG, "Failed to initialize AudioRecord"); - audioRecord.release(); - return null; - } - - return audioRecord; - } catch (IllegalArgumentException e) { - Slog.e(TAG, "Failed to create AudioRecord", e); - return null; - } - } - - @Nullable - private AudioRecord createFakeAudioRecord() { - if (DEBUG) { - Slog.i(TAG, "#createFakeAudioRecord"); - } - try { - AudioRecord audioRecord = new AudioRecord.Builder() - .setAudioFormat(new AudioFormat.Builder() - .setSampleRate(32000) - .setEncoding(AudioFormat.ENCODING_PCM_16BIT) - .setChannelMask(AudioFormat.CHANNEL_IN_MONO).build()) - .setAudioAttributes(new AudioAttributes.Builder() - .setInternalCapturePreset(MediaRecorder.AudioSource.HOTWORD).build()) - .setBufferSizeInBytes( - AudioRecord.getMinBufferSize(32000, - AudioFormat.CHANNEL_IN_MONO, - AudioFormat.ENCODING_PCM_16BIT) * 2) - .build(); - - if (audioRecord.getState() != AudioRecord.STATE_INITIALIZED) { - Slog.w(TAG, "Failed to initialize AudioRecord"); - audioRecord.release(); - return null; - } - return audioRecord; - } catch (IllegalArgumentException e) { - Slog.e(TAG, "Failed to create AudioRecord", e); - } - return null; - } - - /** - * Returns the number of bytes required to store {@code bufferLengthSeconds} of audio sampled at - * {@code sampleRate} Hz, using the format returned by DSP audio capture. - */ - private static int getBufferSizeInBytes( - int sampleRate, int bufferLengthSeconds, int intChannelCount) { - return BYTES_PER_SAMPLE * sampleRate * bufferLengthSeconds * intChannelCount; - } - - private static Pair<ParcelFileDescriptor, ParcelFileDescriptor> createPipe() { - ParcelFileDescriptor[] fileDescriptors; - try { - fileDescriptors = ParcelFileDescriptor.createPipe(); - } catch (IOException e) { - Slog.e(TAG, "Failed to create audio stream pipe", e); - return null; - } - - return Pair.create(fileDescriptors[0], fileDescriptors[1]); - } - public void dump(String prefix, PrintWriter pw) { - pw.print(prefix); pw.print("mBound="); pw.println(mBound); - } - - private interface AudioReader extends Closeable { - int read(byte[] dest, int offset, int length) throws IOException; - - static AudioReader createFromInputStream(InputStream is) { - return new AudioReader() { - @Override - public int read(byte[] dest, int offset, int length) throws IOException { - return is.read(dest, offset, length); - } - - @Override - public void close() throws IOException { - is.close(); - } - }; - } - - static AudioReader createFromAudioRecord(AudioRecord record) { - record.startRecording(); - - return new AudioReader() { - @Override - public int read(byte[] dest, int offset, int length) throws IOException { - return record.read(dest, offset, length); - } - - @Override - public void close() throws IOException { - record.stop(); - record.release(); - } - }; - } + pw.print(prefix); + pw.print("mBound=" + mRemoteHotwordDetectionService.isBound()); + pw.print(", mValidatingDspTrigger=" + mValidatingDspTrigger); + pw.print(", mPerformingSoftwareHotwordDetection=" + mPerformingSoftwareHotwordDetection); + pw.print(", mRestartCount=" + mServiceConnectionFactory.mRestartCount); + pw.println(", mLastRestartInstant=" + mLastRestartInstant); } private void handleExternalSourceHotwordDetection( @@ -605,8 +585,7 @@ final class HotwordDetectionConnection { if (DEBUG) { Slog.d(TAG, "#handleExternalSourceHotwordDetection"); } - AudioReader audioSource = AudioReader.createFromInputStream( - new ParcelFileDescriptor.AutoCloseInputStream(audioStream)); + InputStream audioSource = new ParcelFileDescriptor.AutoCloseInputStream(audioStream); Pair<ParcelFileDescriptor, ParcelFileDescriptor> clientPipe = createPipe(); if (clientPipe == null) { @@ -621,7 +600,7 @@ final class HotwordDetectionConnection { } mAudioCopyExecutor.execute(() -> { - try (AudioReader source = audioSource; + try (InputStream source = audioSource; OutputStream fos = new ParcelFileDescriptor.AutoCloseOutputStream(serviceAudioSink)) { @@ -681,6 +660,150 @@ final class HotwordDetectionConnection { })); } + private class ServiceConnectionFactory { + private final Intent mIntent; + private final int mBindingFlags; + + private int mRestartCount = 0; + + ServiceConnectionFactory(@NonNull Intent intent, boolean bindInstantServiceAllowed) { + mIntent = intent; + mBindingFlags = bindInstantServiceAllowed ? Context.BIND_ALLOW_INSTANT : 0; + } + + ServiceConnection create() { + ServiceConnection connection = + new ServiceConnection(mContext, mIntent, mBindingFlags, mUser, + IHotwordDetectionService.Stub::asInterface, ++mRestartCount); + connection.connect(); + + updateAudioFlinger(connection); + updateContentCaptureManager(connection); + return connection; + } + } + + private class ServiceConnection extends ServiceConnector.Impl<IHotwordDetectionService> { + private final Object mLock = new Object(); + + private final Intent mIntent; + private final int mBindingFlags; + private final int mInstanceNumber; + + private boolean mRespectServiceConnectionStatusChanged = true; + private boolean mIsBound = false; + + ServiceConnection(@NonNull Context context, + @NonNull Intent intent, int bindingFlags, int userId, + @Nullable Function<IBinder, IHotwordDetectionService> binderAsInterface, + int instanceNumber) { + super(context, intent, bindingFlags, userId, binderAsInterface); + this.mIntent = intent; + this.mBindingFlags = bindingFlags; + this.mInstanceNumber = instanceNumber; + } + + @Override // from ServiceConnector.Impl + protected void onServiceConnectionStatusChanged(IHotwordDetectionService service, + boolean connected) { + if (DEBUG) { + Slog.d(TAG, "onServiceConnectionStatusChanged connected = " + connected); + } + synchronized (mLock) { + if (!mRespectServiceConnectionStatusChanged) { + if (DEBUG) { + Slog.d(TAG, "Ignored onServiceConnectionStatusChanged event"); + } + return; + } + mIsBound = connected; + } + } + + @Override + protected long getAutoDisconnectTimeoutMs() { + return -1; + } + + @Override + public void binderDied() { + super.binderDied(); + synchronized (mLock) { + if (!mRespectServiceConnectionStatusChanged) { + if (DEBUG) { + Slog.d(TAG, "Ignored #binderDied event"); + } + return; + } + + Slog.w(TAG, "binderDied"); + try { + mCallback.onError(-1); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to report onError status: " + e); + } + } + } + + @Override + protected boolean bindService( + @NonNull android.content.ServiceConnection serviceConnection) { + try { + return mContext.bindIsolatedService( + mIntent, + Context.BIND_AUTO_CREATE | mBindingFlags, + "hotword_detector_" + mInstanceNumber, + mExecutor, + serviceConnection); + } catch (IllegalArgumentException e) { + Slog.wtf(TAG, "Can't bind to the hotword detection service!", e); + return false; + } + } + + boolean isBound() { + synchronized (mLock) { + return mIsBound; + } + } + + void ignoreConnectionStatusEvents() { + synchronized (mLock) { + mRespectServiceConnectionStatusChanged = false; + } + } + } + + private static Pair<ParcelFileDescriptor, ParcelFileDescriptor> createPipe() { + ParcelFileDescriptor[] fileDescriptors; + try { + fileDescriptors = ParcelFileDescriptor.createPipe(); + } catch (IOException e) { + Slog.e(TAG, "Failed to create audio stream pipe", e); + return null; + } + + return Pair.create(fileDescriptors[0], fileDescriptors[1]); + } + + private static void updateAudioFlinger(ServiceConnection connection) { + // TODO: Consider using a proxy that limits the exposed API surface. + IBinder audioFlinger = ServiceManager.getService("media.audio_flinger"); + if (audioFlinger == null) { + throw new IllegalStateException("Service media.audio_flinger wasn't found."); + } + connection.post(service -> service.updateAudioFlinger(audioFlinger)); + } + + private static void updateContentCaptureManager(ServiceConnection connection) { + IBinder b = ServiceManager + .getService(Context.CONTENT_CAPTURE_MANAGER_SERVICE); + IContentCaptureManager binderService = IContentCaptureManager.Stub.asInterface(b); + connection.post( + service -> service.updateContentCaptureManager(binderService, + new ContentCaptureOptions(null))); + } + private static void bestEffortClose(Closeable closeable) { try { closeable.close(); diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index bc812c2ae4a7..162acba8002d 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -795,6 +795,10 @@ public class VoiceInteractionManagerService extends SystemService { Settings.Secure.ASSISTANT, null, userHandle); } + void forceRestartHotwordDetector() { + mImpl.forceRestartHotwordDetector(); + } + @Override public void showSession(Bundle args, int flags) { synchronized (this) { diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java index ca30bc51e046..89c5a720ee7e 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java @@ -562,6 +562,14 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne && (serviceInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) == 0; } + void forceRestartHotwordDetector() { + if (mHotwordDetectionConnection == null) { + Slog.w(TAG, "Failed to force-restart hotword detection: no hotword detection active"); + return; + } + mHotwordDetectionConnection.forceRestart(); + } + public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) { if (!mValid) { pw.print(" NOT VALID: "); diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java index 2e3ca0157a3b..cdd8f7b91d9d 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java @@ -54,6 +54,8 @@ final class VoiceInteractionManagerServiceShellCommand extends ShellCommand { return requestHide(pw); case "disable": return requestDisable(pw); + case "restart-detection": + return requestRestartDetection(pw); default: return handleDefaultCommands(cmd); } @@ -74,6 +76,8 @@ final class VoiceInteractionManagerServiceShellCommand extends ShellCommand { pw.println(""); pw.println(" disable [true|false]"); pw.println(" Temporarily disable (when true) service"); + pw.println(" restart-detection"); + pw.println(" Force a restart of a hotword detection service"); pw.println(""); } } @@ -143,6 +147,16 @@ final class VoiceInteractionManagerServiceShellCommand extends ShellCommand { return 0; } + private int requestRestartDetection(PrintWriter pw) { + Slog.i(TAG, "requestRestartDetection()"); + try { + mService.forceRestartHotwordDetector(); + } catch (Exception e) { + return handleError(pw, "requestRestartDetection()", e); + } + return 0; + } + private static int handleError(PrintWriter pw, String message, Exception e) { Slog.e(TAG, "error calling " + message, e); pw.printf("Error calling %s: %s\n", message, e); diff --git a/tests/Internal/src/android/app/WallpaperColorsTest.java b/tests/Internal/src/android/app/WallpaperColorsTest.java index 45d3dade82b6..9ffb236d3f59 100644 --- a/tests/Internal/src/android/app/WallpaperColorsTest.java +++ b/tests/Internal/src/android/app/WallpaperColorsTest.java @@ -20,6 +20,7 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; +import android.os.Parcel; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -106,4 +107,26 @@ public class WallpaperColorsTest { // This would crash: canvas.drawBitmap(image, 0, 0, new Paint()); } + + /** + * Parcelled WallpaperColors object should equal the original. + */ + @Test + public void testParcelUnparcel() { + Bitmap image = Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888); + WallpaperColors colors = WallpaperColors.fromBitmap(image); + Parcel parcel = Parcel.obtain(); + colors.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + WallpaperColors reconstructed = new WallpaperColors(parcel); + parcel.recycle(); + Assert.assertEquals("WallpaperColors recreated from Parcel should equal original", + colors, reconstructed); + Assert.assertEquals("getAllColors() on WallpaperColors recreated from Parcel should" + + "return the same as the original", + colors.getAllColors(), reconstructed.getAllColors()); + Assert.assertEquals("getMainColors() on WallpaperColors recreated from Parcel should" + + "return the same as the original", + colors.getMainColors(), reconstructed.getMainColors()); + } } diff --git a/tests/vcn/java/com/android/server/vcn/VcnTest.java b/tests/vcn/java/com/android/server/vcn/VcnTest.java index f681ee19ab12..5d2f9d748581 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnTest.java @@ -242,6 +242,27 @@ public class VcnTest { verifyUpdateSubscriptionSnapshotNotifiesGatewayConnections(VCN_STATUS_CODE_SAFE_MODE); } + @Test + public void testSubscriptionSnapshotUpdatesMobileDataState() { + final NetworkRequestListener requestListener = verifyAndGetRequestListener(); + startVcnGatewayWithCapabilities(requestListener, TEST_CAPS[0]); + + // Expect mobile data enabled from setUp() + assertTrue(mVcn.isMobileDataEnabled()); + + final TelephonySubscriptionSnapshot updatedSnapshot = + mock(TelephonySubscriptionSnapshot.class); + doReturn(TEST_SUB_IDS_IN_GROUP) + .when(updatedSnapshot) + .getAllSubIdsInGroup(eq(TEST_SUB_GROUP)); + doReturn(false).when(mTelephonyManager).isDataEnabled(); + + mVcn.updateSubscriptionSnapshot(updatedSnapshot); + mTestLooper.dispatchAll(); + + assertFalse(mVcn.isMobileDataEnabled()); + } + private void triggerVcnRequestListeners(NetworkRequestListener requestListener) { for (final int[] caps : TEST_CAPS) { startVcnGatewayWithCapabilities(requestListener, caps); |