diff options
248 files changed, 4820 insertions, 1536 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/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java index 0e9efbcc98b8..ac2018707c75 100644 --- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java +++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java @@ -442,6 +442,7 @@ public class DeviceIdleController extends SystemService private long mNextIdlePendingDelay; private long mNextIdleDelay; private long mNextLightIdleDelay; + private long mNextLightIdleDelayFlex; private long mNextLightAlarmTime; private long mNextSensingTimeoutAlarmTime; @@ -886,16 +887,20 @@ public class DeviceIdleController extends SystemService */ public final class Constants implements DeviceConfig.OnPropertiesChangedListener { // Key names stored in the settings value. - private static final String KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT - = "light_after_inactive_to"; + private static final String KEY_FLEX_TIME_SHORT = "flex_time_short"; + private static final String KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT = + "light_after_inactive_to"; private static final String KEY_LIGHT_PRE_IDLE_TIMEOUT = "light_pre_idle_to"; private static final String KEY_LIGHT_IDLE_TIMEOUT = "light_idle_to"; + private static final String KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX = + "light_idle_to_initial_flex"; + private static final String KEY_LIGHT_MAX_IDLE_TIMEOUT_FLEX = "light_max_idle_to_flex"; private static final String KEY_LIGHT_IDLE_FACTOR = "light_idle_factor"; private static final String KEY_LIGHT_MAX_IDLE_TIMEOUT = "light_max_idle_to"; - private static final String KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET - = "light_idle_maintenance_min_budget"; - private static final String KEY_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET - = "light_idle_maintenance_max_budget"; + private static final String KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET = + "light_idle_maintenance_min_budget"; + private static final String KEY_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET = + "light_idle_maintenance_max_budget"; private static final String KEY_MIN_LIGHT_MAINTENANCE_TIME = "min_light_maintenance_time"; private static final String KEY_MIN_DEEP_MAINTENANCE_TIME = "min_deep_maintenance_time"; private static final String KEY_INACTIVE_TIMEOUT = "inactive_to"; @@ -903,6 +908,7 @@ public class DeviceIdleController extends SystemService private static final String KEY_LOCATING_TIMEOUT = "locating_to"; private static final String KEY_LOCATION_ACCURACY = "location_accuracy"; private static final String KEY_MOTION_INACTIVE_TIMEOUT = "motion_inactive_to"; + private static final String KEY_MOTION_INACTIVE_TIMEOUT_FLEX = "motion_inactive_to_flex"; private static final String KEY_IDLE_AFTER_INACTIVE_TIMEOUT = "idle_after_inactive_to"; private static final String KEY_IDLE_PENDING_TIMEOUT = "idle_pending_to"; private static final String KEY_MAX_IDLE_PENDING_TIMEOUT = "max_idle_pending_to"; @@ -929,13 +935,20 @@ public class DeviceIdleController extends SystemService "pre_idle_factor_long"; private static final String KEY_PRE_IDLE_FACTOR_SHORT = "pre_idle_factor_short"; + private static final String KEY_USE_WINDOW_ALARMS = "use_window_alarms"; + private static final long DEFAULT_FLEX_TIME_SHORT = + !COMPRESS_TIME ? 60 * 1000L : 5 * 1000L; private static final long DEFAULT_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT = - !COMPRESS_TIME ? 3 * 60 * 1000L : 15 * 1000L; + !COMPRESS_TIME ? 60 * 1000L : 15 * 1000L; private static final long DEFAULT_LIGHT_PRE_IDLE_TIMEOUT = !COMPRESS_TIME ? 3 * 60 * 1000L : 30 * 1000L; private static final long DEFAULT_LIGHT_IDLE_TIMEOUT = !COMPRESS_TIME ? 5 * 60 * 1000L : 15 * 1000L; + private static final long DEFAULT_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX = + !COMPRESS_TIME ? 60 * 1000L : 5 * 1000L; + private static final long DEFAULT_LIGHT_MAX_IDLE_TIMEOUT_FLEX = + !COMPRESS_TIME ? 15 * 60 * 1000L : 60 * 1000L; private static final float DEFAULT_LIGHT_IDLE_FACTOR = 2f; private static final long DEFAULT_LIGHT_MAX_IDLE_TIMEOUT = !COMPRESS_TIME ? 15 * 60 * 1000L : 60 * 1000L; @@ -958,6 +971,8 @@ public class DeviceIdleController extends SystemService private static final float DEFAULT_LOCATION_ACCURACY = 20f; private static final long DEFAULT_MOTION_INACTIVE_TIMEOUT = !COMPRESS_TIME ? 10 * 60 * 1000L : 60 * 1000L; + private static final long DEFAULT_MOTION_INACTIVE_TIMEOUT_FLEX = + !COMPRESS_TIME ? 60 * 1000L : 5 * 1000L; private static final long DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT = (30 * 60 * 1000L) / (!COMPRESS_TIME ? 1 : 10); private static final long DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT_SMALL_BATTERY = @@ -983,6 +998,14 @@ public class DeviceIdleController extends SystemService private static final boolean DEFAULT_WAIT_FOR_UNLOCK = true; private static final float DEFAULT_PRE_IDLE_FACTOR_LONG = 1.67f; private static final float DEFAULT_PRE_IDLE_FACTOR_SHORT = .33f; + private static final boolean DEFAULT_USE_WINDOW_ALARMS = true; + + /** + * A somewhat short alarm window size that we will tolerate for various alarm timings. + * + * @see #KEY_FLEX_TIME_SHORT + */ + public long FLEX_TIME_SHORT = DEFAULT_FLEX_TIME_SHORT; /** * This is the time, after becoming inactive, that we go in to the first @@ -1002,13 +1025,28 @@ public class DeviceIdleController extends SystemService public long LIGHT_PRE_IDLE_TIMEOUT = DEFAULT_LIGHT_PRE_IDLE_TIMEOUT; /** - * This is the initial time that we will run in idle maintenance mode. + * This is the initial time that we will run in light idle maintenance mode. * * @see #KEY_LIGHT_IDLE_TIMEOUT */ public long LIGHT_IDLE_TIMEOUT = DEFAULT_LIGHT_IDLE_TIMEOUT; /** + * This is the initial alarm window size that we will tolerate for light idle maintenance + * timing. + * + * @see #KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX + */ + public long LIGHT_IDLE_TIMEOUT_INITIAL_FLEX = DEFAULT_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX; + + /** + * This is the maximum value that {@link #LIGHT_IDLE_TIMEOUT_INITIAL_FLEX} should take. + * + * @see #KEY_LIGHT_MAX_IDLE_TIMEOUT_FLEX + */ + public long LIGHT_MAX_IDLE_TIMEOUT_FLEX = DEFAULT_LIGHT_MAX_IDLE_TIMEOUT_FLEX; + + /** * Scaling factor to apply to the light idle mode time each time we complete a cycle. * * @see #KEY_LIGHT_IDLE_FACTOR @@ -1016,7 +1054,7 @@ public class DeviceIdleController extends SystemService public float LIGHT_IDLE_FACTOR = DEFAULT_LIGHT_IDLE_FACTOR; /** - * This is the maximum time we will run in idle maintenance mode. + * This is the maximum time we will stay in light idle mode. * * @see #KEY_LIGHT_MAX_IDLE_TIMEOUT */ @@ -1099,13 +1137,22 @@ public class DeviceIdleController extends SystemService /** * This is the time, after seeing motion, that we wait after becoming inactive from * that until we start looking for motion again. + * * @see #KEY_MOTION_INACTIVE_TIMEOUT */ public long MOTION_INACTIVE_TIMEOUT = DEFAULT_MOTION_INACTIVE_TIMEOUT; /** + * This is the alarm window size we will tolerate for motion detection timings. + * + * @see #KEY_MOTION_INACTIVE_TIMEOUT_FLEX + */ + public long MOTION_INACTIVE_TIMEOUT_FLEX = DEFAULT_MOTION_INACTIVE_TIMEOUT_FLEX; + + /** * This is the time, after the inactive timeout elapses, that we will wait looking * for motion until we truly consider the device to be idle. + * * @see #KEY_IDLE_AFTER_INACTIVE_TIMEOUT */ public long IDLE_AFTER_INACTIVE_TIMEOUT = DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT; @@ -1204,6 +1251,12 @@ public class DeviceIdleController extends SystemService public boolean WAIT_FOR_UNLOCK = DEFAULT_WAIT_FOR_UNLOCK; + /** + * Whether to use window alarms. True to use window alarms (call AlarmManager.setWindow()). + * False to use the legacy inexact alarms (call AlarmManager.set()). + */ + public boolean USE_WINDOW_ALARMS = DEFAULT_USE_WINDOW_ALARMS; + private final boolean mSmallBatteryDevice; public Constants() { @@ -1227,6 +1280,10 @@ public class DeviceIdleController extends SystemService continue; } switch (name) { + case KEY_FLEX_TIME_SHORT: + FLEX_TIME_SHORT = properties.getLong( + KEY_FLEX_TIME_SHORT, DEFAULT_FLEX_TIME_SHORT); + break; case KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT: LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT = properties.getLong( KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT, @@ -1240,9 +1297,19 @@ public class DeviceIdleController extends SystemService LIGHT_IDLE_TIMEOUT = properties.getLong( KEY_LIGHT_IDLE_TIMEOUT, DEFAULT_LIGHT_IDLE_TIMEOUT); break; + case KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX: + LIGHT_IDLE_TIMEOUT_INITIAL_FLEX = properties.getLong( + KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX, + DEFAULT_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX); + break; + case KEY_LIGHT_MAX_IDLE_TIMEOUT_FLEX: + LIGHT_MAX_IDLE_TIMEOUT_FLEX = properties.getLong( + KEY_LIGHT_MAX_IDLE_TIMEOUT_FLEX, + DEFAULT_LIGHT_MAX_IDLE_TIMEOUT_FLEX); + break; case KEY_LIGHT_IDLE_FACTOR: - LIGHT_IDLE_FACTOR = properties.getFloat( - KEY_LIGHT_IDLE_FACTOR, DEFAULT_LIGHT_IDLE_FACTOR); + LIGHT_IDLE_FACTOR = Math.max(1, properties.getFloat( + KEY_LIGHT_IDLE_FACTOR, DEFAULT_LIGHT_IDLE_FACTOR)); break; case KEY_LIGHT_MAX_IDLE_TIMEOUT: LIGHT_MAX_IDLE_TIMEOUT = properties.getLong( @@ -1291,6 +1358,11 @@ public class DeviceIdleController extends SystemService MOTION_INACTIVE_TIMEOUT = properties.getLong( KEY_MOTION_INACTIVE_TIMEOUT, DEFAULT_MOTION_INACTIVE_TIMEOUT); break; + case KEY_MOTION_INACTIVE_TIMEOUT_FLEX: + MOTION_INACTIVE_TIMEOUT_FLEX = properties.getLong( + KEY_MOTION_INACTIVE_TIMEOUT_FLEX, + DEFAULT_MOTION_INACTIVE_TIMEOUT_FLEX); + break; case KEY_IDLE_AFTER_INACTIVE_TIMEOUT: final long defaultIdleAfterInactiveTimeout = mSmallBatteryDevice ? DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT_SMALL_BATTERY @@ -1362,6 +1434,10 @@ public class DeviceIdleController extends SystemService PRE_IDLE_FACTOR_SHORT = properties.getFloat( KEY_PRE_IDLE_FACTOR_SHORT, DEFAULT_PRE_IDLE_FACTOR_SHORT); break; + case KEY_USE_WINDOW_ALARMS: + USE_WINDOW_ALARMS = properties.getBoolean( + KEY_USE_WINDOW_ALARMS, DEFAULT_USE_WINDOW_ALARMS); + break; default: Slog.e(TAG, "Unknown configuration key: " + name); break; @@ -1373,6 +1449,10 @@ public class DeviceIdleController extends SystemService void dump(PrintWriter pw) { pw.println(" Settings:"); + pw.print(" "); pw.print(KEY_FLEX_TIME_SHORT); pw.print("="); + TimeUtils.formatDuration(FLEX_TIME_SHORT, pw); + pw.println(); + pw.print(" "); pw.print(KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT); pw.print("="); @@ -1387,6 +1467,14 @@ public class DeviceIdleController extends SystemService TimeUtils.formatDuration(LIGHT_IDLE_TIMEOUT, pw); pw.println(); + pw.print(" "); pw.print(KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX); pw.print("="); + TimeUtils.formatDuration(LIGHT_IDLE_TIMEOUT_INITIAL_FLEX, pw); + pw.println(); + + pw.print(" "); pw.print(KEY_LIGHT_MAX_IDLE_TIMEOUT_FLEX); pw.print("="); + TimeUtils.formatDuration(LIGHT_MAX_IDLE_TIMEOUT_FLEX, pw); + pw.println(); + pw.print(" "); pw.print(KEY_LIGHT_IDLE_FACTOR); pw.print("="); pw.print(LIGHT_IDLE_FACTOR); pw.println(); @@ -1431,6 +1519,10 @@ public class DeviceIdleController extends SystemService TimeUtils.formatDuration(MOTION_INACTIVE_TIMEOUT, pw); pw.println(); + pw.print(" "); pw.print(KEY_MOTION_INACTIVE_TIMEOUT_FLEX); pw.print("="); + TimeUtils.formatDuration(MOTION_INACTIVE_TIMEOUT_FLEX, pw); + pw.println(); + pw.print(" "); pw.print(KEY_IDLE_AFTER_INACTIVE_TIMEOUT); pw.print("="); TimeUtils.formatDuration(IDLE_AFTER_INACTIVE_TIMEOUT, pw); pw.println(); @@ -1489,6 +1581,9 @@ public class DeviceIdleController extends SystemService pw.print(" "); pw.print(KEY_PRE_IDLE_FACTOR_SHORT); pw.print("="); pw.println(PRE_IDLE_FACTOR_SHORT); + + pw.print(" "); pw.print(KEY_USE_WINDOW_ALARMS); pw.print("="); + pw.println(USE_WINDOW_ALARMS); } } @@ -3199,7 +3294,8 @@ public class DeviceIdleController extends SystemService mLightState = LIGHT_STATE_INACTIVE; if (DEBUG) Slog.d(TAG, "Moved from LIGHT_STATE_ACTIVE to LIGHT_STATE_INACTIVE"); resetLightIdleManagementLocked(); - scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT); + scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT, + mConstants.FLEX_TIME_SHORT); EventLogTags.writeDeviceIdleLight(mLightState, "no activity"); } } @@ -3219,6 +3315,7 @@ public class DeviceIdleController extends SystemService private void resetLightIdleManagementLocked() { mNextLightIdleDelay = 0; + mNextLightIdleDelayFlex = 0; mCurLightIdleBudget = 0; cancelLightAlarmLocked(); } @@ -3265,13 +3362,15 @@ public class DeviceIdleController extends SystemService mCurLightIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET; // Reset the upcoming idle delays. mNextLightIdleDelay = mConstants.LIGHT_IDLE_TIMEOUT; + mNextLightIdleDelayFlex = mConstants.LIGHT_IDLE_TIMEOUT_INITIAL_FLEX; mMaintenanceStartTime = 0; if (!isOpsInactiveLocked()) { // We have some active ops going on... give them a chance to finish // before going in to our first idle. mLightState = LIGHT_STATE_PRE_IDLE; EventLogTags.writeDeviceIdleLight(mLightState, reason); - scheduleLightAlarmLocked(mConstants.LIGHT_PRE_IDLE_TIMEOUT); + scheduleLightAlarmLocked(mConstants.LIGHT_PRE_IDLE_TIMEOUT, + mConstants.FLEX_TIME_SHORT); break; } // Nothing active, fall through to immediately idle. @@ -3290,12 +3389,11 @@ public class DeviceIdleController extends SystemService } } mMaintenanceStartTime = 0; - scheduleLightAlarmLocked(mNextLightIdleDelay); + scheduleLightAlarmLocked(mNextLightIdleDelay, mNextLightIdleDelayFlex); mNextLightIdleDelay = Math.min(mConstants.LIGHT_MAX_IDLE_TIMEOUT, - (long)(mNextLightIdleDelay * mConstants.LIGHT_IDLE_FACTOR)); - if (mNextLightIdleDelay < mConstants.LIGHT_IDLE_TIMEOUT) { - mNextLightIdleDelay = mConstants.LIGHT_IDLE_TIMEOUT; - } + (long) (mNextLightIdleDelay * mConstants.LIGHT_IDLE_FACTOR)); + mNextLightIdleDelayFlex = Math.min(mConstants.LIGHT_MAX_IDLE_TIMEOUT_FLEX, + (long) (mNextLightIdleDelayFlex * mConstants.LIGHT_IDLE_FACTOR)); if (DEBUG) Slog.d(TAG, "Moved to LIGHT_STATE_IDLE."); mLightState = LIGHT_STATE_IDLE; EventLogTags.writeDeviceIdleLight(mLightState, reason); @@ -3315,7 +3413,7 @@ public class DeviceIdleController extends SystemService } else if (mCurLightIdleBudget > mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET) { mCurLightIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET; } - scheduleLightAlarmLocked(mCurLightIdleBudget); + scheduleLightAlarmLocked(mCurLightIdleBudget, mConstants.FLEX_TIME_SHORT); if (DEBUG) Slog.d(TAG, "Moved from LIGHT_STATE_IDLE to LIGHT_STATE_IDLE_MAINTENANCE."); mLightState = LIGHT_STATE_IDLE_MAINTENANCE; @@ -3326,7 +3424,7 @@ public class DeviceIdleController extends SystemService // We'd like to do maintenance, but currently don't have network // connectivity... let's try to wait until the network comes back. // We'll only wait for another full idle period, however, and then give up. - scheduleLightAlarmLocked(mNextLightIdleDelay); + scheduleLightAlarmLocked(mNextLightIdleDelay, mNextLightIdleDelayFlex / 2); if (DEBUG) Slog.d(TAG, "Moved to LIGHT_WAITING_FOR_NETWORK."); mLightState = LIGHT_STATE_WAITING_FOR_NETWORK; EventLogTags.writeDeviceIdleLight(mLightState, reason); @@ -3844,40 +3942,75 @@ public class DeviceIdleController extends SystemService mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP, mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler); } else { - mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, - mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler); + if (mConstants.USE_WINDOW_ALARMS) { + mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP, + mConstants.FLEX_TIME_SHORT, + mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler); + } else { + mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, + mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler); + } } } - void scheduleLightAlarmLocked(long delay) { - if (DEBUG) Slog.d(TAG, "scheduleLightAlarmLocked(" + delay + ")"); + void scheduleLightAlarmLocked(long delay, long flex) { + if (DEBUG) { + Slog.d(TAG, "scheduleLightAlarmLocked(" + delay + + (mConstants.USE_WINDOW_ALARMS ? "/" + flex : "") + ")"); + } mNextLightAlarmTime = SystemClock.elapsedRealtime() + delay; - mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, - mNextLightAlarmTime, "DeviceIdleController.light", mLightAlarmListener, mHandler); + if (mConstants.USE_WINDOW_ALARMS) { + mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP, mNextLightAlarmTime, flex, + "DeviceIdleController.light", mLightAlarmListener, mHandler); + } else { + mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, mNextLightAlarmTime, + "DeviceIdleController.light", mLightAlarmListener, mHandler); + } } private void scheduleMotionRegistrationAlarmLocked() { if (DEBUG) Slog.d(TAG, "scheduleMotionRegistrationAlarmLocked"); long nextMotionRegistrationAlarmTime = mInjector.getElapsedRealtime() + mConstants.MOTION_INACTIVE_TIMEOUT / 2; - mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextMotionRegistrationAlarmTime, - "DeviceIdleController.motion_registration", mMotionRegistrationAlarmListener, - mHandler); + if (mConstants.USE_WINDOW_ALARMS) { + mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP, + nextMotionRegistrationAlarmTime, mConstants.MOTION_INACTIVE_TIMEOUT_FLEX, + "DeviceIdleController.motion_registration", mMotionRegistrationAlarmListener, + mHandler); + } else { + mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextMotionRegistrationAlarmTime, + "DeviceIdleController.motion_registration", mMotionRegistrationAlarmListener, + mHandler); + } } private void scheduleMotionTimeoutAlarmLocked() { if (DEBUG) Slog.d(TAG, "scheduleMotionAlarmLocked"); long nextMotionTimeoutAlarmTime = mInjector.getElapsedRealtime() + mConstants.MOTION_INACTIVE_TIMEOUT; - mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextMotionTimeoutAlarmTime, - "DeviceIdleController.motion", mMotionTimeoutAlarmListener, mHandler); + if (mConstants.USE_WINDOW_ALARMS) { + mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP, + nextMotionTimeoutAlarmTime, + mConstants.MOTION_INACTIVE_TIMEOUT_FLEX, + "DeviceIdleController.motion", mMotionTimeoutAlarmListener, mHandler); + } else { + mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextMotionTimeoutAlarmTime, + "DeviceIdleController.motion", mMotionTimeoutAlarmListener, mHandler); + } } void scheduleSensingTimeoutAlarmLocked(long delay) { if (DEBUG) Slog.d(TAG, "scheduleSensingAlarmLocked(" + delay + ")"); mNextSensingTimeoutAlarmTime = SystemClock.elapsedRealtime() + delay; - mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, mNextSensingTimeoutAlarmTime, - "DeviceIdleController.sensing", mSensingTimeoutAlarmListener, mHandler); + if (mConstants.USE_WINDOW_ALARMS) { + mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP, + mNextSensingTimeoutAlarmTime, + mConstants.FLEX_TIME_SHORT, + "DeviceIdleController.sensing", mSensingTimeoutAlarmListener, mHandler); + } else { + mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, mNextSensingTimeoutAlarmTime, + "DeviceIdleController.sensing", mSensingTimeoutAlarmListener, mHandler); + } } private static int[] buildAppIdArray(ArrayMap<String, Integer> systemApps, @@ -4852,7 +4985,13 @@ public class DeviceIdleController extends SystemService if (mNextLightIdleDelay != 0) { pw.print(" mNextIdleDelay="); TimeUtils.formatDuration(mNextLightIdleDelay, pw); - pw.println(); + if (mConstants.USE_WINDOW_ALARMS) { + pw.print(" (flex="); + TimeUtils.formatDuration(mNextLightIdleDelayFlex, pw); + pw.println(")"); + } else { + pw.println(); + } } if (mNextLightAlarmTime != 0) { pw.print(" mNextLightAlarmTime="); 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/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/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/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/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/net/VpnManager.java b/core/java/android/net/VpnManager.java index 662ebb356f4c..5c2855307509 100644 --- a/core/java/android/net/VpnManager.java +++ b/core/java/android/net/VpnManager.java @@ -389,6 +389,10 @@ public class VpnManager { /** * Starts a legacy VPN. + * + * Legacy VPN is deprecated starting from Android S. So this API shouldn't be called if the + * initial SDK version of device is Android S+. Otherwise, UnsupportedOperationException will be + * thrown. * @hide */ public void startLegacyVpn(VpnProfile profile) { 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/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/contentcapture/ContentCaptureEvent.java b/core/java/android/view/contentcapture/ContentCaptureEvent.java index 10ae69118f54..ce6d034c585e 100644 --- a/core/java/android/view/contentcapture/ContentCaptureEvent.java +++ b/core/java/android/view/contentcapture/ContentCaptureEvent.java @@ -286,6 +286,15 @@ public final class ContentCaptureEvent implements Parcelable { return this; } + boolean hasSameComposingSpan(@NonNull ContentCaptureEvent other) { + return mComposingStart == other.mComposingStart && mComposingEnd == other.mComposingEnd; + } + + boolean hasSameSelectionSpan(@NonNull ContentCaptureEvent other) { + return mSelectionStartIndex == other.mSelectionStartIndex + && mSelectionEndIndex == other.mSelectionEndIndex; + } + private int getComposingStart() { return mComposingStart; } diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java index bcb914208958..7ec9d34bd364 100644 --- a/core/java/android/view/contentcapture/MainContentCaptureSession.java +++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java @@ -368,7 +368,10 @@ public final class MainContentCaptureSession extends ContentCaptureSession { final CharSequence lastText = lastEvent.getText(); final boolean bothNonEmpty = !TextUtils.isEmpty(lastText) && !TextUtils.isEmpty(text); - boolean equalContent = TextUtils.equals(lastText, text); + boolean equalContent = + TextUtils.equals(lastText, text) + && lastEvent.hasSameComposingSpan(event) + && lastEvent.hasSameSelectionSpan(event); if (equalContent) { addEvent = false; } else if (bothNonEmpty) { diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java index bdd12063e6cf..c4540b0d8726 100644 --- a/core/java/android/view/inputmethod/BaseInputConnection.java +++ b/core/java/android/view/inputmethod/BaseInputConnection.java @@ -163,6 +163,17 @@ public class BaseInputConnection implements InputConnection { } /** + * Called after only the composing region is modified (so it isn't called if the text also + * changes). + * <p> + * Default implementation does nothing. + * + * @hide + */ + public void endComposingRegionEditInternal() { + } + + /** * Default implementation calls {@link #finishComposingText()} and * {@code setImeConsumesInput(false)}. */ @@ -468,6 +479,7 @@ public class BaseInputConnection implements InputConnection { // Note: sendCurrentText does nothing unless mFallbackMode is set sendCurrentText(); endBatchEdit(); + endComposingRegionEditInternal(); } return true; } @@ -734,6 +746,7 @@ public class BaseInputConnection implements InputConnection { // Note: sendCurrentText does nothing unless mFallbackMode is set sendCurrentText(); endBatchEdit(); + endComposingRegionEditInternal(); } return true; } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 3c4fd5e93580..cd560d75d913 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -10832,11 +10832,19 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } + notifyContentCaptureTextChanged(); + } + + /** + * Notifies the ContentCapture service that the text of the view has changed (only if + * ContentCapture has been notified of this view's existence already). + * + * @hide + */ + public void notifyContentCaptureTextChanged() { // TODO(b/121045053): should use a flag / boolean to keep status of SHOWN / HIDDEN instead // of using isLaidout(), so it's not called in cases where it's laid out but a // notifyAppeared was not sent. - - // ContentCapture if (isLaidOut() && isImportantForContentCapture() && getNotifiedContentCaptureAppeared()) { final ContentCaptureManager cm = mContext.getSystemService(ContentCaptureManager.class); if (cm != null && cm.isContentCaptureEnabled()) { 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/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/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java index 3d054a5e773c..02ffe8c5268e 100644 --- a/core/java/com/android/internal/widget/EditableInputConnection.java +++ b/core/java/com/android/internal/widget/EditableInputConnection.java @@ -99,6 +99,12 @@ public class EditableInputConnection extends BaseInputConnection } @Override + public void endComposingRegionEditInternal() { + // The ContentCapture service is interested in Composing-state changes. + mTextView.notifyContentCaptureTextChanged(); + } + + @Override public void closeConnection() { super.closeConnection(); synchronized(this) { diff --git a/core/java/com/android/server/AppWidgetBackupBridge.java b/core/java/com/android/server/AppWidgetBackupBridge.java index 7d82d355e3eb..8e834a87784d 100644 --- a/core/java/com/android/server/AppWidgetBackupBridge.java +++ b/core/java/com/android/server/AppWidgetBackupBridge.java @@ -47,9 +47,9 @@ public class AppWidgetBackupBridge { : null; } - public static void restoreStarting(int userId) { + public static void systemRestoreStarting(int userId) { if (sAppWidgetService != null) { - sAppWidgetService.restoreStarting(userId); + sAppWidgetService.systemRestoreStarting(userId); } } @@ -59,9 +59,9 @@ public class AppWidgetBackupBridge { } } - public static void restoreFinished(int userId) { + public static void systemRestoreFinished(int userId) { if (sAppWidgetService != null) { - sAppWidgetService.restoreFinished(userId); + sAppWidgetService.systemRestoreFinished(userId); } } } diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java index bd0de2984b7f..a8dcbaffeeb5 100644 --- a/core/java/com/android/server/SystemConfig.java +++ b/core/java/com/android/server/SystemConfig.java @@ -86,6 +86,7 @@ public class SystemConfig { // and "allow-ignore-location-settings". private static final int ALLOW_OVERRIDE_APP_RESTRICTIONS = 0x100; private static final int ALLOW_IMPLICIT_BROADCASTS = 0x200; + private static final int ALLOW_VENDOR_APEX = 0x400; private static final int ALLOW_ALL = ~0; // property for runtime configuration differentiation @@ -240,6 +241,7 @@ public class SystemConfig { private final ArraySet<String> mRollbackWhitelistedPackages = new ArraySet<>(); private final ArraySet<String> mWhitelistedStagedInstallers = new ArraySet<>(); + private final ArraySet<String> mAllowedVendorApexes = new ArraySet<>(); /** * Map of system pre-defined, uniquely named actors; keys are namespace, @@ -410,6 +412,10 @@ public class SystemConfig { return mWhitelistedStagedInstallers; } + public Set<String> getAllowedVendorApexes() { + return mAllowedVendorApexes; + } + public ArraySet<String> getAppDataIsolationWhitelistedApps() { return mAppDataIsolationWhitelistedApps; } @@ -484,7 +490,7 @@ public class SystemConfig { // Vendors are only allowed to customize these int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS - | ALLOW_ASSOCIATIONS; + | ALLOW_ASSOCIATIONS | ALLOW_VENDOR_APEX; if (Build.VERSION.DEVICE_INITIAL_SDK_INT <= Build.VERSION_CODES.O_MR1) { // For backward compatibility vendorPermissionFlag |= (ALLOW_PERMISSIONS | ALLOW_APP_CONFIGS); @@ -525,7 +531,8 @@ public class SystemConfig { } // Allow OEM to customize these - int oemPermissionFlag = ALLOW_FEATURES | ALLOW_OEM_PERMISSIONS | ALLOW_ASSOCIATIONS; + int oemPermissionFlag = ALLOW_FEATURES | ALLOW_OEM_PERMISSIONS | ALLOW_ASSOCIATIONS + | ALLOW_VENDOR_APEX; readPermissions(Environment.buildPath( Environment.getOemDirectory(), "etc", "sysconfig"), oemPermissionFlag); readPermissions(Environment.buildPath( @@ -536,7 +543,8 @@ public class SystemConfig { // the use of hidden APIs from the product partition. int productPermissionFlag = ALLOW_FEATURES | ALLOW_LIBS | ALLOW_PERMISSIONS | ALLOW_APP_CONFIGS | ALLOW_PRIVAPP_PERMISSIONS | ALLOW_HIDDENAPI_WHITELISTING - | ALLOW_ASSOCIATIONS | ALLOW_OVERRIDE_APP_RESTRICTIONS | ALLOW_IMPLICIT_BROADCASTS; + | ALLOW_ASSOCIATIONS | ALLOW_OVERRIDE_APP_RESTRICTIONS | ALLOW_IMPLICIT_BROADCASTS + | ALLOW_VENDOR_APEX; if (Build.VERSION.DEVICE_INITIAL_SDK_INT <= Build.VERSION_CODES.R) { // TODO(b/157393157): This must check product interface enforcement instead of // DEVICE_INITIAL_SDK_INT for the devices without product interface enforcement. @@ -663,6 +671,7 @@ public class SystemConfig { (permissionFlag & ALLOW_OVERRIDE_APP_RESTRICTIONS) != 0; final boolean allowImplicitBroadcasts = (permissionFlag & ALLOW_IMPLICIT_BROADCASTS) != 0; + final boolean allowVendorApex = (permissionFlag & ALLOW_VENDOR_APEX) != 0; while (true) { XmlUtils.nextElement(parser); if (parser.getEventType() == XmlPullParser.END_DOCUMENT) { @@ -1212,6 +1221,20 @@ public class SystemConfig { } XmlUtils.skipCurrentTag(parser); } break; + case "allowed-vendor-apex": { + if (allowVendorApex) { + String pkgName = parser.getAttributeValue(null, "package"); + if (pkgName == null) { + Slog.w(TAG, "<" + name + "> without package in " + permFile + + " at " + parser.getPositionDescription()); + } else { + mAllowedVendorApexes.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/java/com/android/server/WidgetBackupProvider.java b/core/java/com/android/server/WidgetBackupProvider.java index a2efbdd6f2f8..5453c4de6986 100644 --- a/core/java/com/android/server/WidgetBackupProvider.java +++ b/core/java/com/android/server/WidgetBackupProvider.java @@ -28,7 +28,7 @@ import java.util.List; public interface WidgetBackupProvider { public List<String> getWidgetParticipants(int userId); public byte[] getWidgetState(String packageName, int userId); - public void restoreStarting(int userId); + public void systemRestoreStarting(int userId); public void restoreWidgetState(String packageName, byte[] restoredState, int userId); - public void restoreFinished(int userId); + public void systemRestoreFinished(int userId); } diff --git a/core/res/res/values-television/config.xml b/core/res/res/values-television/config.xml index 3ecb1dddd916..55e5685b95e5 100644 --- a/core/res/res/values-television/config.xml +++ b/core/res/res/values-television/config.xml @@ -42,4 +42,8 @@ <!-- Allow SystemUI to show the shutdown dialog --> <bool name="config_showSysuiShutdown">true</bool> + + <!-- Component name of the activity used to inform a user about a sensory being blocked because + of privacy settings. --> + <string name="config_sensorUseStartedActivity">com.android.systemui/com.android.systemui.sensorprivacy.television.TvUnblockSensorActivity</string> </resources> 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/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/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/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java index 860d88afe4a2..d8f48c2cf0c6 100755 --- a/media/java/android/mtp/MtpDatabase.java +++ b/media/java/android/mtp/MtpDatabase.java @@ -101,6 +101,8 @@ public class MtpDatabase implements AutoCloseable { private int mBatteryLevel; private int mBatteryScale; private int mDeviceType; + private String mHostType; + private boolean mSkipThumbForHost = false; private MtpServer mServer; private MtpStorageManager mManager; @@ -192,6 +194,7 @@ public class MtpDatabase implements AutoCloseable { MtpConstants.DEVICE_PROPERTY_IMAGE_SIZE, MtpConstants.DEVICE_PROPERTY_BATTERY_LEVEL, MtpConstants.DEVICE_PROPERTY_PERCEIVED_DEVICE_TYPE, + MtpConstants.DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO, }; @VisibleForNative @@ -408,6 +411,8 @@ public class MtpDatabase implements AutoCloseable { } context.deleteDatabase(devicePropertiesName); } + mHostType = ""; + mSkipThumbForHost = false; } @VisibleForNative @@ -672,12 +677,24 @@ public class MtpDatabase implements AutoCloseable { @VisibleForNative private int getDeviceProperty(int property, long[] outIntValue, char[] outStringValue) { + int length; + String value; + switch (property) { case MtpConstants.DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER: case MtpConstants.DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME: // writable string properties kept in shared preferences - String value = mDeviceProperties.getString(Integer.toString(property), ""); - int length = value.length(); + value = mDeviceProperties.getString(Integer.toString(property), ""); + length = value.length(); + if (length > 255) { + length = 255; + } + value.getChars(0, length, outStringValue, 0); + outStringValue[length] = 0; + return MtpConstants.RESPONSE_OK; + case MtpConstants.DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO: + value = mHostType; + length = value.length(); if (length > 255) { length = 255; } @@ -717,6 +734,14 @@ public class MtpDatabase implements AutoCloseable { e.putString(Integer.toString(property), stringValue); return (e.commit() ? MtpConstants.RESPONSE_OK : MtpConstants.RESPONSE_GENERAL_ERROR); + case MtpConstants.DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO: + mHostType = stringValue; + if (stringValue.startsWith("Android/")) { + Log.d(TAG, "setDeviceProperty." + Integer.toHexString(property) + + "=" + stringValue); + mSkipThumbForHost = true; + } + return MtpConstants.RESPONSE_OK; } return MtpConstants.RESPONSE_DEVICE_PROP_NOT_SUPPORTED; @@ -838,6 +863,10 @@ public class MtpDatabase implements AutoCloseable { outLongs[0] = thumbOffsetAndSize != null ? thumbOffsetAndSize[1] : 0; outLongs[1] = exif.getAttributeInt(ExifInterface.TAG_PIXEL_X_DIMENSION, 0); outLongs[2] = exif.getAttributeInt(ExifInterface.TAG_PIXEL_Y_DIMENSION, 0); + if (mSkipThumbForHost) { + Log.d(TAG, "getThumbnailInfo: Skip runtime thumbnail."); + return true; + } if (exif.getThumbnailRange() != null) { if ((outLongs[0] == 0) || (outLongs[1] == 0) || (outLongs[2] == 0)) { Log.d(TAG, "getThumbnailInfo: check thumb info:" @@ -880,6 +909,10 @@ public class MtpDatabase implements AutoCloseable { try { ExifInterface exif = new ExifInterface(path); + if (mSkipThumbForHost) { + Log.d(TAG, "getThumbnailData: Skip runtime thumbnail."); + return exif.getThumbnail(); + } if (exif.getThumbnailRange() != null) return exif.getThumbnail(); } catch (IOException e) { diff --git a/media/java/android/mtp/MtpDevice.java b/media/java/android/mtp/MtpDevice.java index e8b04edb2e1b..ec925918d4e6 100644 --- a/media/java/android/mtp/MtpDevice.java +++ b/media/java/android/mtp/MtpDevice.java @@ -170,6 +170,18 @@ public final class MtpDevice { } /** + * Set device property SESSION_INITIATOR_VERSION_INFO + * + * @param propertyStr string value for device property SESSION_INITIATOR_VERSION_INFO + * @return -1 for error, 0 for success + * + * {@hide} + */ + public int setDevicePropertyInitVersion(@NonNull String propertyStr) { + return native_set_device_property_init_version(propertyStr); + } + + /** * Returns the list of IDs for all storage units on this device * Information about each storage unit can be accessed via {@link #getStorageInfo}. * @@ -421,6 +433,7 @@ public final class MtpDevice { private native boolean native_open(String deviceName, int fd); private native void native_close(); private native MtpDeviceInfo native_get_device_info(); + private native int native_set_device_property_init_version(String propertyStr); private native int[] native_get_storage_ids(); private native MtpStorageInfo native_get_storage_info(int storageId); private native int[] native_get_object_handles(int storageId, int format, int objectHandle); diff --git a/media/java/android/mtp/MtpDeviceInfo.java b/media/java/android/mtp/MtpDeviceInfo.java index 0304ee386ace..88514515eabf 100644 --- a/media/java/android/mtp/MtpDeviceInfo.java +++ b/media/java/android/mtp/MtpDeviceInfo.java @@ -31,6 +31,7 @@ public class MtpDeviceInfo { private String mSerialNumber; private int[] mOperationsSupported; private int[] mEventsSupported; + private int[] mDevicePropertySupported; // only instantiated via JNI private MtpDeviceInfo() { @@ -144,6 +145,21 @@ public class MtpDeviceInfo { } /** + * Returns Device property code supported by the device. + * + * @return supported Device property code. Can be null if device does not provide the property. + * + * @see MtpConstants#DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER + * @see MtpConstants#DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME + * @see MtpConstants#DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO + * + * {@hide} + */ + public final @NonNull int[] getDevicePropertySupported() { + return mDevicePropertySupported; + } + + /** * Returns if the given operation is supported by the device or not. * @param code Operation code. * @return If the given operation is supported by the device or not. @@ -162,6 +178,17 @@ public class MtpDeviceInfo { } /** + * Returns if the given Device property is supported by the device or not. + * @param code Device property code. + * @return If the given Device property is supported by the device or not. + * + * {@hide} + */ + public boolean isDevicePropertySupported(int code) { + return isSupported(mDevicePropertySupported, code); + } + + /** * Returns if the code set contains code. * @hide */ diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp index ffed4747d3ea..a77bc9fe0570 100644 --- a/media/jni/android_mtp_MtpDatabase.cpp +++ b/media/jni/android_mtp_MtpDatabase.cpp @@ -1131,6 +1131,7 @@ static const PropertyTableEntry kDevicePropertyTable[] = { { MTP_DEVICE_PROPERTY_IMAGE_SIZE, MTP_TYPE_STR }, { MTP_DEVICE_PROPERTY_BATTERY_LEVEL, MTP_TYPE_UINT8 }, { MTP_DEVICE_PROPERTY_PERCEIVED_DEVICE_TYPE, MTP_TYPE_UINT32 }, + { MTP_DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO, MTP_TYPE_STR }, }; bool MtpDatabase::getObjectPropertyInfo(MtpObjectProperty property, int& type) { @@ -1289,6 +1290,7 @@ MtpProperty* MtpDatabase::getDevicePropertyDesc(MtpDeviceProperty property) { switch (property) { case MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER: case MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME: + case MTP_DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO: writable = true; // fall through FALLTHROUGH_INTENDED; diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp index 3d2b00fec26c..ac89fecd9150 100644 --- a/media/jni/android_mtp_MtpDevice.cpp +++ b/media/jni/android_mtp_MtpDevice.cpp @@ -72,6 +72,7 @@ static jfieldID field_deviceInfo_version; static jfieldID field_deviceInfo_serialNumber; static jfieldID field_deviceInfo_operationsSupported; static jfieldID field_deviceInfo_eventsSupported; +static jfieldID field_deviceInfo_devicePropertySupported; // MtpStorageInfo fields static jfieldID field_storageInfo_storageId; @@ -129,6 +130,8 @@ static void initializeJavaIDs(JNIEnv* env) { GetFieldIDOrDie(env, clazz_deviceInfo, "mOperationsSupported", "[I"); field_deviceInfo_eventsSupported = GetFieldIDOrDie(env, clazz_deviceInfo, "mEventsSupported", "[I"); + field_deviceInfo_devicePropertySupported = + GetFieldIDOrDie(env, clazz_deviceInfo, "mDevicePropertySupported", "[I"); clazz_storageInfo = (jclass)env->NewGlobalRef(FindClassOrDie(env, "android/mtp/MtpStorageInfo")); @@ -377,9 +380,65 @@ android_mtp_MtpDevice_get_device_info(JNIEnv *env, jobject thiz) } } + assert(deviceInfo->mDeviceProperties); + { + const size_t size = deviceInfo->mDeviceProperties->size(); + ScopedLocalRef<jintArray> events(env, static_cast<jintArray>(env->NewIntArray(size))); + { + ScopedIntArrayRW elements(env, events.get()); + if (elements.get() == NULL) { + ALOGE("Could not create devicePropertySupported element."); + return NULL; + } + for (size_t i = 0; i < size; ++i) { + elements[i] = static_cast<int>(deviceInfo->mDeviceProperties->at(i)); + } + env->SetObjectField(info, field_deviceInfo_devicePropertySupported, events.get()); + } + } + return info; } +static jint +android_mtp_MtpDevice_set_device_property_init_version(JNIEnv *env, jobject thiz, + jstring property_str) { + MtpDevice* const device = get_device_from_object(env, thiz); + + if (!device) { + ALOGD("%s device is null\n", __func__); + env->ThrowNew(clazz_io_exception, "Failed to obtain MtpDevice."); + return -1; + } + + const char *propertyStr = env->GetStringUTFChars(property_str, NULL); + if (propertyStr == NULL) { + return -1; + } + + MtpProperty* property = new MtpProperty(MTP_DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO, + MTP_TYPE_STR, true); + if (!property) { + env->ThrowNew(clazz_io_exception, "Failed to obtain property."); + return -1; + } + + if (property->getDataType() != MTP_TYPE_STR) { + env->ThrowNew(clazz_io_exception, "Unexpected property data type."); + return -1; + } + + property->setCurrentValue(propertyStr); + if (!device->setDevicePropValueStr(property)) { + env->ThrowNew(clazz_io_exception, "Failed to obtain property value."); + return -1; + } + + env->ReleaseStringUTFChars(property_str, propertyStr); + + return 0; +} + static jintArray android_mtp_MtpDevice_get_storage_ids(JNIEnv *env, jobject thiz) { @@ -847,6 +906,8 @@ static const JNINativeMethod gMethods[] = { {"native_close", "()V", (void *)android_mtp_MtpDevice_close}, {"native_get_device_info", "()Landroid/mtp/MtpDeviceInfo;", (void *)android_mtp_MtpDevice_get_device_info}, + {"native_set_device_property_init_version", "(Ljava/lang/String;)I", + (void *)android_mtp_MtpDevice_set_device_property_init_version}, {"native_get_storage_ids", "()[I", (void *)android_mtp_MtpDevice_get_storage_ids}, {"native_get_storage_info", "(I)Landroid/mtp/MtpStorageInfo;", (void *)android_mtp_MtpDevice_get_storage_info}, 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/SettingsTheme/res/values-v31/styles.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml index 9610c9443184..46f1e030af23 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml @@ -25,6 +25,7 @@ <style name="Switch.SettingsLib" parent="@android:style/Widget.Material.CompoundButton.Switch"> <item name="android:switchMinWidth">52dp</item> + <item name="android:minHeight">@dimen/settingslib_preferred_minimum_touch_target</item> <item name="android:track">@drawable/settingslib_switch_track</item> <item name="android:thumb">@drawable/settingslib_switch_thumb</item> </style> 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/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 8c092ae37222..604310a9e905 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -454,6 +454,14 @@ android:finishOnCloseSystemDialogs="true"> </activity> + <!-- started from SensoryPrivacyService --> + <activity android:name=".sensorprivacy.television.TvUnblockSensorActivity" + android:exported="true" + android:permission="android.permission.MANAGE_SENSOR_PRIVACY" + android:theme="@style/BottomSheet" + android:finishOnCloseSystemDialogs="true"> + </activity> + <!-- started from UsbDeviceSettingsManager --> <activity android:name=".usb.UsbAccessoryUriActivity" diff --git a/packages/SystemUI/res/anim/tv_bottom_sheet_button_state_list_animator.xml b/packages/SystemUI/res/anim/tv_bottom_sheet_button_state_list_animator.xml new file mode 100644 index 000000000000..fc3b4ed6eecb --- /dev/null +++ b/packages/SystemUI/res/anim/tv_bottom_sheet_button_state_list_animator.xml @@ -0,0 +1,52 @@ +<?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. + --> + +<selector + xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_focused="true"> + <set> + <objectAnimator + android:duration="200" + android:propertyName="scaleX" + android:valueFrom="1.0" + android:valueTo="@dimen/bottom_sheet_button_selection_scaled" + android:valueType="floatType"/> + <objectAnimator + android:duration="200" + android:propertyName="scaleY" + android:valueFrom="1.0" + android:valueTo="@dimen/bottom_sheet_button_selection_scaled" + android:valueType="floatType"/> + </set> + </item> + <item android:state_focused="false"> + <set> + <objectAnimator + android:duration="200" + android:propertyName="scaleX" + android:valueFrom="@dimen/bottom_sheet_button_selection_scaled" + android:valueTo="1.0" + android:valueType="floatType"/> + <objectAnimator + android:duration="200" + android:propertyName="scaleY" + android:valueFrom="@dimen/bottom_sheet_button_selection_scaled" + android:valueTo="1.0" + android:valueType="floatType"/> + </set> + </item> +</selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/anim/tv_bottom_sheet_enter.xml b/packages/SystemUI/res/anim/tv_bottom_sheet_enter.xml new file mode 100644 index 000000000000..cace36d68b43 --- /dev/null +++ b/packages/SystemUI/res/anim/tv_bottom_sheet_enter.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:interpolator="@android:interpolator/decelerate_quint"> + <translate android:fromYDelta="100%" + android:toYDelta="0" + android:duration="900"/> +</set>
\ No newline at end of file diff --git a/packages/SystemUI/res/anim/tv_bottom_sheet_exit.xml b/packages/SystemUI/res/anim/tv_bottom_sheet_exit.xml new file mode 100644 index 000000000000..f7efe7cd2584 --- /dev/null +++ b/packages/SystemUI/res/anim/tv_bottom_sheet_exit.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:interpolator="@android:interpolator/decelerate_quint"> + <translate android:fromYDelta="0" + android:toYDelta="100%" + android:duration="500"/> +</set>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/bottom_sheet_button_background_color.xml b/packages/SystemUI/res/color/bottom_sheet_button_background_color.xml new file mode 100644 index 000000000000..9b0bae09b326 --- /dev/null +++ b/packages/SystemUI/res/color/bottom_sheet_button_background_color.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. + --> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_focused="true" + android:color="@color/bottom_sheet_button_background_color_focused"/> + <item android:color="@color/bottom_sheet_button_background_color_unfocused"/> +</selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/bottom_sheet_button_text_color.xml b/packages/SystemUI/res/color/bottom_sheet_button_text_color.xml new file mode 100644 index 000000000000..05248f17097b --- /dev/null +++ b/packages/SystemUI/res/color/bottom_sheet_button_text_color.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. + --> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_focused="true" + android:color="@color/bottom_sheet_button_text_color_focused"/> + <item android:color="@color/bottom_sheet_button_text_color_unfocused"/> +</selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/bottom_sheet_background.xml b/packages/SystemUI/res/drawable/bottom_sheet_background.xml new file mode 100644 index 000000000000..87850a0d00ec --- /dev/null +++ b/packages/SystemUI/res/drawable/bottom_sheet_background.xml @@ -0,0 +1,20 @@ +<?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. + --> +<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> + <solid android:color="@color/bottom_sheet_background_color"/> + <corners android:radius="@dimen/bottom_sheet_corner_radius"/> +</shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/bottom_sheet_background_with_blur.xml b/packages/SystemUI/res/drawable/bottom_sheet_background_with_blur.xml new file mode 100644 index 000000000000..cd2aa9c751d9 --- /dev/null +++ b/packages/SystemUI/res/drawable/bottom_sheet_background_with_blur.xml @@ -0,0 +1,20 @@ +<?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. + --> +<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> + <solid android:color="@color/bottom_sheet_background_color_with_blur"/> + <corners android:radius="@dimen/bottom_sheet_corner_radius"/> +</shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/bottom_sheet_button_background.xml b/packages/SystemUI/res/drawable/bottom_sheet_button_background.xml new file mode 100644 index 000000000000..585a6bc771f7 --- /dev/null +++ b/packages/SystemUI/res/drawable/bottom_sheet_button_background.xml @@ -0,0 +1,20 @@ +<?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. + --> +<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> + <solid android:color="@color/bottom_sheet_button_background_color"/> + <corners android:radius="@dimen/bottom_sheet_button_corner_radius"/> +</shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/tv_bottom_sheet.xml b/packages/SystemUI/res/layout/tv_bottom_sheet.xml new file mode 100644 index 000000000000..b69cdc76ae40 --- /dev/null +++ b/packages/SystemUI/res/layout/tv_bottom_sheet.xml @@ -0,0 +1,87 @@ +<?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. + --> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/bottom_sheet" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:orientation="horizontal" + android:minHeight="@dimen/bottom_sheet_min_height" + android:paddingHorizontal="@dimen/bottom_sheet_padding_horizontal" + android:paddingVertical="@dimen/bottom_sheet_padding_vertical"> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:minWidth="80dp" + android:gravity="center" + android:orientation="horizontal"> + <ImageView + android:id="@+id/bottom_sheet_icon" + android:layout_width="@dimen/bottom_sheet_icon_size" + android:layout_height="@dimen/bottom_sheet_icon_size" + android:layout_gravity="center_vertical" + android:tint="@color/bottom_sheet_icon_color"/> + <ImageView + android:id="@+id/bottom_sheet_second_icon" + android:layout_width="@dimen/bottom_sheet_icon_size" + android:layout_height="@dimen/bottom_sheet_icon_size" + android:layout_marginStart="@dimen/bottom_sheet_icon_margin" + android:layout_gravity="center_vertical" + android:tint="@color/bottom_sheet_icon_color"/> + </LinearLayout> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/bottom_sheet_padding_horizontal" + android:layout_weight="1" + android:orientation="vertical"> + <TextView + android:id="@+id/bottom_sheet_title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/bottom_sheet_title_margin_bottom" + android:textAppearance="@style/BottomSheet.TitleText"/> + + <TextView + android:id="@+id/bottom_sheet_body" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/bottom_sheet_details_margin_bottom" + android:textAppearance="@style/BottomSheet.BodyText" /> + </LinearLayout> + + <LinearLayout + android:orientation="vertical" + android:layout_width="@dimen/bottom_sheet_actions_width" + android:layout_height="match_parent" + android:gravity="center"> + <Button + android:id="@+id/bottom_sheet_positive_button" + style="@style/BottomSheet.ActionItem" /> + <Space + android:layout_width="0dp" + android:layout_height="@dimen/bottom_sheet_actions_spacing" /> + <Button + android:id="@+id/bottom_sheet_negative_button" + style="@style/BottomSheet.ActionItem" /> + </LinearLayout> + +</LinearLayout> 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-television/colors.xml b/packages/SystemUI/res/values-television/colors.xml index e5f3b4768fe2..e13c42e9ca3d 100644 --- a/packages/SystemUI/res/values-television/colors.xml +++ b/packages/SystemUI/res/values-television/colors.xml @@ -19,4 +19,19 @@ <resources> <color name="volume_dialog_background_color">#E61F232B</color> <color name="volume_dialog_background_color_above_blur">#C71F232B</color> + + <color name="bottom_sheet_icon_color">#D2E3FC</color> + + <color name="bottom_sheet_title_color">#E8F0FE</color> + <color name="bottom_sheet_body_color">#D2E3FC</color> + + <color name="bottom_sheet_background_color">#1F232C</color> + <color name="bottom_sheet_background_color_with_blur">#AA1A2734</color> + + <color name="bottom_sheet_button_background_color_focused">#E8F0FE</color> + <color name="bottom_sheet_button_background_color_unfocused">#0FE8EAED</color> + + <color name="bottom_sheet_button_text_color_focused">#DB202124</color> + <color name="bottom_sheet_button_text_color_unfocused">#B5E8EAED</color> + </resources> diff --git a/packages/SystemUI/res/values-television/dimens.xml b/packages/SystemUI/res/values-television/dimens.xml index 7626db93dd76..3a1a3d923fcc 100644 --- a/packages/SystemUI/res/values-television/dimens.xml +++ b/packages/SystemUI/res/values-television/dimens.xml @@ -21,4 +21,27 @@ <dimen name="privacy_chip_icon_margin">3dp</dimen> <dimen name="privacy_chip_icon_padding">8dp</dimen> <dimen name="privacy_chip_icon_size">13dp</dimen> + + <dimen name="bottom_sheet_padding_horizontal">32dp</dimen> + <dimen name="bottom_sheet_padding_vertical">24dp</dimen> + + <dimen name="bottom_sheet_icon_size">42dp</dimen> + <dimen name="bottom_sheet_icon_margin">8dp</dimen> + <dimen name="bottom_sheet_title_margin_bottom">18dp</dimen> + <dimen name="bottom_sheet_details_margin_bottom">8dp</dimen> + + <dimen name="bottom_sheet_actions_width">296dp</dimen> + <dimen name="bottom_sheet_actions_spacing">12dp</dimen> + <item name="bottom_sheet_button_selection_scaled" format="float" type="dimen">1.1</item> + <dimen name="bottom_sheet_button_width">232dp</dimen> + <dimen name="bottom_sheet_button_padding_horizontal">20dp</dimen> + <dimen name="bottom_sheet_button_padding_vertical">16dp</dimen> + + <dimen name="bottom_sheet_corner_radius">24dp</dimen> + <dimen name="bottom_sheet_button_corner_radius">10dp</dimen> + + <dimen name="bottom_sheet_min_height">208dp</dimen> + <dimen name="bottom_sheet_margin">24dp</dimen> + <dimen name="bottom_sheet_background_blur_radius">120dp</dimen> + </resources>
\ No newline at end of file diff --git a/packages/SystemUI/res/values-television/styles.xml b/packages/SystemUI/res/values-television/styles.xml index 00217fb39b93..0fb789863bd9 100644 --- a/packages/SystemUI/res/values-television/styles.xml +++ b/packages/SystemUI/res/values-television/styles.xml @@ -28,4 +28,34 @@ <item name="android:textColorPrimaryInverse">@color/tv_volume_dialog_accent</item> <item name="android:dialogCornerRadius">@dimen/volume_dialog_panel_width_half</item> </style> + + <style name="BottomSheet" parent="Theme.Leanback"> + <item name="android:windowIsFloating">true</item> + <item name="android:windowActivityTransitions">true</item> + <item name="android:windowNoTitle">true</item> + <item name="android:windowIsTranslucent">true</item> + <item name="android:backgroundDimAmount">0.2</item> + </style> + + <style name="BottomSheet.TitleText"> + <item name="android:textSize">28sp</item> + <item name="android:textColor">@color/bottom_sheet_title_color</item> + </style> + + <style name="BottomSheet.BodyText"> + <item name="android:textSize">16sp</item> + <item name="android:textColor">@color/bottom_sheet_body_color</item> + </style> + + <style name="BottomSheet.ActionItem"> + <item name="android:layout_width">@dimen/bottom_sheet_button_width</item> + <item name="android:layout_height">wrap_content</item> + <item name="android:gravity">left|center_vertical</item> + <item name="android:textSize">16sp</item> + <item name="android:textColor">@color/bottom_sheet_button_text_color</item> + <item name="android:background">@drawable/bottom_sheet_button_background</item> + <item name="android:paddingHorizontal">@dimen/bottom_sheet_button_padding_horizontal</item> + <item name="android:paddingVertical">@dimen/bottom_sheet_button_padding_vertical</item> + <item name="android:stateListAnimator">@anim/tv_bottom_sheet_button_state_list_animator</item> + </style> </resources> 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/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index ec930b0c41d1..11412f41f578 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -67,6 +67,7 @@ import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.LockscreenShadeTransitionController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.util.concurrency.DelayableExecutor; @@ -111,6 +112,7 @@ public class UdfpsController implements DozeReceiver { @NonNull private final FalsingManager mFalsingManager; @NonNull private final PowerManager mPowerManager; @NonNull private final AccessibilityManager mAccessibilityManager; + @NonNull private final LockscreenShadeTransitionController mLockscreenShadeTransitionController; @Nullable private final UdfpsHbmProvider mHbmProvider; // Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple // sensors, this, in addition to a lot of the code here, will be updated. @@ -507,6 +509,7 @@ public class UdfpsController implements DozeReceiver { @NonNull FalsingManager falsingManager, @NonNull PowerManager powerManager, @NonNull AccessibilityManager accessibilityManager, + @NonNull LockscreenShadeTransitionController lockscreenShadeTransitionController, @NonNull ScreenLifecycle screenLifecycle, @Nullable Vibrator vibrator, @NonNull Optional<UdfpsHbmProvider> hbmProvider) { @@ -529,6 +532,7 @@ public class UdfpsController implements DozeReceiver { mFalsingManager = falsingManager; mPowerManager = powerManager; mAccessibilityManager = accessibilityManager; + mLockscreenShadeTransitionController = lockscreenShadeTransitionController; mHbmProvider = hbmProvider.orElse(null); screenLifecycle.addObserver(mScreenObserver); mScreenOn = screenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_ON; @@ -716,6 +720,7 @@ public class UdfpsController implements DozeReceiver { mFgExecutor, mDumpManager, mKeyguardViewMediator, + mLockscreenShadeTransitionController, this ); case IUdfpsOverlayController.REASON_AUTH_BP: diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java index 00888dfe48d3..35ca470df523 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java @@ -31,6 +31,7 @@ import com.android.systemui.R; import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.LockscreenShadeTransitionController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.phone.KeyguardBouncer; import com.android.systemui.statusbar.phone.StatusBar; @@ -54,6 +55,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud @NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; @NonNull private final DelayableExecutor mExecutor; @NonNull private final KeyguardViewMediator mKeyguardViewMediator; + @NonNull private final LockscreenShadeTransitionController mLockScreenShadeTransitionController; @NonNull private final UdfpsController mUdfpsController; @Nullable private Runnable mCancelDelayedHintRunnable; @@ -63,6 +65,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud private boolean mFaceDetectRunning; private boolean mHintShown; private int mStatusBarState; + private float mTransitionToFullShadeProgress; /** * hidden amount of pin/pattern/password bouncer @@ -81,12 +84,14 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud @NonNull DelayableExecutor mainDelayableExecutor, @NonNull DumpManager dumpManager, @NonNull KeyguardViewMediator keyguardViewMediator, + @NonNull LockscreenShadeTransitionController transitionController, @NonNull UdfpsController udfpsController) { super(view, statusBarStateController, statusBar, dumpManager); mKeyguardViewManager = statusBarKeyguardViewManager; mKeyguardUpdateMonitor = keyguardUpdateMonitor; mExecutor = mainDelayableExecutor; mKeyguardViewMediator = keyguardViewMediator; + mLockScreenShadeTransitionController = transitionController; mUdfpsController = udfpsController; } @@ -116,6 +121,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud updatePauseAuth(); mKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor); + mLockScreenShadeTransitionController.setUdfpsKeyguardViewController(this); } @Override @@ -127,6 +133,9 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud mStatusBarStateController.removeCallback(mStateListener); mKeyguardViewManager.removeAlternateAuthInterceptor(mAlternateAuthInterceptor); mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false); + if (mLockScreenShadeTransitionController.getUdfpsKeyguardViewController() == this) { + mLockScreenShadeTransitionController.setUdfpsKeyguardViewController(null); + } if (mCancelDelayedHintRunnable != null) { mCancelDelayedHintRunnable.run(); @@ -256,11 +265,21 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud } } + /** + * Set the progress we're currently transitioning to the full shade. 0.0f means we're not + * transitioning yet, while 1.0f means we've fully dragged down. + */ + public void setTransitionToFullShadeProgress(float progress) { + mTransitionToFullShadeProgress = progress; + updateAlpha(); + } + private void updateAlpha() { // fade icon on transition to showing bouncer int alpha = mShowingUdfpsBouncer ? 255 : Math.abs((int) MathUtils.constrainedMap(0f, 255f, .4f, .7f, mInputBouncerHiddenAmount)); + alpha *= (1.0f - mTransitionToFullShadeProgress); mView.setUnpausedAlpha(alpha); } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java index 2dbf30fdd289..de8ed7013ab2 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java @@ -25,6 +25,7 @@ import com.android.systemui.people.widget.LaunchConversationActivity; import com.android.systemui.screenrecord.ScreenRecordDialog; import com.android.systemui.screenshot.LongScreenshotActivity; import com.android.systemui.sensorprivacy.SensorUseStartedActivity; +import com.android.systemui.sensorprivacy.television.TvUnblockSensorActivity; import com.android.systemui.settings.brightness.BrightnessDialog; import com.android.systemui.statusbar.tv.notifications.TvNotificationPanelActivity; import com.android.systemui.tuner.TunerActivity; @@ -120,4 +121,10 @@ public abstract class DefaultActivityBinder { @IntoMap @ClassKey(SensorUseStartedActivity.class) public abstract Activity bindSensorUseStartedActivity(SensorUseStartedActivity activity); + + /** Inject into TvUnblockSensorActivity. */ + @Binds + @IntoMap + @ClassKey(TvUnblockSensorActivity.class) + public abstract Activity bindTvUnblockSensorActivity(TvUnblockSensorActivity activity); } 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 3251ab2e4d50..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. @@ -237,7 +238,7 @@ 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 { @@ -266,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 { @@ -384,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 diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt index ed6f5505cbd1..df1b07f3e0b2 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt @@ -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 @@ -883,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) { @@ -893,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/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt index 3d1b4fbde56a..186f961ff1b6 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt @@ -660,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/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java index edfbed04f70d..6660081006cd 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java @@ -297,7 +297,7 @@ public class QSContainerImpl extends FrameLayout { // start margin of next page). qsPanelController.setPageMargin(mSideMargins); } else if (view == mHeader) { - // No content padding for the header. + quickStatusBarHeaderController.setContentMargins(mContentPadding, mContentPadding); } else { view.setPaddingRelative( mContentPadding, diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index 0bb0a3f7bad4..c70eaffcaeb6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -425,7 +425,7 @@ public class QSPanel extends LinearLayout implements Tunable { LinearLayout.LayoutParams layoutParams = (LayoutParams) hostView.getLayoutParams(); layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT; layoutParams.width = horizontal ? 0 : ViewGroup.LayoutParams.MATCH_PARENT; - layoutParams.weight = horizontal ? 1.2f : 0; + layoutParams.weight = horizontal ? 1f : 0; // Add any bottom margin, such that the total spacing is correct. This is only // necessary if the view isn't horizontal, since otherwise the padding is // carried in the parent of this view (to ensure correct vertical alignment) diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java index cbdcad5cf385..76076f6c2761 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java @@ -177,7 +177,6 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader mView.onAttach(mIconManager, mQSExpansionPathInterpolator); mDemoModeController.addCallback(mDemoModeReceiver); - mHeaderQsPanelController.setContentMargins(0, 0); } @Override @@ -253,6 +252,10 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader return mMicCameraIndicatorsEnabled || mLocationIndicatorsEnabled; } + public void setContentMargins(int marginStart, int marginEnd) { + mHeaderQsPanelController.setContentMargins(marginStart, marginEnd); + } + private static class ClockDemoModeReceiver implements DemoMode { private Clock mClockView; diff --git a/packages/SystemUI/src/com/android/systemui/sensorprivacy/television/TvUnblockSensorActivity.java b/packages/SystemUI/src/com/android/systemui/sensorprivacy/television/TvUnblockSensorActivity.java new file mode 100644 index 000000000000..9d101effa99f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/sensorprivacy/television/TvUnblockSensorActivity.java @@ -0,0 +1,145 @@ +/* + * 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.sensorprivacy.television; + +import static android.hardware.SensorPrivacyManager.Sensors.CAMERA; +import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE; + +import android.hardware.SensorPrivacyManager; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; + +import com.android.systemui.R; +import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController; +import com.android.systemui.tv.TvBottomSheetActivity; + +import javax.inject.Inject; + +/** + * Bottom sheet that is shown when the camera/mic sensors are blocked by the global toggle and + * allows the user to re-enable them. + */ +public class TvUnblockSensorActivity extends TvBottomSheetActivity { + + private static final String TAG = TvUnblockSensorActivity.class.getSimpleName(); + + private static final int ALL_SENSORS = Integer.MAX_VALUE; + private int mSensor = -1; + + private final IndividualSensorPrivacyController mSensorPrivacyController; + private IndividualSensorPrivacyController.Callback mSensorPrivacyCallback; + + @Inject + public TvUnblockSensorActivity( + IndividualSensorPrivacyController individualSensorPrivacyController) { + mSensorPrivacyController = individualSensorPrivacyController; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + boolean allSensors = getIntent().getBooleanExtra(SensorPrivacyManager.EXTRA_ALL_SENSORS, + false); + if (allSensors) { + mSensor = ALL_SENSORS; + } else { + mSensor = getIntent().getIntExtra(SensorPrivacyManager.EXTRA_SENSOR, -1); + } + + if (mSensor == -1) { + Log.v(TAG, "Invalid extras"); + finish(); + return; + } + + mSensorPrivacyCallback = (sensor, blocked) -> { + if (mSensor == ALL_SENSORS) { + if (!mSensorPrivacyController.isSensorBlocked(CAMERA) + && !mSensorPrivacyController.isSensorBlocked(MICROPHONE)) { + finish(); + } + } else if (this.mSensor == sensor && !blocked) { + finish(); + } + }; + + initUI(); + } + + private void initUI() { + TextView title = findViewById(R.id.bottom_sheet_title); + TextView content = findViewById(R.id.bottom_sheet_body); + ImageView icon = findViewById(R.id.bottom_sheet_icon); + // mic icon if both icons are shown + ImageView secondIcon = findViewById(R.id.bottom_sheet_second_icon); + Button unblockButton = findViewById(R.id.bottom_sheet_positive_button); + Button cancelButton = findViewById(R.id.bottom_sheet_negative_button); + + switch (mSensor) { + case MICROPHONE: + title.setText(R.string.sensor_privacy_start_use_mic_dialog_title); + content.setText(R.string.sensor_privacy_start_use_mic_dialog_content); + icon.setImageResource(com.android.internal.R.drawable.perm_group_microphone); + secondIcon.setVisibility(View.GONE); + break; + case CAMERA: + title.setText(R.string.sensor_privacy_start_use_camera_dialog_title); + content.setText(R.string.sensor_privacy_start_use_camera_dialog_content); + icon.setImageResource(com.android.internal.R.drawable.perm_group_camera); + secondIcon.setVisibility(View.GONE); + break; + case ALL_SENSORS: + default: + title.setText(R.string.sensor_privacy_start_use_mic_camera_dialog_title); + content.setText(R.string.sensor_privacy_start_use_mic_camera_dialog_content); + icon.setImageResource(com.android.internal.R.drawable.perm_group_camera); + secondIcon.setImageResource(com.android.internal.R.drawable.perm_group_microphone); + break; + } + unblockButton.setText( + com.android.internal.R.string.sensor_privacy_start_use_dialog_turn_on_button); + unblockButton.setOnClickListener(v -> { + if (mSensor == ALL_SENSORS) { + mSensorPrivacyController.setSensorBlocked(CAMERA, false); + mSensorPrivacyController.setSensorBlocked(MICROPHONE, false); + } else { + mSensorPrivacyController.setSensorBlocked(mSensor, false); + } + }); + + cancelButton.setText(android.R.string.cancel); + cancelButton.setOnClickListener(v -> finish()); + } + + @Override + public void onResume() { + super.onResume(); + mSensorPrivacyController.addCallback(mSensorPrivacyCallback); + } + + @Override + public void onPause() { + mSensorPrivacyController.removeCallback(mSensorPrivacyCallback); + super.onPause(); + } + +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt index 4a4e990728f3..6f4a73ec4516 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt @@ -18,6 +18,7 @@ import com.android.systemui.ExpandHelper import com.android.systemui.Gefingerpoken import com.android.systemui.R import com.android.systemui.animation.Interpolators +import com.android.systemui.biometrics.UdfpsKeyguardViewController import com.android.systemui.classifier.Classifier import com.android.systemui.classifier.FalsingCollector import com.android.systemui.dagger.SysUISingleton @@ -109,6 +110,11 @@ class LockscreenShadeTransitionController @Inject constructor( private var nextHideKeyguardNeedsNoAnimation = false /** + * The udfpsKeyguardViewController if it exists. + */ + var udfpsKeyguardViewController: UdfpsKeyguardViewController? = null + + /** * The touch helper responsible for the drag down animation. */ val touchHelper = DragDownHelper(falsingManager, falsingCollector, this, context) @@ -291,6 +297,7 @@ class LockscreenShadeTransitionController @Inject constructor( // Fade out all content only visible on the lockscreen notificationPanelController.setKeyguardOnlyContentAlpha(1.0f - scrimProgress) depthController.transitionToFullShadeProgress = scrimProgress + udfpsKeyguardViewController?.setTransitionToFullShadeProgress(scrimProgress) } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ExpandAnimationParameters.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ExpandAnimationParameters.kt index f1479a149a41..f19cf5d8d9c7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ExpandAnimationParameters.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ExpandAnimationParameters.kt @@ -22,11 +22,27 @@ class ExpandAnimationParameters( ) var startTranslationZ = 0f + + /** + * The top position of the notification at the start of the animation. This is needed in order + * to keep the notification at its place when launching a notification that is clipped rounded. + */ + var startNotificationTop = 0f var startClipTopAmount = 0 var parentStartClipTopAmount = 0 var progress = 0f var linearProgress = 0f + /** + * The rounded top clipping at the beginning. + */ + var startRoundedTopClipping = 0 + + /** + * The rounded top clipping of the parent notification at the start. + */ + var parentStartRoundedTopClipping = 0 + override val topChange: Int get() { // We need this compensation to ensure that the QS moves in sync. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt index c248670c48db..1bbef2562d21 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt @@ -40,6 +40,11 @@ class NotificationLaunchAnimatorController( private val headsUpManager: HeadsUpManagerPhone, private val notification: ExpandableNotificationRow ) : ActivityLaunchAnimator.Controller { + + companion object { + const val ANIMATION_DURATION_TOP_ROUNDING = 100L + } + private val notificationEntry = notification.entry private val notificationKey = notificationEntry.sbn.key @@ -54,18 +59,37 @@ class NotificationLaunchAnimatorController( val height = max(0, notification.actualHeight - notification.clipBottomAmount) val location = notification.locationOnScreen + val clipStartLocation = notificationListContainer.getTopClippingStartLocation() + val roundedTopClipping = Math.max(clipStartLocation - location[1], 0) + val windowTop = location[1] + roundedTopClipping + val topCornerRadius = if (roundedTopClipping > 0) { + // Because the rounded Rect clipping is complex, we start the top rounding at + // 0, which is pretty close to matching the real clipping. + // We'd have to clipOut the overlaid drawable too with the outer rounded rect in case + // if we'd like to have this perfect, but this is close enough. + 0f + } else { + notification.currentBackgroundRadiusTop + } val params = ExpandAnimationParameters( - top = location[1], + top = windowTop, bottom = location[1] + height, left = location[0], right = location[0] + notification.width, - topCornerRadius = notification.currentBackgroundRadiusTop, + topCornerRadius = topCornerRadius, bottomCornerRadius = notification.currentBackgroundRadiusBottom ) params.startTranslationZ = notification.translationZ + params.startNotificationTop = notification.translationY + params.startRoundedTopClipping = roundedTopClipping params.startClipTopAmount = notification.clipTopAmount if (notification.isChildInGroup) { + params.startNotificationTop += notification.notificationParent.translationY + val parentRoundedClip = Math.max(clipStartLocation + - notification.notificationParent.locationOnScreen[1], 0) + params.parentStartRoundedTopClipping = parentRoundedClip + val parentClip = notification.notificationParent.clipTopAmount params.parentStartClipTopAmount = parentClip 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..76f9fe728f2f 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 @@ -35,6 +35,7 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; +import android.graphics.Canvas; import android.graphics.Path; import android.graphics.drawable.AnimatedVectorDrawable; import android.graphics.drawable.AnimationDrawable; @@ -85,6 +86,7 @@ import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.StatusBarIconView; import com.android.systemui.statusbar.notification.AboveShelfChangedListener; import com.android.systemui.statusbar.notification.ExpandAnimationParameters; +import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorController; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; @@ -133,7 +135,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. @@ -252,6 +254,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView private OnExpandClickListener mOnExpandClickListener; private View.OnClickListener mOnAppClickListener; private View.OnClickListener mOnFeedbackClickListener; + private Path mExpandingClipPath; // Listener will be called when receiving a long click event. // Use #setLongPressPosition to optionally assign positional data with the long press. @@ -836,6 +839,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) { if (mExpandAnimationRunning && !isChildInGroup && mNotificationParent != null) { mNotificationParent.setChildIsExpanding(false); + mNotificationParent.setExpandingClipPath(null); mNotificationParent.setExtraWidthForClipping(0.0f); mNotificationParent.setMinimumHeightForClipping(0); } @@ -1105,8 +1109,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 +1824,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView void onGutsClosed() { updateContentAccessibilityImportanceForGuts(true /* isEnabled */); - if (mSnoozedMenuItems != null && mSnoozedMenuItems.size() > 0) { - mMenuRow.setMenuItems(mSnoozedMenuItems); - mSnoozedMenuItems = null; - } + mIsSnoozed = false; } /** @@ -2036,7 +2036,22 @@ public class ExpandableNotificationRow extends ActivatableNotificationView setTranslationZ(translationZ); float extraWidthForClipping = params.getWidth() - getWidth(); setExtraWidthForClipping(extraWidthForClipping); - int top = params.getTop(); + int top; + if (params.getStartRoundedTopClipping() > 0) { + // If we were clipping initially, let's interpolate from the start position to the + // top. Otherwise, we just take the top directly. + float expandProgress = Interpolators.FAST_OUT_SLOW_IN.getInterpolation( + params.getProgress(0, + NotificationLaunchAnimatorController.ANIMATION_DURATION_TOP_ROUNDING)); + float startTop = params.getStartNotificationTop(); + top = (int) Math.min(MathUtils.lerp(startTop, + params.getTop(), expandProgress), + startTop); + } else { + top = params.getTop(); + } + int actualHeight = params.getBottom() - top; + setActualHeight(actualHeight); int startClipTopAmount = params.getStartClipTopAmount(); int clipTopAmount = (int) MathUtils.lerp(startClipTopAmount, 0, params.getProgress()); if (mNotificationParent != null) { @@ -2065,13 +2080,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView setClipTopAmount(clipTopAmount); } setTranslationY(top); - setActualHeight(params.getHeight()); mTopRoundnessDuringExpandAnimation = params.getTopCornerRadius() / mOutlineRadius; mBottomRoundnessDuringExpandAnimation = params.getBottomCornerRadius() / mOutlineRadius; invalidateOutline(); - mBackgroundNormal.setExpandAnimationParams(params); + mBackgroundNormal.setExpandAnimationSize(params.getWidth(), actualHeight); } public void setExpandAnimationRunning(boolean expandAnimationRunning) { @@ -2981,7 +2995,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 +3011,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView isExpanded = isExpanded(); } } - if (expandable) { + if (expandable && !mIsSnoozed) { if (isExpanded) { info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE); } else { @@ -3085,6 +3099,26 @@ public class ExpandableNotificationRow extends ActivatableNotificationView return super.childNeedsClipping(child); } + /** + * Set a clip path to be set while expanding the notification. This is needed to nicely + * clip ourselves during the launch if we were clipped rounded in the beginning + */ + public void setExpandingClipPath(Path path) { + mExpandingClipPath = path; + invalidate(); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + canvas.save(); + if (mExpandingClipPath != null && (mExpandAnimationRunning || mChildIsExpanding)) { + // If we're launching a notification, let's clip if a clip rounded to the clipPath + canvas.clipPath(mExpandingClipPath); + } + super.dispatchDraw(canvas); + canvas.restore(); + } + @Override protected void applyRoundness() { super.applyRoundness(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java index 754de580cd61..0f615aa9356f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java @@ -240,10 +240,10 @@ public class NotificationBackgroundView extends View { invalidate(); } - /** Set the current expand animation parameters. */ - public void setExpandAnimationParams(ExpandAnimationParameters params) { - mActualHeight = params.getHeight(); - mActualWidth = params.getWidth(); + /** Set the current expand animation size. */ + public void setExpandAnimationSize(int actualWidth, int actualHeight) { + mActualHeight = actualHeight; + mActualWidth = actualWidth; invalidate(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java index 26606cda5582..197920f7be19 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java @@ -72,8 +72,6 @@ public class AmbientState { private boolean mUnlockHintRunning; private boolean mQsCustomizerShowing; private int mIntrinsicPadding; - private int mExpandAnimationTopChange; - private ExpandableNotificationRow mExpandingNotification; private float mHideAmount; private boolean mAppearing; private float mPulseHeight = MAX_PULSE_HEIGHT; @@ -518,22 +516,6 @@ public class AmbientState { return isDozing() && !isPulsing(row.getEntry()); } - public void setExpandAnimationTopChange(int expandAnimationTopChange) { - mExpandAnimationTopChange = expandAnimationTopChange; - } - - public void setExpandingNotification(ExpandableNotificationRow row) { - mExpandingNotification = row; - } - - public ExpandableNotificationRow getExpandingNotification() { - return mExpandingNotification; - } - - public int getExpandAnimationTopChange() { - return mExpandAnimationTopChange; - } - /** * @return {@code true } when shade is completely hidden: in AOD, ambient display or when * bypassing. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java index 2a2e733f78a1..7a5c18896e5f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java @@ -200,4 +200,11 @@ public interface NotificationListContainer extends default void setWillExpand(boolean willExpand) {} void setNotificationActivityStarter(NotificationActivityStarter notificationActivityStarter); + + /** + * @return the start location where we start clipping notifications. + */ + default int getTopClippingStartLocation() { + return 0; + } } 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..a9d61f1c5c4f 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 @@ -77,6 +77,7 @@ import com.android.settingslib.Utils; import com.android.systemui.Dumpable; import com.android.systemui.ExpandHelper; import com.android.systemui.R; +import com.android.systemui.animation.ActivityLaunchAnimator; import com.android.systemui.animation.Interpolators; import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper; import com.android.systemui.statusbar.CommandQueue; @@ -90,6 +91,7 @@ import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.ExpandAnimationParameters; import com.android.systemui.statusbar.notification.FakeShadowView; import com.android.systemui.statusbar.notification.NotificationActivityStarter; +import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorController; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.ShadeViewRefactor; import com.android.systemui.statusbar.notification.ShadeViewRefactor.RefactorComponent; @@ -111,6 +113,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 +424,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<>(); @@ -467,6 +473,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable private final Path mRoundedClipPath = new Path(); /** + * The clip Path used to clip the launching notification. This may be different + * from the normal path, as the views launch animation could start clipped. + */ + private final Path mLaunchedNotificationClipPath = new Path(); + + /** * Should we use rounded rect clipping right now */ private boolean mShouldUseRoundedRectClipping = false; @@ -489,6 +501,26 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable private boolean mLaunchingNotification; /** + * Does the launching notification need to be clipped + */ + private boolean mLaunchingNotificationNeedsToBeClipped; + + /** + * The current launch animation params when launching a notification + */ + private ExpandAnimationParameters mLaunchAnimationParams; + + /** + * Corner radii of the launched notification if it's clipped + */ + private float[] mLaunchedNotificationRadii = new float[8]; + + /** + * The notification that is being launched currently. + */ + private ExpandableNotificationRow mExpandingNotificationRow; + + /** * Do notifications dismiss with normal transitioning */ private boolean mDismissUsingRowTranslationX = true; @@ -896,7 +928,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 +941,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 +1016,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 +2168,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; @@ -2726,6 +2777,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable * @return the amount of scrolling needed to start clipping notifications. */ private int getScrollAmountToScrollBoundary() { + if (mShouldUseSplitNotificationShade) { + return mSidePaddings; + } return mTopPadding - mQsScrollBoundaryPosition; } @@ -2869,7 +2923,16 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) void setExpandingNotification(ExpandableNotificationRow row) { - mAmbientState.setExpandingNotification(row); + if (mExpandingNotificationRow != null && row == null) { + // Let's unset the clip path being set during launch + mExpandingNotificationRow.setExpandingClipPath(null); + ExpandableNotificationRow parent = mExpandingNotificationRow.getNotificationParent(); + if (parent != null) { + parent.setExpandingClipPath(null); + } + } + mExpandingNotificationRow = row; + updateLaunchedNotificationClipPath(); requestChildrenUpdate(); } @@ -2879,10 +2942,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) public void applyExpandAnimationParams(ExpandAnimationParameters params) { - mAmbientState.setExpandAnimationTopChange(params == null ? 0 : params.getTopChange()); - - // Disable clipping for launches + // Modify the clipping for launching notifications + mLaunchAnimationParams = params; setLaunchingNotification(params != null); + updateLaunchedNotificationClipPath(); requestChildrenUpdate(); } @@ -5330,7 +5393,15 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable return; } mLaunchingNotification = launching; - updateUseRoundedRectClipping(); + mLaunchingNotificationNeedsToBeClipped = mLaunchAnimationParams != null + && (mLaunchAnimationParams.getStartRoundedTopClipping() > 0 + || mLaunchAnimationParams.getParentStartRoundedTopClipping() > 0); + if (!mLaunchingNotificationNeedsToBeClipped || !mLaunchingNotification) { + mLaunchedNotificationClipPath.reset(); + } + // When launching notifications, we're clipping the children individually instead of in + // dispatchDraw + invalidate(); } /** @@ -5340,22 +5411,97 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable // We don't want to clip notifications when QS is expanded, because incoming heads up on // the bottom would be clipped otherwise boolean qsAllowsClipping = mQsExpansionFraction < 0.5f || mShouldUseSplitNotificationShade; - boolean clip = !mLaunchingNotification && mIsExpanded && qsAllowsClipping; + boolean clip = mIsExpanded && qsAllowsClipping; if (clip != mShouldUseRoundedRectClipping) { mShouldUseRoundedRectClipping = clip; invalidate(); } } + /** + * Update the clip path for launched notifications in case they were originally clipped + */ + private void updateLaunchedNotificationClipPath() { + if (!mLaunchingNotificationNeedsToBeClipped || !mLaunchingNotification + || mExpandingNotificationRow == null) { + return; + } + int left = Math.min(mLaunchAnimationParams.getLeft(), mRoundedRectClippingLeft); + int right = Math.max(mLaunchAnimationParams.getRight(), mRoundedRectClippingRight); + int bottom = Math.max(mLaunchAnimationParams.getBottom(), mRoundedRectClippingBottom); + float expandProgress = Interpolators.FAST_OUT_SLOW_IN.getInterpolation( + mLaunchAnimationParams.getProgress(0, + NotificationLaunchAnimatorController.ANIMATION_DURATION_TOP_ROUNDING)); + int top = (int) Math.min(MathUtils.lerp(mRoundedRectClippingTop, + mLaunchAnimationParams.getTop(), expandProgress), + mRoundedRectClippingTop); + float topRadius = mLaunchAnimationParams.getTopCornerRadius(); + float bottomRadius = mLaunchAnimationParams.getBottomCornerRadius(); + mLaunchedNotificationRadii[0] = topRadius; + mLaunchedNotificationRadii[1] = topRadius; + mLaunchedNotificationRadii[2] = topRadius; + mLaunchedNotificationRadii[3] = topRadius; + mLaunchedNotificationRadii[4] = bottomRadius; + mLaunchedNotificationRadii[5] = bottomRadius; + mLaunchedNotificationRadii[6] = bottomRadius; + mLaunchedNotificationRadii[7] = bottomRadius; + mLaunchedNotificationClipPath.reset(); + mLaunchedNotificationClipPath.addRoundRect(left, top, right, bottom, + mLaunchedNotificationRadii, Path.Direction.CW); + // Offset into notification clip coordinates instead of parent ones. + // This is needed since the notification changes in translationZ, where clipping via + // canvas dispatching won't work. + ExpandableNotificationRow expandingRow = mExpandingNotificationRow; + if (expandingRow.getNotificationParent() != null) { + expandingRow = expandingRow.getNotificationParent(); + } + mLaunchedNotificationClipPath.offset( + -expandingRow.getLeft() - expandingRow.getTranslationX(), + -expandingRow.getTop() - expandingRow.getTranslationY()); + expandingRow.setExpandingClipPath(mLaunchedNotificationClipPath); + if (mShouldUseRoundedRectClipping) { + invalidate(); + } + } + @Override protected void dispatchDraw(Canvas canvas) { - if (mShouldUseRoundedRectClipping) { + if (mShouldUseRoundedRectClipping && !mLaunchingNotification) { + // When launching notifications, we're clipping the children individually instead of in + // dispatchDraw // Let's clip rounded. canvas.clipPath(mRoundedClipPath); } super.dispatchDraw(canvas); } + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + if (mShouldUseRoundedRectClipping && mLaunchingNotification) { + // Let's clip children individually during notification launch + canvas.save(); + ExpandableView expandableView = (ExpandableView) child; + Path clipPath; + if (expandableView.isExpandAnimationRunning() + || ((ExpandableView) child).hasExpandingChild()) { + // When launching the notification, it is not clipped by this layout, but by the + // view itself. This is because the view is Translating in Z, where this clipPath + // wouldn't apply. + clipPath = null; + } else { + clipPath = mRoundedClipPath; + } + if (clipPath != null) { + canvas.clipPath(clipPath); + } + boolean result = super.drawChild(canvas, child, drawingTime); + canvas.restore(); + return result; + } else { + return super.drawChild(canvas, child, drawingTime); + } + } + /** * Calculate the total translation needed when dismissing. */ @@ -5370,6 +5516,13 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } /** + * @return the start location where we start clipping notifications. + */ + public int getTopClippingStartLocation() { + return mIsExpanded ? mQsScrollBoundaryPosition : 0; + } + + /** * A listener that is notified when the empty space below the notifications is clicked on */ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index 495eda772219..e71f7dbb008b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -1533,6 +1533,11 @@ public class NotificationStackScrollLayoutController { } @Override + public int getTopClippingStartLocation() { + return mView.getTopClippingStartLocation(); + } + + @Override public View getContainerChildAt(int i) { return mView.getContainerChildAt(i); } 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/src/com/android/systemui/tv/TvBottomSheetActivity.java b/packages/SystemUI/src/com/android/systemui/tv/TvBottomSheetActivity.java new file mode 100644 index 000000000000..2b7a33260248 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/tv/TvBottomSheetActivity.java @@ -0,0 +1,98 @@ +/* + * 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.tv; + +import android.app.Activity; +import android.graphics.PixelFormat; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.Gravity; +import android.view.WindowManager; + +import com.android.systemui.R; + +import java.util.function.Consumer; + +/** + * Generic bottom sheet with up to two icons in the beginning and two buttons. + */ +public abstract class TvBottomSheetActivity extends Activity { + + private static final String TAG = TvBottomSheetActivity.class.getSimpleName(); + private Drawable mBackgroundWithBlur; + private Drawable mBackgroundWithoutBlur; + + private final Consumer<Boolean> mBlurConsumer = this::onBlurChanged; + + private void onBlurChanged(boolean enabled) { + Log.v(TAG, "blur enabled: " + enabled); + getWindow().setBackgroundDrawable(enabled ? mBackgroundWithBlur : mBackgroundWithoutBlur); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.tv_bottom_sheet); + + overridePendingTransition(R.anim.tv_bottom_sheet_enter, 0); + + mBackgroundWithBlur = getResources() + .getDrawable(R.drawable.bottom_sheet_background_with_blur); + mBackgroundWithoutBlur = getResources().getDrawable(R.drawable.bottom_sheet_background); + + DisplayMetrics metrics = getResources().getDisplayMetrics(); + int screenWidth = metrics.widthPixels; + int screenHeight = metrics.heightPixels; + int marginPx = getResources().getDimensionPixelSize(R.dimen.bottom_sheet_margin); + + WindowManager.LayoutParams windowParams = getWindow().getAttributes(); + windowParams.width = screenWidth - marginPx * 2; + windowParams.height = WindowManager.LayoutParams.WRAP_CONTENT; + windowParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; + windowParams.horizontalMargin = 0f; + windowParams.verticalMargin = (float) marginPx / screenHeight; + windowParams.format = PixelFormat.TRANSPARENT; + windowParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG; + windowParams.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; + windowParams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; + getWindow().setAttributes(windowParams); + getWindow().setElevation(getWindow().getElevation() + 5); + getWindow().setBackgroundBlurRadius(getResources().getDimensionPixelSize( + R.dimen.bottom_sheet_background_blur_radius)); + } + + @Override + public void onAttachedToWindow() { + super.onAttachedToWindow(); + getWindowManager().addCrossWindowBlurEnabledListener(mBlurConsumer); + } + + @Override + public void onDetachedFromWindow() { + getWindowManager().removeCrossWindowBlurEnabledListener(mBlurConsumer); + super.onDetachedFromWindow(); + } + + @Override + public void finish() { + super.finish(); + overridePendingTransition(0, R.anim.tv_bottom_sheet_exit); + } + +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java index 41f987727860..0c750a179358 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -53,6 +53,7 @@ import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.LockscreenShadeTransitionController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.util.concurrency.FakeExecutor; @@ -117,6 +118,8 @@ public class UdfpsControllerTest extends SysuiTestCase { @Mock private AccessibilityManager mAccessibilityManager; @Mock + private LockscreenShadeTransitionController mLockscreenShadeTransitionController; + @Mock private ScreenLifecycle mScreenLifecycle; @Mock private Vibrator mVibrator; @@ -176,6 +179,7 @@ public class UdfpsControllerTest extends SysuiTestCase { mFalsingManager, mPowerManager, mAccessibilityManager, + mLockscreenShadeTransitionController, mScreenLifecycle, mVibrator, Optional.of(mHbmProvider)); diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java index 5923de6719a8..f62587c6e87c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java @@ -35,6 +35,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.LockscreenShadeTransitionController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; @@ -65,6 +66,8 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase { @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; @Mock + private LockscreenShadeTransitionController mLockscreenShadeTransitionController; + @Mock private DumpManager mDumpManager; @Mock private DelayableExecutor mExecutor; @@ -106,6 +109,7 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase { mExecutor, mDumpManager, mKeyguardViewMediator, + mLockscreenShadeTransitionController, mUdfpsController); } 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/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/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 241a0dbac758..f63198866b08 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -872,18 +872,32 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub "userId=" + userId); } + final int resolvedUserId; + final List<AccessibilityServiceInfo> serviceInfos; synchronized (mLock) { // We treat calls from a profile as if made by its parent as profiles // share the accessibility state of the parent. The call below // performs the current profile parent resolution. - final int resolvedUserId = mSecurityPolicy + resolvedUserId = mSecurityPolicy .resolveCallingUserIdEnforcingPermissionsLocked(userId); + serviceInfos = new ArrayList<>( + getUserStateLocked(resolvedUserId).mInstalledServices); + } - if (Binder.getCallingPid() == OWN_PROCESS_ID) { - return new ArrayList<>(getUserStateLocked(resolvedUserId).mInstalledServices); + if (Binder.getCallingPid() == OWN_PROCESS_ID) { + return serviceInfos; + } + final PackageManagerInternal pm = LocalServices.getService( + PackageManagerInternal.class); + final int callingUid = Binder.getCallingUid(); + for (int i = serviceInfos.size() - 1; i >= 0; i--) { + final AccessibilityServiceInfo serviceInfo = serviceInfos.get(i); + if (pm.filterAppAccess(serviceInfo.getComponentName().getPackageName(), callingUid, + resolvedUserId)) { + serviceInfos.remove(i); } - return getUserStateLocked(resolvedUserId).mInstalledServices; } + return serviceInfos; } @Override diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index acbf4875ae8d..5aec6aa99c12 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -409,6 +409,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku // If the set of providers has been modified, notify each active AppWidgetHost scheduleNotifyGroupHostsForProvidersChangedLocked(userId); + // Possibly notify any new components of widget id changes + mBackupRestoreController.widgetComponentsChanged(userId); } } } @@ -2471,8 +2473,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } @Override - public void restoreStarting(int userId) { - mBackupRestoreController.restoreStarting(userId); + public void systemRestoreStarting(int userId) { + mBackupRestoreController.systemRestoreStarting(userId); } @Override @@ -2481,8 +2483,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } @Override - public void restoreFinished(int userId) { - mBackupRestoreController.restoreFinished(userId); + public void systemRestoreFinished(int userId) { + mBackupRestoreController.systemRestoreFinished(userId); } @SuppressWarnings("deprecation") @@ -4272,6 +4274,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku private final HashMap<Host, ArrayList<RestoreUpdateRecord>> mUpdatesByHost = new HashMap<>(); + @GuardedBy("mLock") + private boolean mHasSystemRestoreFinished; + public List<String> getWidgetParticipants(int userId) { if (DEBUG) { Slog.i(TAG, "Getting widget participants for user: " + userId); @@ -4375,12 +4380,13 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku return stream.toByteArray(); } - public void restoreStarting(int userId) { + public void systemRestoreStarting(int userId) { if (DEBUG) { - Slog.i(TAG, "Restore starting for user: " + userId); + Slog.i(TAG, "System restore starting for user: " + userId); } synchronized (mLock) { + mHasSystemRestoreFinished = false; // We're starting a new "system" restore operation, so any widget restore // state that we see from here on is intended to replace the current // widget configuration of any/all of the affected apps. @@ -4542,26 +4548,90 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } } - // Called once following the conclusion of a restore operation. This is when we + // Called once following the conclusion of a system restore operation. This is when we // send out updates to apps involved in widget-state restore telling them about - // the new widget ID space. - public void restoreFinished(int userId) { + // the new widget ID space. Apps that are not yet installed will be notifed when they are. + public void systemRestoreFinished(int userId) { if (DEBUG) { - Slog.i(TAG, "restoreFinished for " + userId); + Slog.i(TAG, "systemRestoreFinished for " + userId); } + synchronized (mLock) { + mHasSystemRestoreFinished = true; + maybeSendWidgetRestoreBroadcastsLocked(userId); + } + } - final UserHandle userHandle = new UserHandle(userId); + // Called when widget components (hosts or providers) are added or changed. If system + // restore has completed, we use this opportunity to tell the apps to update to the new + // widget ID space. If system restore is still in progress, we delay the updates until + // the end, to allow all participants to restore their state before updating widget IDs. + public void widgetComponentsChanged(int userId) { synchronized (mLock) { - // Build the providers' broadcasts and send them off - Set<Map.Entry<Provider, ArrayList<RestoreUpdateRecord>>> providerEntries - = mUpdatesByProvider.entrySet(); - for (Map.Entry<Provider, ArrayList<RestoreUpdateRecord>> e : providerEntries) { - // For each provider there's a list of affected IDs - Provider provider = e.getKey(); + if (mHasSystemRestoreFinished) { + maybeSendWidgetRestoreBroadcastsLocked(userId); + } + } + } + + // Called following the conclusion of a restore operation and when widget components + // are added or changed. This is when we send out updates to apps involved in widget-state + // restore telling them about the new widget ID space. + @GuardedBy("mLock") + private void maybeSendWidgetRestoreBroadcastsLocked(int userId) { + if (DEBUG) { + Slog.i(TAG, "maybeSendWidgetRestoreBroadcasts for " + userId); + } + + final UserHandle userHandle = new UserHandle(userId); + // Build the providers' broadcasts and send them off + Set<Map.Entry<Provider, ArrayList<RestoreUpdateRecord>>> providerEntries + = mUpdatesByProvider.entrySet(); + for (Map.Entry<Provider, ArrayList<RestoreUpdateRecord>> e : providerEntries) { + // For each provider there's a list of affected IDs + Provider provider = e.getKey(); + if (provider.zombie) { + // Provider not installed, we can't send them broadcasts yet. + // We'll be called again when the provider is installed. + continue; + } + ArrayList<RestoreUpdateRecord> updates = e.getValue(); + final int pending = countPendingUpdates(updates); + if (DEBUG) { + Slog.i(TAG, "Provider " + provider + " pending: " + pending); + } + if (pending > 0) { + int[] oldIds = new int[pending]; + int[] newIds = new int[pending]; + final int N = updates.size(); + int nextPending = 0; + for (int i = 0; i < N; i++) { + RestoreUpdateRecord r = updates.get(i); + if (!r.notified) { + r.notified = true; + oldIds[nextPending] = r.oldId; + newIds[nextPending] = r.newId; + nextPending++; + if (DEBUG) { + Slog.i(TAG, " " + r.oldId + " => " + r.newId); + } + } + } + sendWidgetRestoreBroadcastLocked( + AppWidgetManager.ACTION_APPWIDGET_RESTORED, + provider, null, oldIds, newIds, userHandle); + } + } + + // same thing per host + Set<Map.Entry<Host, ArrayList<RestoreUpdateRecord>>> hostEntries + = mUpdatesByHost.entrySet(); + for (Map.Entry<Host, ArrayList<RestoreUpdateRecord>> e : hostEntries) { + Host host = e.getKey(); + if (host.id.uid != UNKNOWN_UID) { ArrayList<RestoreUpdateRecord> updates = e.getValue(); final int pending = countPendingUpdates(updates); if (DEBUG) { - Slog.i(TAG, "Provider " + provider + " pending: " + pending); + Slog.i(TAG, "Host " + host + " pending: " + pending); } if (pending > 0) { int[] oldIds = new int[pending]; @@ -4581,43 +4651,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } } sendWidgetRestoreBroadcastLocked( - AppWidgetManager.ACTION_APPWIDGET_RESTORED, - provider, null, oldIds, newIds, userHandle); - } - } - - // same thing per host - Set<Map.Entry<Host, ArrayList<RestoreUpdateRecord>>> hostEntries - = mUpdatesByHost.entrySet(); - for (Map.Entry<Host, ArrayList<RestoreUpdateRecord>> e : hostEntries) { - Host host = e.getKey(); - if (host.id.uid != UNKNOWN_UID) { - ArrayList<RestoreUpdateRecord> updates = e.getValue(); - final int pending = countPendingUpdates(updates); - if (DEBUG) { - Slog.i(TAG, "Host " + host + " pending: " + pending); - } - if (pending > 0) { - int[] oldIds = new int[pending]; - int[] newIds = new int[pending]; - final int N = updates.size(); - int nextPending = 0; - for (int i = 0; i < N; i++) { - RestoreUpdateRecord r = updates.get(i); - if (!r.notified) { - r.notified = true; - oldIds[nextPending] = r.oldId; - newIds[nextPending] = r.newId; - nextPending++; - if (DEBUG) { - Slog.i(TAG, " " + r.oldId + " => " + r.newId); - } - } - } - sendWidgetRestoreBroadcastLocked( - AppWidgetManager.ACTION_APPWIDGET_HOST_RESTORED, - null, host, oldIds, newIds, userHandle); - } + AppWidgetManager.ACTION_APPWIDGET_HOST_RESTORED, + null, host, oldIds, newIds, userHandle); } } } diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java index 261ebe69a15e..f07bac8cd762 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java @@ -381,7 +381,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { // If we're starting a full-system restore, set up to begin widget ID remapping if (mIsSystemRestore) { - AppWidgetBackupBridge.restoreStarting(mUserId); + AppWidgetBackupBridge.systemRestoreStarting(mUserId); } try { @@ -1133,8 +1133,10 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { restoreAgentTimeoutMillis); } - // Kick off any work that may be needed regarding app widget restores - AppWidgetBackupBridge.restoreFinished(mUserId); + if (mIsSystemRestore) { + // Kick off any work that may be needed regarding app widget restores + AppWidgetBackupBridge.systemRestoreFinished(mUserId); + } // If this was a full-system restore, record the ancestral // dataset information diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java index 26ecee8f21ab..70176a0fefeb 100644 --- a/services/core/java/com/android/server/VpnManagerService.java +++ b/services/core/java/com/android/server/VpnManagerService.java @@ -38,6 +38,7 @@ import android.net.VpnManager; import android.net.VpnService; import android.net.util.NetdService; import android.os.Binder; +import android.os.Build; import android.os.Handler; import android.os.HandlerThread; import android.os.INetworkManagementService; @@ -348,9 +349,17 @@ public class VpnManagerService extends IVpnManager.Stub { /** * Start legacy VPN, controlling native daemons as needed. Creates a * secondary thread to perform connection work, returning quickly. + * + * Legacy VPN is deprecated starting from Android S. So this API shouldn't be called if the + * initial SDK version of device is Android S+. Otherwise, UnsupportedOperationException will be + * thrown. */ + @SuppressWarnings("AndroidFrameworkCompatChange") // This is not an app-visible API. @Override public void startLegacyVpn(VpnProfile profile) { + if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.S) { + throw new UnsupportedOperationException("Legacy VPN is deprecated"); + } int user = UserHandle.getUserId(mDeps.getCallingUid()); // Note that if the caller is not system (uid >= Process.FIRST_APPLICATION_UID), // the code might not work well since getActiveNetwork might return null if the uid is diff --git a/services/core/java/com/android/server/appop/DiscreteRegistry.java b/services/core/java/com/android/server/appop/DiscreteRegistry.java index 49469cc8a597..1e32129dcee1 100644 --- a/services/core/java/com/android/server/appop/DiscreteRegistry.java +++ b/services/core/java/com/android/server/appop/DiscreteRegistry.java @@ -16,6 +16,7 @@ package com.android.server.appop; +import static android.app.AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE; import static android.app.AppOpsManager.FILTER_BY_ATTRIBUTION_TAG; import static android.app.AppOpsManager.FILTER_BY_OP_NAMES; import static android.app.AppOpsManager.FILTER_BY_PACKAGE_NAME; @@ -58,7 +59,9 @@ import com.android.internal.util.XmlUtils; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.io.IOException; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.time.Duration; @@ -138,6 +141,7 @@ final class DiscreteRegistry { private static final String TAG_HISTORY = "h"; private static final String ATTR_VERSION = "v"; + private static final String ATTR_LARGEST_CHAIN_ID = "lc"; private static final int CURRENT_VERSION = 1; private static final String TAG_UID = "u"; @@ -182,6 +186,16 @@ final class DiscreteRegistry { DiscreteRegistry(Object inMemoryLock) { mInMemoryLock = inMemoryLock; + synchronized (mOnDiskLock) { + mDiscreteAccessDir = new File( + new File(Environment.getDataSystemDirectory(), "appops"), + "discrete"); + createDiscreteAccessDirLocked(); + int largestChainId = readLargestChainIdFromDiskLocked(); + synchronized (mInMemoryLock) { + mDiscreteOps = new DiscreteOps(largestChainId); + } + } } void systemReady() { @@ -190,15 +204,6 @@ final class DiscreteRegistry { setDiscreteHistoryParameters(p); }); setDiscreteHistoryParameters(DeviceConfig.getProperties(DeviceConfig.NAMESPACE_PRIVACY)); - synchronized (mOnDiskLock) { - synchronized (mInMemoryLock) { - mDiscreteAccessDir = new File( - new File(Environment.getDataSystemDirectory(), "appops"), - "discrete"); - createDiscreteAccessDirLocked(); - mDiscreteOps = new DiscreteOps(); - } - } } private void setDiscreteHistoryParameters(DeviceConfig.Properties p) { @@ -251,7 +256,7 @@ final class DiscreteRegistry { DiscreteOps discreteOps; synchronized (mInMemoryLock) { discreteOps = mDiscreteOps; - mDiscreteOps = new DiscreteOps(); + mDiscreteOps = new DiscreteOps(discreteOps.mChainIdOffset); mCachedOps = null; } deleteOldDiscreteHistoryFilesLocked(); @@ -275,6 +280,50 @@ final class DiscreteRegistry { return; } + private int readLargestChainIdFromDiskLocked() { + final File[] files = mDiscreteAccessDir.listFiles(); + if (files != null && files.length > 0) { + File latestFile = null; + long latestFileTimestamp = 0; + for (File f : files) { + final String fileName = f.getName(); + if (!fileName.endsWith(DISCRETE_HISTORY_FILE_SUFFIX)) { + continue; + } + long timestamp = Long.valueOf(fileName.substring(0, + fileName.length() - DISCRETE_HISTORY_FILE_SUFFIX.length())); + if (latestFileTimestamp < timestamp) { + latestFile = f; + latestFileTimestamp = timestamp; + } + } + if (latestFile == null) { + return 0; + } + FileInputStream stream; + try { + stream = new FileInputStream(latestFile); + } catch (FileNotFoundException e) { + return 0; + } + try { + TypedXmlPullParser parser = Xml.resolvePullParser(stream); + XmlUtils.beginDocument(parser, TAG_HISTORY); + + final int largestChainId = parser.getAttributeInt(null, ATTR_LARGEST_CHAIN_ID, 0); + return largestChainId; + } catch (Throwable t) { + return 0; + } finally { + try { + stream.close(); + } catch (IOException e) { } + } + } else { + return 0; + } + } + private void readDiscreteOpsFromDisk(DiscreteOps discreteOps) { synchronized (mOnDiskLock) { long beginTimeMillis = Instant.now().minus(sDiscreteHistoryCutoff, @@ -301,7 +350,7 @@ final class DiscreteRegistry { void clearHistory() { synchronized (mOnDiskLock) { synchronized (mInMemoryLock) { - mDiscreteOps = new DiscreteOps(); + mDiscreteOps = new DiscreteOps(0); } clearOnDiskHistoryLocked(); } @@ -341,6 +390,10 @@ final class DiscreteRegistry { : new String[]{AppOpsManager.opToPublicName(dumpOp)}; discreteOps.filter(0, Instant.now().toEpochMilli(), filter, uidFilter, packageNameFilter, opNamesFilter, attributionTagFilter, OP_FLAGS_ALL); + pw.print(prefix); + pw.print("Largest chain id: "); + pw.print(mDiscreteOps.mLargestChainId); + pw.println(); discreteOps.dump(pw, sdf, date, prefix, nDiscreteOps); } @@ -351,14 +404,14 @@ final class DiscreteRegistry { } private DiscreteOps getAllDiscreteOps() { - DiscreteOps discreteOps = new DiscreteOps(); + DiscreteOps discreteOps = new DiscreteOps(0); synchronized (mOnDiskLock) { synchronized (mInMemoryLock) { discreteOps.merge(mDiscreteOps); } if (mCachedOps == null) { - mCachedOps = new DiscreteOps(); + mCachedOps = new DiscreteOps(0); readDiscreteOpsFromDisk(mCachedOps); } discreteOps.merge(mCachedOps); @@ -368,9 +421,13 @@ final class DiscreteRegistry { private final class DiscreteOps { ArrayMap<Integer, DiscreteUidOps> mUids; + int mChainIdOffset; + int mLargestChainId; - DiscreteOps() { + DiscreteOps(int chainIdOffset) { mUids = new ArrayMap<>(); + mChainIdOffset = chainIdOffset; + mLargestChainId = chainIdOffset; } boolean isEmpty() { @@ -378,6 +435,7 @@ final class DiscreteRegistry { } void merge(DiscreteOps other) { + mLargestChainId = max(mLargestChainId, other.mLargestChainId); int nUids = other.mUids.size(); for (int i = 0; i < nUids; i++) { int uid = other.mUids.keyAt(i); @@ -390,6 +448,17 @@ final class DiscreteRegistry { @Nullable String attributionTag, @AppOpsManager.OpFlags int flags, @AppOpsManager.UidState int uidState, long accessTime, long accessDuration, @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId) { + if (attributionChainId != ATTRIBUTION_CHAIN_ID_NONE) { + attributionChainId += mChainIdOffset; + if (attributionChainId < 0) { + attributionChainId -= mChainIdOffset; + mChainIdOffset = 0; + mLargestChainId = attributionChainId; + } + if (attributionChainId > mLargestChainId) { + mLargestChainId = attributionChainId; + } + } getOrCreateDiscreteUidOps(uid).addDiscreteAccess(op, packageName, attributionTag, flags, uidState, accessTime, accessDuration, attributionFlags, attributionChainId); } @@ -442,6 +511,7 @@ final class DiscreteRegistry { out.startDocument(null, true); out.startTag(null, TAG_HISTORY); out.attributeInt(null, ATTR_VERSION, CURRENT_VERSION); + out.attributeInt(null, ATTR_LARGEST_CHAIN_ID, mLargestChainId); int nUids = mUids.size(); for (int i = 0; i < nUids; i++) { @@ -476,8 +546,13 @@ final class DiscreteRegistry { } private void readFromFile(File f, long beginTimeMillis) { + FileInputStream stream; + try { + stream = new FileInputStream(f); + } catch (FileNotFoundException e) { + return; + } try { - FileInputStream stream = new FileInputStream(f); TypedXmlPullParser parser = Xml.resolvePullParser(stream); XmlUtils.beginDocument(parser, TAG_HISTORY); @@ -487,7 +562,6 @@ final class DiscreteRegistry { if (version != CURRENT_VERSION) { throw new IllegalStateException("Dropping unsupported discrete history " + f); } - int depth = parser.getDepth(); while (XmlUtils.nextElementWithin(parser, depth)) { if (TAG_UID.equals(parser.getName())) { @@ -498,8 +572,12 @@ final class DiscreteRegistry { } catch (Throwable t) { Slog.e(TAG, "Failed to read file " + f.getName() + " " + t.getMessage() + " " + Arrays.toString(t.getStackTrace())); + } finally { + try { + stream.close(); + } catch (IOException e) { + } } - } } diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java index dd5df503d936..62472b5f1d75 100644 --- a/services/core/java/com/android/server/appop/HistoricalRegistry.java +++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java @@ -209,6 +209,7 @@ final class HistoricalRegistry { mMode = other.mMode; mBaseSnapshotInterval = other.mBaseSnapshotInterval; mIntervalCompressionMultiplier = other.mIntervalCompressionMultiplier; + mDiscreteRegistry = other.mDiscreteRegistry; } void systemReady(@NonNull ContentResolver resolver) { 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/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index a3f3a3a503c8..9151e4e1779a 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -140,6 +140,7 @@ import android.app.INotificationManager; import android.app.ITransientNotification; import android.app.ITransientNotificationCallback; import android.app.IUriGrantsManager; +import android.app.KeyguardManager; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; @@ -549,6 +550,8 @@ public class NotificationManagerService extends SystemService { // Used for rate limiting toasts by package. private MultiRateLimiter mToastRateLimiter; + private KeyguardManager mKeyguardManager; + // The last key in this list owns the hardware. ArrayList<String> mLights = new ArrayList<>(); @@ -2008,6 +2011,11 @@ public class NotificationManagerService extends SystemService { } @VisibleForTesting + void setKeyguardManager(KeyguardManager keyguardManager) { + mKeyguardManager = keyguardManager; + } + + @VisibleForTesting ShortcutHelper getShortcutHelper() { return mShortcutHelper; } @@ -2653,6 +2661,7 @@ public class NotificationManagerService extends SystemService { mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); mAudioManagerInternal = getLocalService(AudioManagerInternal.class); mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); + mKeyguardManager = getContext().getSystemService(KeyguardManager.class); mZenModeHelper.onSystemReady(); RoleObserver roleObserver = new RoleObserver(getContext(), getContext().getSystemService(RoleManager.class), @@ -7388,7 +7397,6 @@ public class NotificationManagerService extends SystemService { boolean beep = false; boolean blink = false; - final Notification notification = record.getSbn().getNotification(); final String key = record.getKey(); // Should this notification make noise, vibe, or use the LED? @@ -7410,7 +7418,7 @@ public class NotificationManagerService extends SystemService { if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN && !suppressedByDnd) { - sendAccessibilityEvent(notification, record.getSbn().getPackageName()); + sendAccessibilityEvent(record); sentAccessibilityEvent = true; } @@ -7433,7 +7441,7 @@ public class NotificationManagerService extends SystemService { boolean hasAudibleAlert = hasValidSound || hasValidVibrate; if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) { if (!sentAccessibilityEvent) { - sendAccessibilityEvent(notification, record.getSbn().getPackageName()); + sendAccessibilityEvent(record); sentAccessibilityEvent = true; } if (DBG) Slog.v(TAG, "Interrupting!"); @@ -8261,17 +8269,30 @@ public class NotificationManagerService extends SystemService { return (x < low) ? low : ((x > high) ? high : x); } - void sendAccessibilityEvent(Notification notification, CharSequence packageName) { + void sendAccessibilityEvent(NotificationRecord record) { if (!mAccessibilityManager.isEnabled()) { return; } - AccessibilityEvent event = + final Notification notification = record.getNotification(); + final CharSequence packageName = record.getSbn().getPackageName(); + final AccessibilityEvent event = AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED); event.setPackageName(packageName); event.setClassName(Notification.class.getName()); - event.setParcelableData(notification); - CharSequence tickerText = notification.tickerText; + final int visibilityOverride = record.getPackageVisibilityOverride(); + final int notifVisibility = visibilityOverride == NotificationManager.VISIBILITY_NO_OVERRIDE + ? notification.visibility : visibilityOverride; + final int userId = record.getUser().getIdentifier(); + final boolean needPublic = userId >= 0 && mKeyguardManager.isDeviceLocked(userId); + if (needPublic && notifVisibility != Notification.VISIBILITY_PUBLIC) { + // Emit the public version if we're on the lockscreen and this notification isn't + // publicly visible. + event.setParcelableData(notification.publicVersion); + } else { + event.setParcelableData(notification); + } + final CharSequence tickerText = notification.tickerText; if (!TextUtils.isEmpty(tickerText)) { event.getText().add(tickerText); } 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..acc83cfd05b6 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().getAllowedVendorApexes().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 463520fb2608..b0a662b3514d 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -21480,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); @@ -21524,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) { @@ -21602,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/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/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/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/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 9a6e4448966d..4471f6c91190 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -683,8 +683,9 @@ class WindowStateAnimator { } // We don't apply animation for application main window here since this window type - // should be controlled by AppWindowToken in general. - if (mAttrType != TYPE_BASE_APPLICATION) { + // should be controlled by ActivityRecord in general. Wallpaper is also excluded because + // WallpaperController should handle it. + if (mAttrType != TYPE_BASE_APPLICATION && !mIsWallpaper) { applyAnimationLocked(transit, true); } 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/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java index e99113d1296f..acf50b4569c6 100644 --- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java @@ -323,6 +323,8 @@ public class DeviceIdleControllerTest { when(mPowerManager.newWakeLock(anyInt(), anyString())).thenReturn(mWakeLock); doNothing().when(mWakeLock).acquire(); doNothing().when(mAlarmManager).set(anyInt(), anyLong(), anyString(), any(), any()); + doNothing().when(mAlarmManager) + .setWindow(anyInt(), anyLong(), anyLong(), anyString(), any(), any()); doReturn(mock(Sensor.class)).when(mSensorManager) .getDefaultSensor(eq(Sensor.TYPE_SIGNIFICANT_MOTION), eq(true)); doReturn(true).when(mSensorManager).registerListener(any(), any(), anyInt()); @@ -1043,24 +1045,28 @@ public class DeviceIdleControllerTest { mDeviceIdleController.stepLightIdleStateLocked("testing"); verifyLightStateConditions(LIGHT_STATE_IDLE); inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked( - longThat(l -> l == mConstants.LIGHT_IDLE_TIMEOUT)); + longThat(l -> l == mConstants.LIGHT_IDLE_TIMEOUT), + longThat(l -> l == mConstants.LIGHT_IDLE_TIMEOUT_INITIAL_FLEX)); // Should just alternate between IDLE and IDLE_MAINTENANCE now. mDeviceIdleController.stepLightIdleStateLocked("testing"); verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE); inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked( - longThat(l -> l >= mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET)); + longThat(l -> l >= mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET), + longThat(l -> l == mConstants.FLEX_TIME_SHORT)); mDeviceIdleController.stepLightIdleStateLocked("testing"); verifyLightStateConditions(LIGHT_STATE_IDLE); inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked( - longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT)); + longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT), + longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT_INITIAL_FLEX)); mDeviceIdleController.stepLightIdleStateLocked("testing"); verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE); inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked( - longThat(l -> l >= mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET)); + longThat(l -> l >= mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET), + longThat(l -> l == mConstants.FLEX_TIME_SHORT)); // Test that motion doesn't reset the idle timeout. mDeviceIdleController.handleMotionDetectedLocked(50, "test"); @@ -1068,7 +1074,8 @@ public class DeviceIdleControllerTest { mDeviceIdleController.stepLightIdleStateLocked("testing"); verifyLightStateConditions(LIGHT_STATE_IDLE); inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked( - longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT)); + longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT), + longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT_INITIAL_FLEX)); } ///////////////// EXIT conditions /////////////////// @@ -1824,9 +1831,9 @@ public class DeviceIdleControllerTest { .forClass(AlarmManager.OnAlarmListener.class); final ArgumentCaptor<AlarmManager.OnAlarmListener> motionRegistrationAlarmListener = ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class); - doNothing().when(mAlarmManager).set(anyInt(), anyLong(), eq("DeviceIdleController.motion"), - motionAlarmListener.capture(), any()); - doNothing().when(mAlarmManager).set(anyInt(), anyLong(), + doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(), + eq("DeviceIdleController.motion"), motionAlarmListener.capture(), any()); + doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(), eq("DeviceIdleController.motion_registration"), motionRegistrationAlarmListener.capture(), any()); @@ -1900,9 +1907,9 @@ public class DeviceIdleControllerTest { mInjector.nowElapsed += mConstants.QUICK_DOZE_DELAY_TIMEOUT; final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListener = ArgumentCaptor .forClass(AlarmManager.OnAlarmListener.class); - doNothing().when(mAlarmManager) - .set(anyInt(), anyLong(), eq("DeviceIdleController.motion"), any(), any()); - doNothing().when(mAlarmManager).set(anyInt(), anyLong(), + doNothing().when(mAlarmManager).setWindow( + anyInt(), anyLong(), anyLong(), eq("DeviceIdleController.motion"), any(), any()); + doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(), eq("DeviceIdleController.motion_registration"), alarmListener.capture(), any()); ArgumentCaptor<TriggerEventListener> listenerCaptor = @@ -1944,9 +1951,9 @@ public class DeviceIdleControllerTest { mInjector.nowElapsed += mConstants.QUICK_DOZE_DELAY_TIMEOUT; final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListener = ArgumentCaptor .forClass(AlarmManager.OnAlarmListener.class); - doNothing().when(mAlarmManager) - .set(anyInt(), anyLong(), eq("DeviceIdleController.motion"), any(), any()); - doNothing().when(mAlarmManager).set(anyInt(), anyLong(), + doNothing().when(mAlarmManager).setWindow( + anyInt(), anyLong(), anyLong(), eq("DeviceIdleController.motion"), any(), any()); + doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(), eq("DeviceIdleController.motion_registration"), alarmListener.capture(), any()); ArgumentCaptor<SensorEventListener> listenerCaptor = 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/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/systemconfig/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java index 17d99e652726..9044b27d4994 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_VENDOR_APEX} + * permission flag for the tag: {@code allowed-vendor-apex}. + */ + @Test + public void readPermissions_allowVendorApex_parsesVendorApexAllowList() + throws IOException { + final String contents = + "<config>\n" + + " <allowed-vendor-apex package=\"com.android.apex1\" />\n" + + "</config>"; + final File folder = createTempSubfolder("folder"); + createTempFile(folder, "vendor-apex-allowlist.xml", contents); + + mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0); + + assertThat(mSysConfig.getAllowedVendorApexes()).containsExactly("com.android.apex1"); + } + + /** + * Tests that readPermissions works correctly with {@link SystemConfig#ALLOW_VENDOR_APEX} + * permission flag for the tag: {@code allowed-vendor-apex}. + */ + @Test + public void readPermissions_allowVendorApex_parsesVendorApexAllowList_noPackage() + throws IOException { + final String contents = + "<config>\n" + + " <allowed-vendor-apex/>\n" + + "</config>"; + final File folder = createTempSubfolder("folder"); + createTempFile(folder, "vendor-apex-allowlist.xml", contents); + + mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0); + + assertThat(mSysConfig.getAllowedVendorApexes()).isEmpty(); + } + + + /** + * Tests that readPermissions works correctly without {@link SystemConfig#ALLOW_VENDOR_APEX} + * permission flag for the tag: {@code allowed-oem-apex}. + */ + @Test + public void readPermissions_notAllowVendorApex_doesNotParseVendorApexAllowList() + throws IOException { + final String contents = + "<config>\n" + + " <allowed-vendor-apex package=\"com.android.apex1\" />\n" + + "</config>"; + final File folder = createTempSubfolder("folder"); + createTempFile(folder, "vendor-apex-allowlist.xml", contents); + + mSysConfig.readPermissions(folder, /* Grant all but ALLOW_VENDOR_APEX flag */ ~0x400); + + assertThat(mSysConfig.getAllowedVendorApexes()).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/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java index 3862d754b8f5..71c05b5c46f7 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java @@ -48,6 +48,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.ActivityManager; +import android.app.KeyguardManager; import android.app.Notification; import android.app.Notification.Builder; import android.app.NotificationChannel; @@ -111,6 +112,8 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { NotificationUsageStats mUsageStats; @Mock IAccessibilityManager mAccessibilityService; + @Mock + KeyguardManager mKeyguardManager; NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake(); private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake( 1 << 30); @@ -153,6 +156,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL); when(mUsageStats.isAlertRateLimited(any())).thenReturn(false); when(mVibrator.hasFrequencyControl()).thenReturn(false); + when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(false); long serviceReturnValue = IntPair.of( AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED, @@ -174,6 +178,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { mService.setScreenOn(false); mService.setUsageStats(mUsageStats); mService.setAccessibilityManager(accessibilityManager); + mService.setKeyguardManager(mKeyguardManager); mService.mScreenOn = false; mService.mInCallStateOffHook = false; mService.mNotificationPulseEnabled = true; @@ -496,6 +501,94 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { } @Test + public void testLockedPrivateA11yRedaction() throws Exception { + NotificationRecord r = getBeepyNotification(); + r.setPackageVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE); + r.getNotification().visibility = Notification.VISIBILITY_PRIVATE; + when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(true); + AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class); + when(accessibilityManager.isEnabled()).thenReturn(true); + mService.setAccessibilityManager(accessibilityManager); + + mService.buzzBeepBlinkLocked(r); + + ArgumentCaptor<AccessibilityEvent> eventCaptor = + ArgumentCaptor.forClass(AccessibilityEvent.class); + + verify(accessibilityManager, times(1)) + .sendAccessibilityEvent(eventCaptor.capture()); + + AccessibilityEvent event = eventCaptor.getValue(); + assertEquals(r.getNotification().publicVersion, event.getParcelableData()); + } + + @Test + public void testLockedOverridePrivateA11yRedaction() throws Exception { + NotificationRecord r = getBeepyNotification(); + r.setPackageVisibilityOverride(Notification.VISIBILITY_PRIVATE); + r.getNotification().visibility = Notification.VISIBILITY_PUBLIC; + when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(true); + AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class); + when(accessibilityManager.isEnabled()).thenReturn(true); + mService.setAccessibilityManager(accessibilityManager); + + mService.buzzBeepBlinkLocked(r); + + ArgumentCaptor<AccessibilityEvent> eventCaptor = + ArgumentCaptor.forClass(AccessibilityEvent.class); + + verify(accessibilityManager, times(1)) + .sendAccessibilityEvent(eventCaptor.capture()); + + AccessibilityEvent event = eventCaptor.getValue(); + assertEquals(r.getNotification().publicVersion, event.getParcelableData()); + } + + @Test + public void testLockedPublicA11yNoRedaction() throws Exception { + NotificationRecord r = getBeepyNotification(); + r.setPackageVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE); + r.getNotification().visibility = Notification.VISIBILITY_PUBLIC; + when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(true); + AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class); + when(accessibilityManager.isEnabled()).thenReturn(true); + mService.setAccessibilityManager(accessibilityManager); + + mService.buzzBeepBlinkLocked(r); + + ArgumentCaptor<AccessibilityEvent> eventCaptor = + ArgumentCaptor.forClass(AccessibilityEvent.class); + + verify(accessibilityManager, times(1)) + .sendAccessibilityEvent(eventCaptor.capture()); + + AccessibilityEvent event = eventCaptor.getValue(); + assertEquals(r.getNotification(), event.getParcelableData()); + } + + @Test + public void testUnlockedPrivateA11yNoRedaction() throws Exception { + NotificationRecord r = getBeepyNotification(); + r.setPackageVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE); + r.getNotification().visibility = Notification.VISIBILITY_PRIVATE; + when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(false); + AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class); + when(accessibilityManager.isEnabled()).thenReturn(true); + mService.setAccessibilityManager(accessibilityManager); + + mService.buzzBeepBlinkLocked(r); + + ArgumentCaptor<AccessibilityEvent> eventCaptor = + ArgumentCaptor.forClass(AccessibilityEvent.class); + + verify(accessibilityManager, times(1)) + .sendAccessibilityEvent(eventCaptor.capture()); + + AccessibilityEvent event = eventCaptor.getValue(); + assertEquals(r.getNotification(), event.getParcelableData()); + } + + @Test public void testBeepInsistently() throws Exception { NotificationRecord r = getInsistentBeepyNotification(); 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/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index 1953af4adee5..e000265f0a2c 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -1018,6 +1018,16 @@ public class TelecomManager { // this magic number is a bug ID public static final long ENABLE_GET_CALL_STATE_PERMISSION_PROTECTION = 157233955L; + /** + * Enable READ_PHONE_NUMBERS or READ_PRIVILEGED_PHONE_STATE protections on + * {@link TelecomManager#getPhoneAccount(PhoneAccountHandle)}. + * @hide + */ + @ChangeId + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S) + // bug ID + public static final long ENABLE_GET_PHONE_ACCOUNT_PERMISSION_PROTECTION = 183407956L; + private static final String TAG = "TelecomManager"; @@ -1351,6 +1361,9 @@ public class TelecomManager { * Return the {@link PhoneAccount} for a specified {@link PhoneAccountHandle}. Object includes * resources which can be used in a user interface. * + * Requires Permission: + * {@link android.Manifest.permission#READ_PHONE_NUMBERS} for applications targeting API + * level 31+. * @param account The {@link PhoneAccountHandle}. * @return The {@link PhoneAccount} object. */ @@ -1358,7 +1371,7 @@ public class TelecomManager { ITelecomService service = getTelecomService(); if (service != null) { try { - return service.getPhoneAccount(account); + return service.getPhoneAccount(account, mContext.getPackageName()); } catch (RemoteException e) { Log.e(TAG, "Error calling ITelecomService#getPhoneAccount", e); } diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl index 18afde742abb..6f286d9f3006 100644 --- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl +++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl @@ -79,7 +79,7 @@ interface ITelecomService { /** * @see TelecomManager#getPhoneAccount */ - PhoneAccount getPhoneAccount(in PhoneAccountHandle account); + PhoneAccount getPhoneAccount(in PhoneAccountHandle account, String callingPackage); /** * @see TelecomManager#getAllPhoneAccountsCount |