Merge "Remove GNSS HAL v3.0 (framework/base)"
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 3ff2546..665deda 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -123,6 +123,20 @@
new_since: ":android-non-updatable.api.public.latest",
},
},
+ dists: [
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/public/api",
+ dest: "android-non-updatable.txt",
+ tag: ".api.txt",
+ },
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/public/api",
+ dest: "android-non-updatable-removed.txt",
+ tag: ".removed-api.txt",
+ },
+ ],
}
priv_apps =
@@ -162,6 +176,20 @@
baseline_file: "core/api/system-lint-baseline.txt",
},
},
+ dists: [
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/system/api",
+ dest: "android-non-updatable.txt",
+ tag: ".api.txt",
+ },
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/system/api",
+ dest: "android-non-updatable-removed.txt",
+ tag: ".removed-api.txt",
+ },
+ ],
}
droidstubs {
@@ -178,11 +206,32 @@
baseline_file: "core/api/test-lint-baseline.txt",
},
},
- dist: {
- targets: ["sdk", "win_sdk"],
- dir: "apistubs/android/test/api",
- dest: "android.txt",
- },
+ dists: [
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/test/api",
+ dest: "android.txt",
+ tag: ".api.txt",
+ },
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/test/api",
+ dest: "removed.txt",
+ tag: ".removed-api.txt",
+ },
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/test/api",
+ dest: "android-non-updatable.txt",
+ tag: ".api.txt",
+ },
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/test/api",
+ dest: "android-non-updatable-removed.txt",
+ tag: ".removed-api.txt",
+ },
+ ],
}
droidstubs {
@@ -203,6 +252,20 @@
new_since: ":android-non-updatable.api.module-lib.latest",
},
},
+ dists: [
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/module-lib/api",
+ dest: "android-non-updatable.txt",
+ tag: ".api.txt",
+ },
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/module-lib/api",
+ dest: "android-non-updatable-removed.txt",
+ tag: ".removed-api.txt",
+ },
+ ],
}
/////////////////////////////////////////////////////////////////////
diff --git a/apex/OWNERS b/apex/OWNERS
index 9760013..bde2bec 100644
--- a/apex/OWNERS
+++ b/apex/OWNERS
@@ -1,7 +1,8 @@
-# Shared module build rule owners
-per-file *.bp=hansson@google.com
-per-file *.bp=jiyong@google.com
+# Mainline modularization team
-# This file, and all other OWNERS files
-per-file OWNERS=dariofreni@google.com
-per-file OWNERS=hansson@google.com
+andreionea@google.com
+dariofreni@google.com
+hansson@google.com
+mathewi@google.com
+pedroql@google.com
+satayev@google.com
diff --git a/apex/appsearch/framework/api/current.txt b/apex/appsearch/framework/api/current.txt
index 2320b75..b1394c1 100644
--- a/apex/appsearch/framework/api/current.txt
+++ b/apex/appsearch/framework/api/current.txt
@@ -22,6 +22,14 @@
method @NonNull public android.app.appsearch.AppSearchManager.SearchContext.Builder setDatabaseName(@NonNull String);
}
+ public interface AppSearchMigrationHelper {
+ method public void queryAndTransform(@NonNull String, @NonNull android.app.appsearch.AppSearchMigrationHelper.Transformer) throws java.lang.Exception;
+ }
+
+ public static interface AppSearchMigrationHelper.Transformer {
+ method @NonNull public android.app.appsearch.GenericDocument transform(int, int, @NonNull android.app.appsearch.GenericDocument) throws java.lang.Exception;
+ }
+
public final class AppSearchResult<ValueType> {
method @Nullable public String getErrorMessage();
method public int getResultCode();
@@ -40,30 +48,82 @@
public final class AppSearchSchema {
method @NonNull public java.util.List<android.app.appsearch.AppSearchSchema.PropertyConfig> getProperties();
method @NonNull public String getSchemaType();
+ method @IntRange(from=0) public int getVersion();
+ }
+
+ public static final class AppSearchSchema.BooleanPropertyConfig extends android.app.appsearch.AppSearchSchema.PropertyConfig {
+ }
+
+ public static final class AppSearchSchema.BooleanPropertyConfig.Builder {
+ ctor public AppSearchSchema.BooleanPropertyConfig.Builder(@NonNull String);
+ method @NonNull public android.app.appsearch.AppSearchSchema.BooleanPropertyConfig build();
+ method @NonNull public android.app.appsearch.AppSearchSchema.BooleanPropertyConfig.Builder setCardinality(int);
}
public static final class AppSearchSchema.Builder {
ctor public AppSearchSchema.Builder(@NonNull String);
method @NonNull public android.app.appsearch.AppSearchSchema.Builder addProperty(@NonNull android.app.appsearch.AppSearchSchema.PropertyConfig);
method @NonNull public android.app.appsearch.AppSearchSchema build();
+ method @NonNull public android.app.appsearch.AppSearchSchema.Builder setVersion(@IntRange(from=0) int);
}
- public static final class AppSearchSchema.PropertyConfig {
+ public static final class AppSearchSchema.BytesPropertyConfig extends android.app.appsearch.AppSearchSchema.PropertyConfig {
+ }
+
+ public static final class AppSearchSchema.BytesPropertyConfig.Builder {
+ ctor public AppSearchSchema.BytesPropertyConfig.Builder(@NonNull String);
+ method @NonNull public android.app.appsearch.AppSearchSchema.BytesPropertyConfig build();
+ method @NonNull public android.app.appsearch.AppSearchSchema.BytesPropertyConfig.Builder setCardinality(int);
+ }
+
+ public static final class AppSearchSchema.DocumentPropertyConfig extends android.app.appsearch.AppSearchSchema.PropertyConfig {
+ method @NonNull public String getSchemaType();
+ method public boolean isIndexNestedProperties();
+ }
+
+ public static final class AppSearchSchema.DocumentPropertyConfig.Builder {
+ ctor public AppSearchSchema.DocumentPropertyConfig.Builder(@NonNull String);
+ method @NonNull public android.app.appsearch.AppSearchSchema.DocumentPropertyConfig build();
+ method @NonNull public android.app.appsearch.AppSearchSchema.DocumentPropertyConfig.Builder setCardinality(int);
+ method @NonNull public android.app.appsearch.AppSearchSchema.DocumentPropertyConfig.Builder setIndexNestedProperties(boolean);
+ method @NonNull public android.app.appsearch.AppSearchSchema.DocumentPropertyConfig.Builder setSchemaType(@NonNull String);
+ }
+
+ public static final class AppSearchSchema.DoublePropertyConfig extends android.app.appsearch.AppSearchSchema.PropertyConfig {
+ }
+
+ public static final class AppSearchSchema.DoublePropertyConfig.Builder {
+ ctor public AppSearchSchema.DoublePropertyConfig.Builder(@NonNull String);
+ method @NonNull public android.app.appsearch.AppSearchSchema.DoublePropertyConfig build();
+ method @NonNull public android.app.appsearch.AppSearchSchema.DoublePropertyConfig.Builder setCardinality(int);
+ }
+
+ public static final class AppSearchSchema.Int64PropertyConfig extends android.app.appsearch.AppSearchSchema.PropertyConfig {
+ }
+
+ public static final class AppSearchSchema.Int64PropertyConfig.Builder {
+ ctor public AppSearchSchema.Int64PropertyConfig.Builder(@NonNull String);
+ method @NonNull public android.app.appsearch.AppSearchSchema.Int64PropertyConfig build();
+ method @NonNull public android.app.appsearch.AppSearchSchema.Int64PropertyConfig.Builder setCardinality(int);
+ }
+
+ public static interface AppSearchSchema.Migrator {
+ method public default void onDowngrade(int, int, @NonNull android.app.appsearch.AppSearchMigrationHelper) throws java.lang.Exception;
+ method public default void onUpgrade(int, int, @NonNull android.app.appsearch.AppSearchMigrationHelper) throws java.lang.Exception;
+ }
+
+ public abstract static class AppSearchSchema.PropertyConfig {
method public int getCardinality();
method public int getDataType();
- method public int getIndexingType();
method @NonNull public String getName();
- method @Nullable public String getSchemaType();
- method public int getTokenizerType();
field public static final int CARDINALITY_OPTIONAL = 2; // 0x2
field public static final int CARDINALITY_REPEATED = 1; // 0x1
field public static final int CARDINALITY_REQUIRED = 3; // 0x3
- field public static final int DATA_TYPE_BOOLEAN = 4; // 0x4
- field public static final int DATA_TYPE_BYTES = 5; // 0x5
- field public static final int DATA_TYPE_DOCUMENT = 6; // 0x6
- field public static final int DATA_TYPE_DOUBLE = 3; // 0x3
- field public static final int DATA_TYPE_INT64 = 2; // 0x2
- field public static final int DATA_TYPE_STRING = 1; // 0x1
+ }
+
+ public static final class AppSearchSchema.StringPropertyConfig extends android.app.appsearch.AppSearchSchema.PropertyConfig {
+ method public int getIndexingType();
+ method public int getTokenizerType();
field public static final int INDEXING_TYPE_EXACT_TERMS = 1; // 0x1
field public static final int INDEXING_TYPE_NONE = 0; // 0x0
field public static final int INDEXING_TYPE_PREFIXES = 2; // 0x2
@@ -71,14 +131,12 @@
field public static final int TOKENIZER_TYPE_PLAIN = 1; // 0x1
}
- public static final class AppSearchSchema.PropertyConfig.Builder {
- ctor public AppSearchSchema.PropertyConfig.Builder(@NonNull String);
- method @NonNull public android.app.appsearch.AppSearchSchema.PropertyConfig build();
- method @NonNull public android.app.appsearch.AppSearchSchema.PropertyConfig.Builder setCardinality(int);
- method @NonNull public android.app.appsearch.AppSearchSchema.PropertyConfig.Builder setDataType(int);
- method @NonNull public android.app.appsearch.AppSearchSchema.PropertyConfig.Builder setIndexingType(int);
- method @NonNull public android.app.appsearch.AppSearchSchema.PropertyConfig.Builder setSchemaType(@NonNull String);
- method @NonNull public android.app.appsearch.AppSearchSchema.PropertyConfig.Builder setTokenizerType(int);
+ public static final class AppSearchSchema.StringPropertyConfig.Builder {
+ ctor public AppSearchSchema.StringPropertyConfig.Builder(@NonNull String);
+ method @NonNull public android.app.appsearch.AppSearchSchema.StringPropertyConfig build();
+ method @NonNull public android.app.appsearch.AppSearchSchema.StringPropertyConfig.Builder setCardinality(int);
+ method @NonNull public android.app.appsearch.AppSearchSchema.StringPropertyConfig.Builder setIndexingType(int);
+ method @NonNull public android.app.appsearch.AppSearchSchema.StringPropertyConfig.Builder setTokenizerType(int);
}
public final class AppSearchSession implements java.io.Closeable {
@@ -89,7 +147,8 @@
method @NonNull public android.app.appsearch.SearchResults query(@NonNull String, @NonNull android.app.appsearch.SearchSpec, @NonNull java.util.concurrent.Executor);
method public void removeByQuery(@NonNull String, @NonNull android.app.appsearch.SearchSpec, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<java.lang.Void>>);
method public void removeByUri(@NonNull android.app.appsearch.RemoveByUriRequest, @NonNull java.util.concurrent.Executor, @NonNull android.app.appsearch.BatchResultCallback<java.lang.String,java.lang.Void>);
- method public void setSchema(@NonNull android.app.appsearch.SetSchemaRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<java.lang.Void>>);
+ method @NonNull public void reportUsage(@NonNull android.app.appsearch.ReportUsageRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<java.lang.Void>>);
+ method public void setSchema(@NonNull android.app.appsearch.SetSchemaRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<android.app.appsearch.SetSchemaResponse>>);
}
public interface BatchResultCallback<KeyType, ValueType> {
@@ -140,11 +199,15 @@
public final class GetByUriRequest {
method @NonNull public String getNamespace();
+ method @NonNull public java.util.Map<java.lang.String,java.util.List<java.lang.String>> getProjections();
method @NonNull public java.util.Set<java.lang.String> getUris();
+ field public static final String PROJECTION_SCHEMA_TYPE_WILDCARD = "*";
}
public static final class GetByUriRequest.Builder {
ctor public GetByUriRequest.Builder();
+ method @NonNull public android.app.appsearch.GetByUriRequest.Builder addProjection(@NonNull String, @NonNull java.lang.String...);
+ method @NonNull public android.app.appsearch.GetByUriRequest.Builder addProjection(@NonNull String, @NonNull java.util.Collection<java.lang.String>);
method @NonNull public android.app.appsearch.GetByUriRequest.Builder addUri(@NonNull java.lang.String...);
method @NonNull public android.app.appsearch.GetByUriRequest.Builder addUri(@NonNull java.util.Collection<java.lang.String>);
method @NonNull public android.app.appsearch.GetByUriRequest build();
@@ -186,7 +249,22 @@
method @NonNull public android.app.appsearch.RemoveByUriRequest.Builder setNamespace(@NonNull String);
}
+ public final class ReportUsageRequest {
+ method @NonNull public String getNamespace();
+ method @NonNull public String getUri();
+ method public long getUsageTimeMillis();
+ }
+
+ public static final class ReportUsageRequest.Builder {
+ ctor public ReportUsageRequest.Builder();
+ method @NonNull public android.app.appsearch.ReportUsageRequest build();
+ method @NonNull public android.app.appsearch.ReportUsageRequest.Builder setNamespace(@NonNull String);
+ method @NonNull public android.app.appsearch.ReportUsageRequest.Builder setUri(@NonNull String);
+ method @NonNull public android.app.appsearch.ReportUsageRequest.Builder setUsageTimeMillis(long);
+ }
+
public final class SearchResult {
+ method @NonNull public String getDatabaseName();
method @NonNull public android.app.appsearch.GenericDocument getDocument();
method @NonNull public java.util.List<android.app.appsearch.SearchResult.MatchInfo> getMatches();
method @NonNull public String getPackageName();
@@ -230,6 +308,8 @@
field public static final int RANKING_STRATEGY_DOCUMENT_SCORE = 1; // 0x1
field public static final int RANKING_STRATEGY_NONE = 0; // 0x0
field public static final int RANKING_STRATEGY_RELEVANCE_SCORE = 3; // 0x3
+ field public static final int RANKING_STRATEGY_USAGE_COUNT = 4; // 0x4
+ field public static final int RANKING_STRATEGY_USAGE_LAST_USED_TIMESTAMP = 5; // 0x5
field public static final int TERM_MATCH_EXACT_ONLY = 1; // 0x1
field public static final int TERM_MATCH_PREFIX = 2; // 0x2
}
@@ -255,6 +335,7 @@
}
public final class SetSchemaRequest {
+ method @NonNull public java.util.Map<java.lang.String,android.app.appsearch.AppSearchSchema.Migrator> getMigrators();
method @NonNull public java.util.Set<android.app.appsearch.AppSearchSchema> getSchemas();
method @NonNull public java.util.Set<java.lang.String> getSchemasNotVisibleToSystemUi();
method @NonNull public java.util.Map<java.lang.String,java.util.Set<android.app.appsearch.PackageIdentifier>> getSchemasVisibleToPackages();
@@ -267,10 +348,26 @@
method @NonNull public android.app.appsearch.SetSchemaRequest.Builder addSchema(@NonNull java.util.Collection<android.app.appsearch.AppSearchSchema>);
method @NonNull public android.app.appsearch.SetSchemaRequest build();
method @NonNull public android.app.appsearch.SetSchemaRequest.Builder setForceOverride(boolean);
+ method @NonNull public android.app.appsearch.SetSchemaRequest.Builder setMigrator(@NonNull String, @NonNull android.app.appsearch.AppSearchSchema.Migrator);
method @NonNull public android.app.appsearch.SetSchemaRequest.Builder setSchemaTypeVisibilityForPackage(@NonNull String, boolean, @NonNull android.app.appsearch.PackageIdentifier);
method @NonNull public android.app.appsearch.SetSchemaRequest.Builder setSchemaTypeVisibilityForSystemUi(@NonNull String, boolean);
}
+ public class SetSchemaResponse {
+ method @NonNull public java.util.Set<java.lang.String> getDeletedTypes();
+ method @NonNull public java.util.Set<java.lang.String> getIncompatibleTypes();
+ method @NonNull public java.util.Set<java.lang.String> getMigratedTypes();
+ method @NonNull public java.util.List<android.app.appsearch.SetSchemaResponse.MigrationFailure> getMigrationFailures();
+ method public boolean isSuccess();
+ }
+
+ public static class SetSchemaResponse.MigrationFailure {
+ method @NonNull public android.app.appsearch.AppSearchResult<java.lang.Void> getAppSearchResult();
+ method @NonNull public String getNamespace();
+ method @NonNull public String getSchemaType();
+ method @NonNull public String getUri();
+ }
+
}
package android.app.appsearch.exceptions {
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
index 6fa8f85..814800e 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
@@ -46,6 +46,7 @@
public class AppSearchManager {
/**
* The default empty database name.
+ *
* @hide
*/
public static final String DEFAULT_DATABASE_NAME = "";
@@ -70,8 +71,8 @@
/**
* Returns the name of the database to create or open.
*
- * <p>Databases with different names are fully separate with distinct types, namespaces,
- * and data.
+ * <p>Databases with different names are fully separate with distinct types, namespaces, and
+ * data.
*/
@NonNull
public String getDatabaseName() {
@@ -126,11 +127,11 @@
* initialization process will create one under the user's credential encrypted directory.
*
* @param searchContext The {@link SearchContext} contains all information to create a new
- * {@link AppSearchSession}
- * @param executor Executor on which to invoke the callback.
- * @param callback The {@link AppSearchResult}<{@link AppSearchSession}> of
- * performing this operation. Or a {@link AppSearchResult} with failure
- * reason code and error information.
+ * {@link AppSearchSession}
+ * @param executor Executor on which to invoke the callback.
+ * @param callback The {@link AppSearchResult}<{@link AppSearchSession}> of performing
+ * this operation. Or a {@link AppSearchResult} with failure reason code and error
+ * information.
*/
public void createSearchSession(
@NonNull SearchContext searchContext,
@@ -140,7 +141,12 @@
Objects.requireNonNull(executor);
Objects.requireNonNull(callback);
AppSearchSession.createSearchSession(
- searchContext, mService, mContext.getUserId(), executor, callback);
+ searchContext,
+ mService,
+ mContext.getUserId(),
+ getPackageName(),
+ executor,
+ callback);
}
/**
@@ -149,10 +155,10 @@
* <p>This process requires an AppSearch native indexing file system. If it's not created, the
* initialization process will create one under the user's credential encrypted directory.
*
- * @param executor Executor on which to invoke the callback.
- * @param callback The {@link AppSearchResult}<{@link GlobalSearchSession}> of
- * performing this operation. Or a {@link AppSearchResult} with failure
- * reason code and error information.
+ * @param executor Executor on which to invoke the callback.
+ * @param callback The {@link AppSearchResult}<{@link GlobalSearchSession}> of performing
+ * this operation. Or a {@link AppSearchResult} with failure reason code and error
+ * information.
*/
public void createGlobalSearchSession(
@NonNull @CallbackExecutor Executor executor,
@@ -160,7 +166,7 @@
Objects.requireNonNull(executor);
Objects.requireNonNull(callback);
GlobalSearchSession.createGlobalSearchSession(
- mService, mContext.getUserId(), executor, callback);
+ mService, mContext.getUserId(), getPackageName(), executor, callback);
}
/**
@@ -170,40 +176,42 @@
* to {@link #setSchema}, if any, to determine how to treat existing documents. The following
* types of schema modifications are always safe and are made without deleting any existing
* documents:
+ *
* <ul>
- * <li>Addition of new types
- * <li>Addition of new
- * {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL
- * OPTIONAL} or
- * {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED
- * REPEATED} properties to a type
- * <li>Changing the cardinality of a data type to be less restrictive (e.g. changing an
- * {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL
- * OPTIONAL} property into a
- * {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED
- * REPEATED} property.
+ * <li>Addition of new types
+ * <li>Addition of new {@link
+ * android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} or
+ * {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED
+ * REPEATED} properties to a type
+ * <li>Changing the cardinality of a data type to be less restrictive (e.g. changing an {@link
+ * android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL}
+ * property into a {@link
+ * android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED REPEATED}
+ * property.
* </ul>
*
* <p>The following types of schema changes are not backwards-compatible:
+ *
* <ul>
- * <li>Removal of an existing type
- * <li>Removal of a property from a type
- * <li>Changing the data type ({@code boolean}, {@code long}, etc.) of an existing property
- * <li>For properties of {@code GenericDocument} type, changing the schema type of
- * {@code GenericDocument}s of that property
- * <li>Changing the cardinality of a data type to be more restrictive (e.g. changing an
- * {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL
- * OPTIONAL} property into a
- * {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED
- * REQUIRED} property).
- * <li>Adding a
- * {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED
- * REQUIRED} property.
+ * <li>Removal of an existing type
+ * <li>Removal of a property from a type
+ * <li>Changing the data type ({@code boolean}, {@code long}, etc.) of an existing property
+ * <li>For properties of {@code GenericDocument} type, changing the schema type of {@code
+ * GenericDocument}s of that property
+ * <li>Changing the cardinality of a data type to be more restrictive (e.g. changing an {@link
+ * android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL}
+ * property into a {@link
+ * android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED REQUIRED}
+ * property).
+ * <li>Adding a {@link
+ * android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED REQUIRED}
+ * property.
* </ul>
- * <p>Supplying a schema with such changes will result in this call returning an
- * {@link AppSearchResult} with a code of {@link AppSearchResult#RESULT_INVALID_SCHEMA} and an
- * error message describing the incompatibility. In this case the previously set schema will
- * remain active.
+ *
+ * <p>Supplying a schema with such changes will result in this call returning an {@link
+ * AppSearchResult} with a code of {@link AppSearchResult#RESULT_INVALID_SCHEMA} and an error
+ * message describing the incompatibility. In this case the previously set schema will remain
+ * active.
*
* <p>If you need to make non-backwards-compatible changes as described above, instead use the
* {@link #setSchema(List, boolean)} method with the {@code forceOverride} parameter set to
@@ -214,8 +222,8 @@
*
* @param request The schema update request.
* @return the result of performing this operation.
- * @deprecated use {@link AppSearchSession#setSchema} instead.
* @hide
+ * @deprecated use {@link AppSearchSession#setSchema} instead.
*/
@NonNull
public AppSearchResult<Void> setSchema(@NonNull SetSchemaRequest request) {
@@ -229,6 +237,7 @@
AndroidFuture<AppSearchResult> future = new AndroidFuture<>();
try {
mService.setSchema(
+ getPackageName(),
DEFAULT_DATABASE_NAME,
schemaBundles,
new ArrayList<>(request.getSchemasNotVisibleToSystemUi()),
@@ -249,21 +258,19 @@
/**
* Index {@link GenericDocument}s into AppSearch.
*
- * <p>You should not call this method directly; instead, use the
- * {@code AppSearch#putDocuments()} API provided by JetPack.
+ * <p>You should not call this method directly; instead, use the {@code
+ * AppSearch#putDocuments()} API provided by JetPack.
*
* <p>Each {@link GenericDocument}'s {@code schemaType} field must be set to the name of a
* schema type previously registered via the {@link #setSchema} method.
*
* @param request {@link PutDocumentsRequest} containing documents to be indexed
- * @return The pending result of performing this operation. The keys of the returned
- * {@link AppSearchBatchResult} are the URIs of the input documents. The values are
- * {@code null} if they were successfully indexed, or a failed {@link AppSearchResult}
- * otherwise.
+ * @return The pending result of performing this operation. The keys of the returned {@link
+ * AppSearchBatchResult} are the URIs of the input documents. The values are {@code null} if
+ * they were successfully indexed, or a failed {@link AppSearchResult} otherwise.
* @throws RuntimeException If an error occurred during the execution.
- *
- * @deprecated use {@link AppSearchSession#putDocuments} instead.
* @hide
+ * @deprecated use {@link AppSearchSession#putDocuments} instead.
*/
public AppSearchBatchResult<String, Void> putDocuments(@NonNull PutDocumentsRequest request) {
// TODO(b/146386470): Transmit these documents as a RemoteStream instead of sending them in
@@ -275,7 +282,11 @@
}
AndroidFuture<AppSearchBatchResult> future = new AndroidFuture<>();
try {
- mService.putDocuments(DEFAULT_DATABASE_NAME, documentBundles, mContext.getUserId(),
+ mService.putDocuments(
+ getPackageName(),
+ DEFAULT_DATABASE_NAME,
+ documentBundles,
+ mContext.getUserId(),
new IAppSearchBatchResultCallback.Stub() {
public void onResult(AppSearchBatchResult result) {
future.complete(result);
@@ -294,19 +305,18 @@
/**
* Retrieves {@link GenericDocument}s by URI.
*
- * <p>You should not call this method directly; instead, use the
- * {@code AppSearch#getDocuments()} API provided by JetPack.
+ * <p>You should not call this method directly; instead, use the {@code
+ * AppSearch#getDocuments()} API provided by JetPack.
*
* @param request {@link GetByUriRequest} containing URIs to be retrieved.
- * @return The pending result of performing this operation. The keys of the returned
- * {@link AppSearchBatchResult} are the input URIs. The values are the returned
- * {@link GenericDocument}s on success, or a failed {@link AppSearchResult} otherwise.
- * URIs that are not found will return a failed {@link AppSearchResult} with a result code
- * of {@link AppSearchResult#RESULT_NOT_FOUND}.
+ * @return The pending result of performing this operation. The keys of the returned {@link
+ * AppSearchBatchResult} are the input URIs. The values are the returned {@link
+ * GenericDocument}s on success, or a failed {@link AppSearchResult} otherwise. URIs that
+ * are not found will return a failed {@link AppSearchResult} with a result code of {@link
+ * AppSearchResult#RESULT_NOT_FOUND}.
* @throws RuntimeException If an error occurred during the execution.
- *
- * @deprecated use {@link AppSearchSession#getByUri} instead.
* @hide
+ * @deprecated use {@link AppSearchSession#getByUri} instead.
*/
public AppSearchBatchResult<String, GenericDocument> getByUri(
@NonNull GetByUriRequest request) {
@@ -315,7 +325,12 @@
List<String> uris = new ArrayList<>(request.getUris());
AndroidFuture<AppSearchBatchResult> future = new AndroidFuture<>();
try {
- mService.getDocuments(DEFAULT_DATABASE_NAME, request.getNamespace(), uris,
+ mService.getDocuments(
+ getPackageName(),
+ DEFAULT_DATABASE_NAME,
+ request.getNamespace(),
+ uris,
+ request.getProjectionsVisibleToPackagesInternal(),
mContext.getUserId(),
new IAppSearchBatchResultCallback.Stub() {
public void onResult(AppSearchBatchResult result) {
@@ -371,43 +386,39 @@
* provided by JetPack.
*
* <p>Currently we support following features in the raw query format:
+ *
* <ul>
- * <li>AND
- * <p>AND joins (e.g. “match documents that have both the terms ‘dog’ and
- * ‘cat’”).
- * Example: hello world matches documents that have both ‘hello’ and ‘world’
- * <li>OR
- * <p>OR joins (e.g. “match documents that have either the term ‘dog’ or
- * ‘cat’”).
- * Example: dog OR puppy
- * <li>Exclusion
- * <p>Exclude a term (e.g. “match documents that do
- * not have the term ‘dog’”).
- * Example: -dog excludes the term ‘dog’
- * <li>Grouping terms
- * <p>Allow for conceptual grouping of subqueries to enable hierarchical structures (e.g.
- * “match documents that have either ‘dog’ or ‘puppy’, and either ‘cat’ or ‘kitten’”).
- * Example: (dog puppy) (cat kitten) two one group containing two terms.
- * <li>Property restricts
- * <p> Specifies which properties of a document to specifically match terms in (e.g.
- * “match documents where the ‘subject’ property contains ‘important’”).
- * Example: subject:important matches documents with the term ‘important’ in the
- * ‘subject’ property
- * <li>Schema type restricts
- * <p>This is similar to property restricts, but allows for restricts on top-level document
- * fields, such as schema_type. Clients should be able to limit their query to documents of
- * a certain schema_type (e.g. “match documents that are of the ‘Email’ schema_type”).
- * Example: { schema_type_filters: “Email”, “Video”,query: “dog” } will match documents
- * that contain the query term ‘dog’ and are of either the ‘Email’ schema type or the
- * ‘Video’ schema type.
+ * <li>AND
+ * <p>AND joins (e.g. “match documents that have both the terms ‘dog’ and ‘cat’”).
+ * Example: hello world matches documents that have both ‘hello’ and ‘world’
+ * <li>OR
+ * <p>OR joins (e.g. “match documents that have either the term ‘dog’ or ‘cat’”). Example:
+ * dog OR puppy
+ * <li>Exclusion
+ * <p>Exclude a term (e.g. “match documents that do not have the term ‘dog’”). Example:
+ * -dog excludes the term ‘dog’
+ * <li>Grouping terms
+ * <p>Allow for conceptual grouping of subqueries to enable hierarchical structures (e.g.
+ * “match documents that have either ‘dog’ or ‘puppy’, and either ‘cat’ or ‘kitten’”).
+ * Example: (dog puppy) (cat kitten) two one group containing two terms.
+ * <li>Property restricts
+ * <p>Specifies which properties of a document to specifically match terms in (e.g. “match
+ * documents where the ‘subject’ property contains ‘important’”). Example:
+ * subject:important matches documents with the term ‘important’ in the ‘subject’ property
+ * <li>Schema type restricts
+ * <p>This is similar to property restricts, but allows for restricts on top-level
+ * document fields, such as schema_type. Clients should be able to limit their query to
+ * documents of a certain schema_type (e.g. “match documents that are of the ‘Email’
+ * schema_type”). Example: { schema_type_filters: “Email”, “Video”,query: “dog” } will
+ * match documents that contain the query term ‘dog’ and are of either the ‘Email’ schema
+ * type or the ‘Video’ schema type.
* </ul>
*
* @param queryExpression Query String to search.
* @param searchSpec Spec for setting filters, raw query etc.
* @throws RuntimeException If an error occurred during the execution.
- *
- * @deprecated use AppSearchSession#query instead.
* @hide
+ * @deprecated use AppSearchSession#query instead.
*/
@NonNull
public AppSearchResult<List<SearchResult>> query(
@@ -416,7 +427,11 @@
// them in one big list.
AndroidFuture<AppSearchResult> future = new AndroidFuture<>();
try {
- mService.query(DEFAULT_DATABASE_NAME, queryExpression, searchSpec.getBundle(),
+ mService.query(
+ getPackageName(),
+ DEFAULT_DATABASE_NAME,
+ queryExpression,
+ searchSpec.getBundle(),
mContext.getUserId(),
new IAppSearchResultCallback.Stub() {
public void onResult(AppSearchResult result) {
@@ -425,8 +440,8 @@
});
AppSearchResult<Bundle> bundleResult = getFutureOrThrow(future);
if (!bundleResult.isSuccess()) {
- return AppSearchResult.newFailedResult(bundleResult.getResultCode(),
- bundleResult.getErrorMessage());
+ return AppSearchResult.newFailedResult(
+ bundleResult.getResultCode(), bundleResult.getErrorMessage());
}
SearchResultPage searchResultPage = new SearchResultPage(bundleResult.getResultValue());
return AppSearchResult.newSuccessfulResult(searchResultPage.getResults());
@@ -444,21 +459,23 @@
* provided by JetPack.
*
* @param request Request containing URIs to be removed.
- * @return The pending result of performing this operation. The keys of the returned
- * {@link AppSearchBatchResult} are the input URIs. The values are {@code null} on success,
- * or a failed {@link AppSearchResult} otherwise. URIs that are not found will return a
- * failed {@link AppSearchResult} with a result code of
- * {@link AppSearchResult#RESULT_NOT_FOUND}.
+ * @return The pending result of performing this operation. The keys of the returned {@link
+ * AppSearchBatchResult} are the input URIs. The values are {@code null} on success, or a
+ * failed {@link AppSearchResult} otherwise. URIs that are not found will return a failed
+ * {@link AppSearchResult} with a result code of {@link AppSearchResult#RESULT_NOT_FOUND}.
* @throws RuntimeException If an error occurred during the execution.
- *
- * @deprecated use {@link AppSearchSession#removeByUri} instead.
* @hide
+ * @deprecated use {@link AppSearchSession#removeByUri} instead.
*/
public AppSearchBatchResult<String, Void> removeByUri(@NonNull RemoveByUriRequest request) {
List<String> uris = new ArrayList<>(request.getUris());
AndroidFuture<AppSearchBatchResult> future = new AndroidFuture<>();
try {
- mService.removeByUri(DEFAULT_DATABASE_NAME, request.getNamespace(), uris,
+ mService.removeByUri(
+ getPackageName(),
+ DEFAULT_DATABASE_NAME,
+ request.getNamespace(),
+ uris,
mContext.getUserId(),
new IAppSearchBatchResultCallback.Stub() {
public void onResult(AppSearchBatchResult result) {
@@ -475,6 +492,12 @@
return getFutureOrThrow(future);
}
+ /** Returns the package name that should be used for uid verification. */
+ @NonNull
+ private String getPackageName() {
+ return mContext.getOpPackageName();
+ }
+
private static <T> T getFutureOrThrow(@NonNull AndroidFuture<T> future) {
try {
return future.get();
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
index 0427577..670f8b9 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
@@ -45,6 +45,7 @@
*/
public final class AppSearchSession implements Closeable {
private static final String TAG = "AppSearchSession";
+ private final String mPackageName;
private final String mDatabaseName;
@UserIdInt
private final int mUserId;
@@ -52,14 +53,20 @@
private boolean mIsMutated = false;
private boolean mIsClosed = false;
+
+ /**
+ * Creates a search session for the client, defined by the {@code userId} and
+ * {@code packageName}.
+ */
static void createSearchSession(
@NonNull AppSearchManager.SearchContext searchContext,
@NonNull IAppSearchManager service,
@UserIdInt int userId,
+ @NonNull String packageName,
@NonNull @CallbackExecutor Executor executor,
@NonNull Consumer<AppSearchResult<AppSearchSession>> callback) {
AppSearchSession searchSession =
- new AppSearchSession(service, userId, searchContext.mDatabaseName);
+ new AppSearchSession(service, userId, packageName, searchContext.mDatabaseName);
searchSession.initialize(executor, callback);
}
@@ -87,10 +94,11 @@
}
private AppSearchSession(@NonNull IAppSearchManager service, @UserIdInt int userId,
- @NonNull String databaseName) {
- mDatabaseName = databaseName;
+ @NonNull String packageName, @NonNull String databaseName) {
mService = service;
mUserId = userId;
+ mPackageName = packageName;
+ mDatabaseName = databaseName;
}
/**
@@ -144,7 +152,7 @@
* Visibility settings for a schema type do not apply or persist across
* {@link SetSchemaRequest}s.
*
- * @param request The schema update request.
+ * @param request The schema update request.
* @param executor Executor on which to invoke the callback.
* @param callback Callback to receive errors resulting from setting the schema. If the
* operation succeeds, the callback will be invoked with {@code null}.
@@ -154,7 +162,7 @@
public void setSchema(
@NonNull SetSchemaRequest request,
@NonNull @CallbackExecutor Executor executor,
- @NonNull Consumer<AppSearchResult<Void>> callback) {
+ @NonNull Consumer<AppSearchResult<SetSchemaResponse>> callback) {
Objects.requireNonNull(request);
Objects.requireNonNull(executor);
Objects.requireNonNull(callback);
@@ -175,6 +183,7 @@
}
try {
mService.setSchema(
+ mPackageName,
mDatabaseName,
schemaBundles,
new ArrayList<>(request.getSchemasNotVisibleToSystemUi()),
@@ -183,7 +192,18 @@
mUserId,
new IAppSearchResultCallback.Stub() {
public void onResult(AppSearchResult result) {
- executor.execute(() -> callback.accept(result));
+ executor.execute(() -> {
+ if (result.isSuccess()) {
+ callback.accept(
+ // TODO(b/151178558) implement Migration in platform.
+ AppSearchResult.newSuccessfulResult(
+ new SetSchemaResponse.Builder().setResultCode(
+ result.getResultCode())
+ .build()));
+ } else {
+ callback.accept(result);
+ }
+ });
}
});
mIsMutated = true;
@@ -206,6 +226,7 @@
Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed");
try {
mService.getSchema(
+ mPackageName,
mDatabaseName,
mUserId,
new IAppSearchResultCallback.Stub() {
@@ -261,7 +282,7 @@
documentBundles.add(documents.get(i).getBundle());
}
try {
- mService.putDocuments(mDatabaseName, documentBundles, mUserId,
+ mService.putDocuments(mPackageName, mDatabaseName, documentBundles, mUserId,
new IAppSearchBatchResultCallback.Stub() {
public void onResult(AppSearchBatchResult result) {
executor.execute(() -> callback.onResult(result));
@@ -280,7 +301,7 @@
/**
* Retrieves {@link GenericDocument}s by URI.
*
- * @param request {@link GetByUriRequest} containing URIs to be retrieved.
+ * @param request {@link GetByUriRequest} containing URIs to be retrieved.
* @param executor Executor on which to invoke the callback.
* @param callback Callback to receive the pending result of performing this operation. The keys
* of the returned {@link AppSearchBatchResult} are the input URIs. The values
@@ -301,8 +322,13 @@
Objects.requireNonNull(callback);
Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed");
try {
- mService.getDocuments(mDatabaseName, request.getNamespace(),
- new ArrayList<>(request.getUris()), mUserId,
+ mService.getDocuments(
+ mPackageName,
+ mDatabaseName,
+ request.getNamespace(),
+ new ArrayList<>(request.getUris()),
+ request.getProjectionsVisibleToPackagesInternal(),
+ mUserId,
new IAppSearchBatchResultCallback.Stub() {
public void onResult(AppSearchBatchResult result) {
executor.execute(() -> {
@@ -405,14 +431,59 @@
Objects.requireNonNull(searchSpec);
Objects.requireNonNull(executor);
Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed");
- return new SearchResults(mService, mDatabaseName, queryExpression, searchSpec, mUserId,
- executor);
+ return new SearchResults(mService, mPackageName, mDatabaseName, queryExpression,
+ searchSpec, mUserId, executor);
+ }
+
+ /**
+ * Reports usage of a particular document by URI and namespace.
+ *
+ * <p>A usage report represents an event in which a user interacted with or viewed a document.
+ *
+ * <p>For each call to {@link #reportUsage}, AppSearch updates usage count and usage recency
+ * metrics for that particular document. These metrics are used for ordering {@link #query}
+ * results by the {@link SearchSpec#RANKING_STRATEGY_USAGE_COUNT} and
+ * {@link SearchSpec#RANKING_STRATEGY_USAGE_LAST_USED_TIMESTAMP} ranking strategies.
+ *
+ * <p>Reporting usage of a document is optional.
+ *
+ * @param request The usage reporting request.
+ * @param executor Executor on which to invoke the callback.
+ * @param callback Callback to receive errors. If the operation succeeds, the callback will be
+ * invoked with {@code null}.
+ */
+ @NonNull
+ public void reportUsage(
+ @NonNull ReportUsageRequest request,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<AppSearchResult<Void>> callback) {
+ Objects.requireNonNull(request);
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
+ Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed");
+ try {
+ mService.reportUsage(
+ mPackageName,
+ mDatabaseName,
+ request.getNamespace(),
+ request.getUri(),
+ request.getUsageTimeMillis(),
+ mUserId,
+ new IAppSearchResultCallback.Stub() {
+ public void onResult(AppSearchResult result) {
+ executor.execute(() -> callback.accept(result));
+ }
+ });
+ mIsMutated = true;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
* Removes {@link GenericDocument}s from the index by URI.
*
- * @param request Request containing URIs to be removed.
+ * @param request Request containing URIs to be removed.
* @param executor Executor on which to invoke the callback.
* @param callback Callback to receive the pending result of performing this operation. The keys
* of the returned {@link AppSearchBatchResult} are the input URIs. The values
@@ -432,7 +503,7 @@
Objects.requireNonNull(callback);
Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed");
try {
- mService.removeByUri(mDatabaseName, request.getNamespace(),
+ mService.removeByUri(mPackageName, mDatabaseName, request.getNamespace(),
new ArrayList<>(request.getUris()), mUserId,
new IAppSearchBatchResultCallback.Stub() {
public void onResult(AppSearchBatchResult result) {
@@ -478,7 +549,8 @@
Objects.requireNonNull(callback);
Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed");
try {
- mService.removeByQuery(mDatabaseName, queryExpression, searchSpec.getBundle(), mUserId,
+ mService.removeByQuery(mPackageName, mDatabaseName, queryExpression,
+ searchSpec.getBundle(), mUserId,
new IAppSearchResultCallback.Stub() {
public void onResult(AppSearchResult result) {
executor.execute(() -> callback.accept(result));
diff --git a/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java
index e4e030e..6bb8554 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java
@@ -37,16 +37,25 @@
public class GlobalSearchSession implements Closeable {
private final IAppSearchManager mService;
+
@UserIdInt
private final int mUserId;
private boolean mIsClosed = false;
+ private final String mPackageName;
+
+ /**
+ * Creates a search session for the client, defined by the {@code userId} and
+ * {@code packageName}.
+ */
static void createGlobalSearchSession(
@NonNull IAppSearchManager service,
@UserIdInt int userId,
+ @NonNull String packageName,
@NonNull @CallbackExecutor Executor executor,
@NonNull Consumer<AppSearchResult<GlobalSearchSession>> callback) {
- GlobalSearchSession globalSearchSession = new GlobalSearchSession(service, userId);
+ GlobalSearchSession globalSearchSession = new GlobalSearchSession(service, userId,
+ packageName);
globalSearchSession.initialize(executor, callback);
}
@@ -73,9 +82,11 @@
}
}
- private GlobalSearchSession(@NonNull IAppSearchManager service, @UserIdInt int userId) {
+ private GlobalSearchSession(@NonNull IAppSearchManager service, @UserIdInt int userId,
+ @NonNull String packageName) {
mService = service;
mUserId = userId;
+ mPackageName = packageName;
}
/**
@@ -131,7 +142,7 @@
Objects.requireNonNull(searchSpec);
Objects.requireNonNull(executor);
Preconditions.checkState(!mIsClosed, "GlobalSearchSession has already been closed");
- return new SearchResults(mService, /*databaseName=*/null, queryExpression,
+ return new SearchResults(mService, mPackageName, /*databaseName=*/null, queryExpression,
searchSpec, mUserId, executor);
}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
index 2b43777..68ae23f 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
+++ b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
@@ -30,6 +30,7 @@
/**
* Updates the AppSearch schema for this database.
*
+ * @param packageName The name of the package that owns this schema.
* @param databaseName The name of the database where this schema lives.
* @param schemaBundles List of {@link AppSearchSchema} bundles.
* @param schemasNotPlatformSurfaceable Schema types that should not be surfaced on platform
@@ -43,6 +44,7 @@
* {@link AppSearchResult}<{@link Void}>.
*/
void setSchema(
+ in String packageName,
in String databaseName,
in List<Bundle> schemaBundles,
in List<String> schemasNotPlatformSurfaceable,
@@ -54,17 +56,23 @@
/**
* Retrieves the AppSearch schema for this database.
*
+ * @param packageName The name of the package that owns the schema.
* @param databaseName The name of the database to retrieve.
* @param userId Id of the calling user
* @param callback {@link IAppSearchResultCallback#onResult} will be called with an
* {@link AppSearchResult}<{@link List}<{@link Bundle}>>, where the value are
* AppSearchSchema bundle.
*/
- void getSchema(in String databaseName, in int userId, in IAppSearchResultCallback callback);
+ void getSchema(
+ in String packageName,
+ in String databaseName,
+ in int userId,
+ in IAppSearchResultCallback callback);
/**
* Inserts documents into the index.
*
+ * @param packageName The name of the package that owns this document.
* @param databaseName The name of the database where this document lives.
* @param documentBundes List of GenericDocument bundles.
* @param userId Id of the calling user
@@ -76,6 +84,7 @@
* where the keys are document URIs, and the values are {@code null}.
*/
void putDocuments(
+ in String packageName,
in String databaseName,
in List<Bundle> documentBundles,
in int userId,
@@ -84,9 +93,12 @@
/**
* Retrieves documents from the index.
*
+ * @param packageName The name of the package that owns this document.
* @param databaseName The databaseName this document resides in.
* @param namespace The namespace this document resides in.
* @param uris The URIs of the documents to retrieve
+ * @param typePropertyPaths A map of schema type to a list of property paths to return in the
+ * result.
* @param userId Id of the calling user
* @param callback
* If the call fails to start, {@link IAppSearchBatchResultCallback#onSystemError}
@@ -96,15 +108,18 @@
* where the keys are document URIs, and the values are Document bundles.
*/
void getDocuments(
+ in String packageName,
in String databaseName,
in String namespace,
in List<String> uris,
+ in Map<String, List<String>> typePropertyPaths,
in int userId,
in IAppSearchBatchResultCallback callback);
/**
* Searches a document based on a given specifications.
*
+ * @param packageName The name of the package to query over.
* @param databaseName The databaseName this query for.
* @param queryExpression String to search for
* @param searchSpecBundle SearchSpec bundle
@@ -113,6 +128,7 @@
* operation.
*/
void query(
+ in String packageName,
in String databaseName,
in String queryExpression,
in Bundle searchSpecBundle,
@@ -123,6 +139,7 @@
* Executes a global query, i.e. over all permitted databases, against the AppSearch index and
* returns results.
*
+ * @param packageName The name of the package making the query.
* @param queryExpression String to search for
* @param searchSpecBundle SearchSpec bundle
* @param userId Id of the calling user
@@ -130,6 +147,7 @@
* operation.
*/
void globalQuery(
+ in String packageName,
in String queryExpression,
in Bundle searchSpecBundle,
in int userId,
@@ -156,8 +174,39 @@
void invalidateNextPageToken(in long nextPageToken, in int userId);
/**
+ * Reports usage of a particular document by URI and namespace.
+ *
+ * <p>A usage report represents an event in which a user interacted with or viewed a document.
+ *
+ * <p>For each call to {@link #reportUsage}, AppSearch updates usage count and usage recency
+ * metrics for that particular document. These metrics are used for ordering {@link #query}
+ * results by the {@link SearchSpec#RANKING_STRATEGY_USAGE_COUNT} and
+ * {@link SearchSpec#RANKING_STRATEGY_USAGE_LAST_USED_TIMESTAMP} ranking strategies.
+ *
+ * <p>Reporting usage of a document is optional.
+ *
+ * @param packageName The name of the package that owns this document.
+ * @param databaseName The name of the database to report usage against.
+ * @param namespace Namespace the document being used belongs to.
+ * @param uri URI of the document being used.
+ * @param usageTimeMillis The timestamp at which the document was used.
+ * @param userId Id of the calling user
+ * @param callback {@link IAppSearchResultCallback#onResult} will be called with an
+ * {@link AppSearchResult}<{@link Void}>.
+ */
+ void reportUsage(
+ in String packageName,
+ in String databaseName,
+ in String namespace,
+ in String uri,
+ in long usageTimeMillis,
+ in int userId,
+ in IAppSearchResultCallback callback);
+
+ /**
* Removes documents by URI.
*
+ * @param packageName The name of the package the document is in.
* @param databaseName The databaseName the document is in.
* @param namespace Namespace of the document to remove.
* @param uris The URIs of the documents to delete
@@ -171,6 +220,7 @@
* failure where the {@code throwable} is {@code null}.
*/
void removeByUri(
+ in String packageName,
in String databaseName,
in String namespace,
in List<String> uris,
@@ -180,6 +230,7 @@
/**
* Removes documents by given query.
*
+ * @param packageName The name of the package to query over.
* @param databaseName The databaseName this query for.
* @param queryExpression String to search for
* @param searchSpecBundle SearchSpec bundle
@@ -188,6 +239,7 @@
* {@link AppSearchResult}<{@link Void}>.
*/
void removeByQuery(
+ in String packageName,
in String databaseName,
in String queryExpression,
in Bundle searchSpecBundle,
diff --git a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java b/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
index 0cb0ea4..704509b 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
@@ -47,6 +47,9 @@
private final IAppSearchManager mService;
+ // The package name of the caller.
+ private final String mPackageName;
+
// The database name to search over. If null, this will search over all database names.
@Nullable
private final String mDatabaseName;
@@ -68,12 +71,14 @@
SearchResults(
@NonNull IAppSearchManager service,
+ @NonNull String packageName,
@Nullable String databaseName,
@NonNull String queryExpression,
@NonNull SearchSpec searchSpec,
@UserIdInt int userId,
@NonNull @CallbackExecutor Executor executor) {
mService = Objects.requireNonNull(service);
+ mPackageName = packageName;
mDatabaseName = databaseName;
mQueryExpression = Objects.requireNonNull(queryExpression);
mSearchSpec = Objects.requireNonNull(searchSpec);
@@ -98,13 +103,12 @@
mIsFirstLoad = false;
if (mDatabaseName == null) {
// Global query, there's no one package-database combination to check.
- mService.globalQuery(mQueryExpression, mSearchSpec.getBundle(), mUserId,
- wrapCallback(callback));
+ mService.globalQuery(mPackageName, mQueryExpression,
+ mSearchSpec.getBundle(), mUserId, wrapCallback(callback));
} else {
// Normal local query, pass in specified database.
- mService.query(
- mDatabaseName, mQueryExpression, mSearchSpec.getBundle(), mUserId,
- wrapCallback(callback));
+ mService.query(mPackageName, mDatabaseName, mQueryExpression,
+ mSearchSpec.getBundle(), mUserId, wrapCallback(callback));
}
} else {
mService.getNextPage(mNextPageToken, mUserId, wrapCallback(callback));
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchEmail.java b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchEmail.java
index 9ca363e..d394904 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchEmail.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchEmail.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.appsearch.AppSearchSchema.PropertyConfig;
+import android.app.appsearch.AppSearchSchema.StringPropertyConfig;
/**
* Encapsulates a {@link GenericDocument} that represent an email.
@@ -41,46 +42,40 @@
public static final AppSearchSchema SCHEMA =
new AppSearchSchema.Builder(SCHEMA_TYPE)
.addProperty(
- new PropertyConfig.Builder(KEY_FROM)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
+ new StringPropertyConfig.Builder(KEY_FROM)
.setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
.build())
.addProperty(
- new PropertyConfig.Builder(KEY_TO)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
+ new StringPropertyConfig.Builder(KEY_TO)
.setCardinality(PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
.build())
.addProperty(
- new PropertyConfig.Builder(KEY_CC)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
+ new StringPropertyConfig.Builder(KEY_CC)
.setCardinality(PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
.build())
.addProperty(
- new PropertyConfig.Builder(KEY_BCC)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
+ new StringPropertyConfig.Builder(KEY_BCC)
.setCardinality(PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
.build())
.addProperty(
- new PropertyConfig.Builder(KEY_SUBJECT)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
+ new StringPropertyConfig.Builder(KEY_SUBJECT)
.setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
.build())
.addProperty(
- new PropertyConfig.Builder(KEY_BODY)
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
+ new StringPropertyConfig.Builder(KEY_BODY)
.setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
.build())
.build();
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchMigrationHelper.java b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchMigrationHelper.java
new file mode 100644
index 0000000..37943fc
--- /dev/null
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchMigrationHelper.java
@@ -0,0 +1,65 @@
+/*
+ * 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 android.app.appsearch;
+
+import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+
+/**
+ * The helper class for {@link AppSearchSchema} migration.
+ *
+ * <p>It will query and migrate {@link GenericDocument} in given type to a new version.
+ */
+public interface AppSearchMigrationHelper {
+
+ /**
+ * Queries all documents that need to be migrated to the different version, and transform
+ * documents to that version by passing them to the provided {@link Transformer}.
+ *
+ * @param schemaType The schema that need be updated and migrated {@link GenericDocument} under
+ * this type.
+ * @param transformer The {@link Transformer} that will upgrade or downgrade a {@link
+ * GenericDocument} to new version.
+ * @see Transformer#transform
+ */
+ // Rethrow the Generic Exception thrown from the Transformer.
+ @SuppressLint("GenericException")
+ void queryAndTransform(@NonNull String schemaType, @NonNull Transformer transformer)
+ throws Exception;
+
+ /** The class to migrate {@link GenericDocument} between different version. */
+ interface Transformer {
+
+ /**
+ * Translates a {@link GenericDocument} from a version to a different version.
+ *
+ * <p>If the uri, schema type or namespace is changed via the transform, it will apply to
+ * the new {@link GenericDocument}.
+ *
+ * @param currentVersion The current version of the document's schema.
+ * @param finalVersion The final version that documents need to be migrated to.
+ * @param document The {@link GenericDocument} need to be translated to new version.
+ * @return A {@link GenericDocument} in new version.
+ */
+ @NonNull
+ // This method will be overridden by users, allow them to throw any customer Exceptions.
+ @SuppressLint("GenericException")
+ GenericDocument transform(
+ int currentVersion, int finalVersion, @NonNull GenericDocument document)
+ throws Exception;
+ }
+}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java
index 62cf38b..2e00ff2 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java
@@ -17,6 +17,7 @@
package android.app.appsearch;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
@@ -46,6 +47,7 @@
*/
public final class AppSearchSchema {
private static final String SCHEMA_TYPE_FIELD = "schemaType";
+ private static final String VERSION_FIELD = "version";
private static final String PROPERTIES_FIELD = "properties";
private final Bundle mBundle;
@@ -77,6 +79,11 @@
return mBundle.getString(SCHEMA_TYPE_FIELD, "");
}
+ /** Returns the version of this {@link AppSearchSchema}. */
+ public @IntRange(from = 0) int getVersion() {
+ return mBundle.getInt(VERSION_FIELD);
+ }
+
/**
* Returns the list of {@link PropertyConfig}s that are part of this schema.
*
@@ -91,7 +98,7 @@
}
List<PropertyConfig> ret = new ArrayList<>(propertyBundles.size());
for (int i = 0; i < propertyBundles.size(); i++) {
- ret.add(new PropertyConfig(propertyBundles.get(i)));
+ ret.add(PropertyConfig.fromBundle(propertyBundles.get(i)));
}
return ret;
}
@@ -108,12 +115,15 @@
if (!getSchemaType().equals(otherSchema.getSchemaType())) {
return false;
}
+ if (getVersion() != otherSchema.getVersion()) {
+ return false;
+ }
return getProperties().equals(otherSchema.getProperties());
}
@Override
public int hashCode() {
- return Objects.hash(getSchemaType(), getProperties());
+ return Objects.hash(getSchemaType(), getVersion(), getProperties());
}
/** Builder for {@link AppSearchSchema objects}. */
@@ -121,6 +131,7 @@
private final String mSchemaType;
private final ArrayList<Bundle> mPropertyBundles = new ArrayList<>();
private final Set<String> mPropertyNames = new ArraySet<>();
+ private int mVersion;
private boolean mBuilt = false;
/** Creates a new {@link AppSearchSchema.Builder}. */
@@ -147,6 +158,42 @@
}
/**
+ * Sets the version number of the {@link AppSearchSchema}.
+ *
+ * <p>The {@link AppSearchSession} database can only ever hold documents for one version of
+ * a {@link AppSearchSchema} type at a time.
+ *
+ * <p>Setting a version number that is different from the version number of the schema
+ * currently stored in AppSearch will result in AppSearch calling the {@link Migrator}
+ * provided to {@link AppSearchSession#setSchema} to migrate the documents already in
+ * AppSearch from the previous version to the one set in this request. The version number
+ * can be updated without any other changes to the schema.
+ *
+ * <p>The version number can stay the same, increase, or decrease relative to the current
+ * version number of the {@link AppSearchSchema} type that is already stored in the {@link
+ * AppSearchSession} database.
+ *
+ * <p>The version number will be updated if the {@link SetSchemaRequest} contains
+ * backwards-compatible changes or {@link SetSchemaRequest.Builder#setForceOverride} method
+ * is set to {@code true}.
+ *
+ * @param version A non-negative int number represents the version of this {@link
+ * AppSearchSchema}, default version is 0.
+ * @throws IllegalStateException if the version is negative or the builder has already been
+ * used.
+ * @see AppSearchSession#setSchema
+ * @see AppSearchSchema.Migrator
+ * @see SetSchemaRequest.Builder#setMigrator
+ */
+ @NonNull
+ public AppSearchSchema.Builder setVersion(@IntRange(from = 0) int version) {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ Preconditions.checkArgumentNonnegative(version);
+ mVersion = version;
+ return this;
+ }
+
+ /**
* Constructs a new {@link AppSearchSchema} from the contents of this builder.
*
* <p>After calling this method, the builder must no longer be used.
@@ -156,6 +203,7 @@
Preconditions.checkState(!mBuilt, "Builder has already been used");
Bundle bundle = new Bundle();
bundle.putString(AppSearchSchema.SCHEMA_TYPE_FIELD, mSchemaType);
+ bundle.putInt(AppSearchSchema.VERSION_FIELD, mVersion);
bundle.putParcelableArrayList(AppSearchSchema.PROPERTIES_FIELD, mPropertyBundles);
mBuilt = true;
return new AppSearchSchema(bundle);
@@ -163,18 +211,15 @@
}
/**
- * Configuration for a single property (field) of a document type.
+ * Common configuration for a single property (field) in a Document.
*
* <p>For example, an {@code EmailMessage} would be a type and the {@code subject} would be a
* property.
*/
- public static final class PropertyConfig {
- private static final String NAME_FIELD = "name";
- private static final String DATA_TYPE_FIELD = "dataType";
- private static final String SCHEMA_TYPE_FIELD = "schemaType";
- private static final String CARDINALITY_FIELD = "cardinality";
- private static final String INDEXING_TYPE_FIELD = "indexingType";
- private static final String TOKENIZER_TYPE_FIELD = "tokenizerType";
+ public abstract static class PropertyConfig {
+ static final String NAME_FIELD = "name";
+ static final String DATA_TYPE_FIELD = "dataType";
+ static final String CARDINALITY_FIELD = "cardinality";
/**
* Physical data-types of the contents of the property.
@@ -195,18 +240,31 @@
@Retention(RetentionPolicy.SOURCE)
public @interface DataType {}
+ /** @hide */
public static final int DATA_TYPE_STRING = 1;
+
+ /** @hide */
public static final int DATA_TYPE_INT64 = 2;
+
+ /** @hide */
public static final int DATA_TYPE_DOUBLE = 3;
+
+ /** @hide */
public static final int DATA_TYPE_BOOLEAN = 4;
- /** Unstructured BLOB. */
+ /**
+ * Unstructured BLOB.
+ *
+ * @hide
+ */
public static final int DATA_TYPE_BYTES = 5;
/**
* Indicates that the property is itself a {@link GenericDocument}, making it part of a
* hierarchical schema. Any property using this DataType MUST have a valid {@link
* PropertyConfig#getSchemaType}.
+ *
+ * @hide
*/
public static final int DATA_TYPE_DOCUMENT = 6;
@@ -235,6 +293,97 @@
/** Exactly one value [1]. */
public static final int CARDINALITY_REQUIRED = 3;
+ final Bundle mBundle;
+
+ @Nullable private Integer mHashCode;
+
+ PropertyConfig(@NonNull Bundle bundle) {
+ mBundle = Preconditions.checkNotNull(bundle);
+ }
+
+ @Override
+ public String toString() {
+ return mBundle.toString();
+ }
+
+ /** Returns the name of this property. */
+ @NonNull
+ public String getName() {
+ return mBundle.getString(NAME_FIELD, "");
+ }
+
+ /** Returns the type of data the property contains (e.g. string, int, bytes, etc). */
+ public @DataType int getDataType() {
+ return mBundle.getInt(DATA_TYPE_FIELD, -1);
+ }
+
+ /**
+ * Returns the cardinality of the property (whether it is optional, required or repeated).
+ */
+ public @Cardinality int getCardinality() {
+ return mBundle.getInt(CARDINALITY_FIELD, -1);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof PropertyConfig)) {
+ return false;
+ }
+ PropertyConfig otherProperty = (PropertyConfig) other;
+ return BundleUtil.deepEquals(this.mBundle, otherProperty.mBundle);
+ }
+
+ @Override
+ public int hashCode() {
+ if (mHashCode == null) {
+ mHashCode = BundleUtil.deepHashCode(mBundle);
+ }
+ return mHashCode;
+ }
+
+ /**
+ * Converts a {@link Bundle} into a {@link PropertyConfig} depending on its internal data
+ * type.
+ *
+ * <p>The bundle is not cloned.
+ *
+ * @throws IllegalArgumentException if the bundle does no contain a recognized value in its
+ * {@code DATA_TYPE_FIELD}.
+ * @hide
+ */
+ @NonNull
+ public static PropertyConfig fromBundle(@NonNull Bundle propertyBundle) {
+ switch (propertyBundle.getInt(PropertyConfig.DATA_TYPE_FIELD)) {
+ case PropertyConfig.DATA_TYPE_STRING:
+ return new StringPropertyConfig(propertyBundle);
+ case PropertyConfig.DATA_TYPE_INT64:
+ return new Int64PropertyConfig(propertyBundle);
+ case PropertyConfig.DATA_TYPE_DOUBLE:
+ return new DoublePropertyConfig(propertyBundle);
+ case PropertyConfig.DATA_TYPE_BOOLEAN:
+ return new BooleanPropertyConfig(propertyBundle);
+ case PropertyConfig.DATA_TYPE_BYTES:
+ return new BytesPropertyConfig(propertyBundle);
+ case PropertyConfig.DATA_TYPE_DOCUMENT:
+ return new DocumentPropertyConfig(propertyBundle);
+ default:
+ throw new IllegalArgumentException(
+ "Unsupported property bundle of type "
+ + propertyBundle.getInt(PropertyConfig.DATA_TYPE_FIELD)
+ + "; contents: "
+ + propertyBundle);
+ }
+ }
+ }
+
+ /** Configuration for a property of type String in a Document. */
+ public static final class StringPropertyConfig extends PropertyConfig {
+ private static final String INDEXING_TYPE_FIELD = "indexingType";
+ private static final String TOKENIZER_TYPE_FIELD = "tokenizerType";
+
/**
* Encapsulates the configurations on how AppSearch should query/index these terms.
*
@@ -249,14 +398,7 @@
@Retention(RetentionPolicy.SOURCE)
public @interface IndexingType {}
- /**
- * Content in this property will not be tokenized or indexed.
- *
- * <p>Useful if the data type is not made up of terms (e.g. {@link
- * PropertyConfig#DATA_TYPE_DOCUMENT} or {@link PropertyConfig#DATA_TYPE_BYTES} type). None
- * of the properties inside the nested property will be indexed regardless of the value of
- * {@code indexingType} for the nested properties.
- */
+ /** Content in this property will not be tokenized or indexed. */
public static final int INDEXING_TYPE_NONE = 0;
/**
@@ -291,54 +433,16 @@
public @interface TokenizerType {}
/**
- * It is only valid for tokenizer_type to be 'NONE' if the data type is {@link
- * PropertyConfig#DATA_TYPE_DOCUMENT}.
+ * It is only valid for tokenizer_type to be 'NONE' if {@link #getIndexingType} is {@link
+ * #INDEXING_TYPE_NONE}.
*/
public static final int TOKENIZER_TYPE_NONE = 0;
/** Tokenization for plain text. */
public static final int TOKENIZER_TYPE_PLAIN = 1;
- final Bundle mBundle;
-
- @Nullable private Integer mHashCode;
-
- PropertyConfig(@NonNull Bundle bundle) {
- mBundle = Preconditions.checkNotNull(bundle);
- }
-
- @Override
- public String toString() {
- return mBundle.toString();
- }
-
- /** Returns the name of this property. */
- @NonNull
- public String getName() {
- return mBundle.getString(NAME_FIELD, "");
- }
-
- /** Returns the type of data the property contains (e.g. string, int, bytes, etc). */
- public @DataType int getDataType() {
- return mBundle.getInt(DATA_TYPE_FIELD, -1);
- }
-
- /**
- * Returns the logical schema-type of the contents of this property.
- *
- * <p>Only set when {@link #getDataType} is set to {@link #DATA_TYPE_DOCUMENT}. Otherwise,
- * it is {@code null}.
- */
- @Nullable
- public String getSchemaType() {
- return mBundle.getString(SCHEMA_TYPE_FIELD);
- }
-
- /**
- * Returns the cardinality of the property (whether it is optional, required or repeated).
- */
- public @Cardinality int getCardinality() {
- return mBundle.getInt(CARDINALITY_FIELD, -1);
+ StringPropertyConfig(@NonNull Bundle bundle) {
+ super(bundle);
}
/** Returns how the property is indexed. */
@@ -351,75 +455,19 @@
return mBundle.getInt(TOKENIZER_TYPE_FIELD);
}
- @Override
- public boolean equals(@Nullable Object other) {
- if (this == other) {
- return true;
- }
- if (!(other instanceof PropertyConfig)) {
- return false;
- }
- PropertyConfig otherProperty = (PropertyConfig) other;
- return BundleUtil.deepEquals(this.mBundle, otherProperty.mBundle);
- }
-
- @Override
- public int hashCode() {
- if (mHashCode == null) {
- mHashCode = BundleUtil.deepHashCode(mBundle);
- }
- return mHashCode;
- }
-
/**
- * Builder for {@link PropertyConfig}.
+ * Builder for {@link StringPropertyConfig}.
*
- * <p>The following properties must be set, or {@link PropertyConfig} construction will
- * fail:
- *
- * <ul>
- * <li>dataType
- * <li>cardinality
- * </ul>
- *
- * <p>In addition, if {@code schemaType} is {@link #DATA_TYPE_DOCUMENT}, {@code schemaType}
- * is also required.
+ * <p>{@link #setCardinality} must be called or {@link #build} will fail.
*/
public static final class Builder {
private final Bundle mBundle = new Bundle();
private boolean mBuilt = false;
- /** Creates a new {@link PropertyConfig.Builder}. */
+ /** Creates a new {@link StringPropertyConfig.Builder}. */
public Builder(@NonNull String propertyName) {
mBundle.putString(NAME_FIELD, propertyName);
- }
-
- /**
- * Type of data the property contains (e.g. string, int, bytes, etc).
- *
- * <p>This property must be set.
- */
- @NonNull
- public PropertyConfig.Builder setDataType(@DataType int dataType) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkArgumentInRange(
- dataType, DATA_TYPE_STRING, DATA_TYPE_DOCUMENT, "dataType");
- mBundle.putInt(DATA_TYPE_FIELD, dataType);
- return this;
- }
-
- /**
- * The logical schema-type of the contents of this property.
- *
- * <p>Only required when {@link #setDataType} is set to {@link #DATA_TYPE_DOCUMENT}.
- * Otherwise, it is ignored.
- */
- @NonNull
- public PropertyConfig.Builder setSchemaType(@NonNull String schemaType) {
- Preconditions.checkState(!mBuilt, "Builder has already been used");
- Preconditions.checkNotNull(schemaType);
- mBundle.putString(SCHEMA_TYPE_FIELD, schemaType);
- return this;
+ mBundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_STRING);
}
/**
@@ -427,8 +475,9 @@
*
* <p>This property must be set.
*/
+ @SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
@NonNull
- public PropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
+ public StringPropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkArgumentInRange(
cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
@@ -440,7 +489,7 @@
* Configures how a property should be indexed so that it can be retrieved by queries.
*/
@NonNull
- public PropertyConfig.Builder setIndexingType(@IndexingType int indexingType) {
+ public StringPropertyConfig.Builder setIndexingType(@IndexingType int indexingType) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkArgumentInRange(
indexingType, INDEXING_TYPE_NONE, INDEXING_TYPE_PREFIXES, "indexingType");
@@ -450,7 +499,7 @@
/** Configures how this property should be tokenized (split into words). */
@NonNull
- public PropertyConfig.Builder setTokenizerType(@TokenizerType int tokenizerType) {
+ public StringPropertyConfig.Builder setTokenizerType(@TokenizerType int tokenizerType) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkArgumentInRange(
tokenizerType, TOKENIZER_TYPE_NONE, TOKENIZER_TYPE_PLAIN, "tokenizerType");
@@ -459,6 +508,337 @@
}
/**
+ * Constructs a new {@link StringPropertyConfig} from the contents of this builder.
+ *
+ * <p>After calling this method, the builder must no longer be used.
+ *
+ * @throws IllegalSchemaException if the property is not correctly populated
+ */
+ @NonNull
+ public StringPropertyConfig build() {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ // TODO(b/147692920): Send the schema to Icing Lib for official validation, instead
+ // of partially reimplementing some of the validation Icing does here.
+ if (!mBundle.containsKey(CARDINALITY_FIELD)) {
+ throw new IllegalSchemaException("Missing field: cardinality");
+ }
+ mBuilt = true;
+ return new StringPropertyConfig(mBundle);
+ }
+ }
+ }
+
+ /** Configuration for a property containing a 64-bit integer. */
+ public static final class Int64PropertyConfig extends PropertyConfig {
+ Int64PropertyConfig(@NonNull Bundle bundle) {
+ super(bundle);
+ }
+
+ /**
+ * Builder for {@link Int64PropertyConfig}.
+ *
+ * <p>{@link #setCardinality} must be called or {@link #build} will fail.
+ */
+ public static final class Builder {
+ private final Bundle mBundle = new Bundle();
+ private boolean mBuilt = false;
+
+ /** Creates a new {@link Int64PropertyConfig.Builder}. */
+ public Builder(@NonNull String propertyName) {
+ mBundle.putString(NAME_FIELD, propertyName);
+ mBundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_INT64);
+ }
+
+ /**
+ * The cardinality of the property (whether it is optional, required or repeated).
+ *
+ * <p>This property must be set.
+ */
+ @SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
+ @NonNull
+ public Int64PropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ Preconditions.checkArgumentInRange(
+ cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
+ mBundle.putInt(CARDINALITY_FIELD, cardinality);
+ return this;
+ }
+
+ /**
+ * Constructs a new {@link Int64PropertyConfig} from the contents of this builder.
+ *
+ * <p>After calling this method, the builder must no longer be used.
+ *
+ * @throws IllegalSchemaException if the property is not correctly populated
+ */
+ @NonNull
+ public Int64PropertyConfig build() {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ if (!mBundle.containsKey(CARDINALITY_FIELD)) {
+ throw new IllegalSchemaException("Missing field: cardinality");
+ }
+ mBuilt = true;
+ return new Int64PropertyConfig(mBundle);
+ }
+ }
+ }
+
+ /** Configuration for a property containing a double-precision decimal number. */
+ public static final class DoublePropertyConfig extends PropertyConfig {
+ DoublePropertyConfig(@NonNull Bundle bundle) {
+ super(bundle);
+ }
+
+ /**
+ * Builder for {@link DoublePropertyConfig}.
+ *
+ * <p>{@link #setCardinality} must be called or {@link #build} will fail.
+ */
+ public static final class Builder {
+ private final Bundle mBundle = new Bundle();
+ private boolean mBuilt = false;
+
+ /** Creates a new {@link DoublePropertyConfig.Builder}. */
+ public Builder(@NonNull String propertyName) {
+ mBundle.putString(NAME_FIELD, propertyName);
+ mBundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_DOUBLE);
+ }
+
+ /**
+ * The cardinality of the property (whether it is optional, required or repeated).
+ *
+ * <p>This property must be set.
+ */
+ @SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
+ @NonNull
+ public DoublePropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ Preconditions.checkArgumentInRange(
+ cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
+ mBundle.putInt(CARDINALITY_FIELD, cardinality);
+ return this;
+ }
+
+ /**
+ * Constructs a new {@link DoublePropertyConfig} from the contents of this builder.
+ *
+ * <p>After calling this method, the builder must no longer be used.
+ *
+ * @throws IllegalSchemaException if the property is not correctly populated
+ */
+ @NonNull
+ public DoublePropertyConfig build() {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ if (!mBundle.containsKey(CARDINALITY_FIELD)) {
+ throw new IllegalSchemaException("Missing field: cardinality");
+ }
+ mBuilt = true;
+ return new DoublePropertyConfig(mBundle);
+ }
+ }
+ }
+
+ /** Configuration for a property containing a boolean. */
+ public static final class BooleanPropertyConfig extends PropertyConfig {
+ BooleanPropertyConfig(@NonNull Bundle bundle) {
+ super(bundle);
+ }
+
+ /**
+ * Builder for {@link BooleanPropertyConfig}.
+ *
+ * <p>{@link #setCardinality} must be called or {@link #build} will fail.
+ */
+ public static final class Builder {
+ private final Bundle mBundle = new Bundle();
+ private boolean mBuilt = false;
+
+ /** Creates a new {@link BooleanPropertyConfig.Builder}. */
+ public Builder(@NonNull String propertyName) {
+ mBundle.putString(NAME_FIELD, propertyName);
+ mBundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_BOOLEAN);
+ }
+
+ /**
+ * The cardinality of the property (whether it is optional, required or repeated).
+ *
+ * <p>This property must be set.
+ */
+ @SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
+ @NonNull
+ public BooleanPropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ Preconditions.checkArgumentInRange(
+ cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
+ mBundle.putInt(CARDINALITY_FIELD, cardinality);
+ return this;
+ }
+
+ /**
+ * Constructs a new {@link BooleanPropertyConfig} from the contents of this builder.
+ *
+ * <p>After calling this method, the builder must no longer be used.
+ *
+ * @throws IllegalSchemaException if the property is not correctly populated
+ */
+ @NonNull
+ public BooleanPropertyConfig build() {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ if (!mBundle.containsKey(CARDINALITY_FIELD)) {
+ throw new IllegalSchemaException("Missing field: cardinality");
+ }
+ mBuilt = true;
+ return new BooleanPropertyConfig(mBundle);
+ }
+ }
+ }
+
+ /** Configuration for a property containing a byte array. */
+ public static final class BytesPropertyConfig extends PropertyConfig {
+ BytesPropertyConfig(@NonNull Bundle bundle) {
+ super(bundle);
+ }
+
+ /**
+ * Builder for {@link BytesPropertyConfig}.
+ *
+ * <p>{@link #setCardinality} must be called or {@link #build} will fail.
+ */
+ public static final class Builder {
+ private final Bundle mBundle = new Bundle();
+ private boolean mBuilt = false;
+
+ /** Creates a new {@link BytesPropertyConfig.Builder}. */
+ public Builder(@NonNull String propertyName) {
+ mBundle.putString(NAME_FIELD, propertyName);
+ mBundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_BYTES);
+ }
+
+ /**
+ * The cardinality of the property (whether it is optional, required or repeated).
+ *
+ * <p>This property must be set.
+ */
+ @SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
+ @NonNull
+ public BytesPropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ Preconditions.checkArgumentInRange(
+ cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
+ mBundle.putInt(CARDINALITY_FIELD, cardinality);
+ return this;
+ }
+
+ /**
+ * Constructs a new {@link BytesPropertyConfig} from the contents of this builder.
+ *
+ * <p>After calling this method, the builder must no longer be used.
+ *
+ * @throws IllegalSchemaException if the property is not correctly populated
+ */
+ @NonNull
+ public BytesPropertyConfig build() {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ if (!mBundle.containsKey(CARDINALITY_FIELD)) {
+ throw new IllegalSchemaException("Missing field: cardinality");
+ }
+ mBuilt = true;
+ return new BytesPropertyConfig(mBundle);
+ }
+ }
+ }
+
+ /** Configuration for a property containing another Document. */
+ public static final class DocumentPropertyConfig extends PropertyConfig {
+ private static final String SCHEMA_TYPE_FIELD = "schemaType";
+ private static final String INDEX_NESTED_PROPERTIES_FIELD = "indexNestedProperties";
+
+ DocumentPropertyConfig(@NonNull Bundle bundle) {
+ super(bundle);
+ }
+
+ /** Returns the logical schema-type of the contents of this document property. */
+ @NonNull
+ public String getSchemaType() {
+ return Preconditions.checkNotNull(mBundle.getString(SCHEMA_TYPE_FIELD));
+ }
+
+ /**
+ * Returns whether fields in the nested document should be indexed according to that
+ * document's schema.
+ *
+ * <p>If false, the nested document's properties are not indexed regardless of its own
+ * schema.
+ */
+ public boolean isIndexNestedProperties() {
+ return mBundle.getBoolean(INDEX_NESTED_PROPERTIES_FIELD);
+ }
+
+ /**
+ * Builder for {@link DocumentPropertyConfig}.
+ *
+ * <p>The following properties must be set, or {@link DocumentPropertyConfig} construction
+ * will fail:
+ *
+ * <ul>
+ * <li>cardinality
+ * <li>schemaType
+ * </ul>
+ */
+ public static final class Builder {
+ private final Bundle mBundle = new Bundle();
+ private boolean mBuilt = false;
+
+ /** Creates a new {@link DocumentPropertyConfig.Builder}. */
+ public Builder(@NonNull String propertyName) {
+ mBundle.putString(NAME_FIELD, propertyName);
+ mBundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_DOCUMENT);
+ }
+
+ /**
+ * The logical schema-type of the contents of this property.
+ *
+ * <p>This property must be set.
+ */
+ @NonNull
+ public DocumentPropertyConfig.Builder setSchemaType(@NonNull String schemaType) {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ Preconditions.checkNotNull(schemaType);
+ mBundle.putString(SCHEMA_TYPE_FIELD, schemaType);
+ return this;
+ }
+
+ /**
+ * The cardinality of the property (whether it is optional, required or repeated).
+ *
+ * <p>This property must be set.
+ */
+ @SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
+ @NonNull
+ public DocumentPropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ Preconditions.checkArgumentInRange(
+ cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
+ mBundle.putInt(CARDINALITY_FIELD, cardinality);
+ return this;
+ }
+
+ /**
+ * Configures whether fields in the nested document should be indexed according to that
+ * document's schema.
+ *
+ * <p>If false, the nested document's properties are not indexed regardless of its own
+ * schema.
+ */
+ @NonNull
+ public DocumentPropertyConfig.Builder setIndexNestedProperties(
+ boolean indexNestedProperties) {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ mBundle.putBoolean(INDEX_NESTED_PROPERTIES_FIELD, indexNestedProperties);
+ return this;
+ }
+
+ /**
* Constructs a new {@link PropertyConfig} from the contents of this builder.
*
* <p>After calling this method, the builder must no longer be used.
@@ -467,25 +847,56 @@
* missing {@code dataType}).
*/
@NonNull
- public PropertyConfig build() {
+ public DocumentPropertyConfig build() {
Preconditions.checkState(!mBuilt, "Builder has already been used");
- // TODO(b/147692920): Send the schema to Icing Lib for official validation, instead
- // of partially reimplementing some of the validation Icing does here.
- if (!mBundle.containsKey(DATA_TYPE_FIELD)) {
- throw new IllegalSchemaException("Missing field: dataType");
- }
- if (mBundle.getString(SCHEMA_TYPE_FIELD, "").isEmpty()
- && mBundle.getInt(DATA_TYPE_FIELD) == DATA_TYPE_DOCUMENT) {
- throw new IllegalSchemaException(
- "Missing field: schemaType (required for configs with "
- + "dataType = DOCUMENT)");
+ if (mBundle.getString(SCHEMA_TYPE_FIELD, "").isEmpty()) {
+ throw new IllegalSchemaException("Missing field: schemaType");
}
if (!mBundle.containsKey(CARDINALITY_FIELD)) {
throw new IllegalSchemaException("Missing field: cardinality");
}
mBuilt = true;
- return new PropertyConfig(mBundle);
+ return new DocumentPropertyConfig(mBundle);
}
}
}
+
+ /**
+ * A migrator class to translate {@link GenericDocument} from different version of {@link
+ * AppSearchSchema}
+ */
+ public interface Migrator {
+
+ /**
+ * Migrates {@link GenericDocument} to a newer version of {@link AppSearchSchema}.
+ *
+ * <p>This methods will be invoked only if the {@link SetSchemaRequest} is setting a higher
+ * version number than the current {@link AppSearchSchema} saved in AppSearch.
+ *
+ * @param currentVersion The current version of the document's schema.
+ * @param targetVersion The final version that documents need to be migrated to.
+ * @param helper The helper class could help to query all documents need to be migrated.
+ */
+ // This method will be overridden by users, allow them to throw any customer Exceptions.
+ @SuppressLint("GenericException")
+ default void onUpgrade(
+ int currentVersion, int targetVersion, @NonNull AppSearchMigrationHelper helper)
+ throws Exception {}
+
+ /**
+ * Migrates {@link GenericDocument} to an older version of {@link AppSearchSchema}.
+ *
+ * <p>The methods will be invoked only if the {@link SetSchemaRequest} is setting a higher
+ * version number than the current {@link AppSearchSchema} saved in AppSearch.
+ *
+ * @param currentVersion The current version of the document's schema.
+ * @param targetVersion The final version that documents need to be migrated to.
+ * @param helper The helper class could help to query all documents need to be migrated.
+ */
+ // This method will be overridden by users, allow them to throw any customer Exceptions.
+ @SuppressLint("GenericException")
+ default void onDowngrade(
+ int currentVersion, int targetVersion, @NonNull AppSearchMigrationHelper helper)
+ throws Exception {}
+ }
}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java b/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
index 11e7fab..2f02808 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
@@ -80,9 +80,9 @@
/**
* The maximum number of indexed properties a document can have.
*
- * <p>Indexed properties are properties where the {@link
- * AppSearchSchema.PropertyConfig#getIndexingType()} constant is anything other than {@link
- * AppSearchSchema.PropertyConfig.IndexingType#INDEXING_TYPE_NONE}.
+ * <p>Indexed properties are properties which are strings where the {@link
+ * AppSearchSchema.StringPropertyConfig#getIndexingType} value is anything other than {@link
+ * AppSearchSchema.StringPropertyConfig.IndexingType#INDEXING_TYPE_NONE}.
*/
public static int getMaxIndexedProperties() {
return MAX_INDEXED_PROPERTIES;
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/GetByUriRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/GetByUriRequest.java
index 74afdd2..38e0046 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/GetByUriRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/GetByUriRequest.java
@@ -17,13 +17,17 @@
package android.app.appsearch;
import android.annotation.NonNull;
+import android.util.ArrayMap;
import android.util.ArraySet;
import com.android.internal.util.Preconditions;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.List;
+import java.util.Map;
import java.util.Set;
/**
@@ -32,12 +36,24 @@
* @see AppSearchSession#getByUri
*/
public final class GetByUriRequest {
+ /**
+ * Schema type to be used in {@link android.app.appsearch.GetByUriRequest.Builder#addProjection}
+ * to apply property paths to all results, excepting any types that have had their own, specific
+ * property paths set.
+ */
+ public static final String PROJECTION_SCHEMA_TYPE_WILDCARD = "*";
+
private final String mNamespace;
private final Set<String> mUris;
+ private final Map<String, List<String>> mTypePropertyPathsMap;
- GetByUriRequest(@NonNull String namespace, @NonNull Set<String> uris) {
- mNamespace = namespace;
- mUris = uris;
+ GetByUriRequest(
+ @NonNull String namespace,
+ @NonNull Set<String> uris,
+ @NonNull Map<String, List<String>> typePropertyPathsMap) {
+ mNamespace = Preconditions.checkNotNull(namespace);
+ mUris = Preconditions.checkNotNull(uris);
+ mTypePropertyPathsMap = Preconditions.checkNotNull(typePropertyPathsMap);
}
/** Returns the namespace to get documents from. */
@@ -52,10 +68,43 @@
return Collections.unmodifiableSet(mUris);
}
+ /**
+ * Returns a map from schema type to property paths to be used for projection.
+ *
+ * <p>If the map is empty, then all properties will be retrieved for all results.
+ *
+ * <p>Calling this function repeatedly is inefficient. Prefer to retain the Map returned by this
+ * function, rather than calling it multiple times.
+ */
+ @NonNull
+ public Map<String, List<String>> getProjections() {
+ Map<String, List<String>> copy = new ArrayMap<>();
+ for (String key : mTypePropertyPathsMap.keySet()) {
+ copy.put(key, new ArrayList<>(mTypePropertyPathsMap.get(key)));
+ }
+ return copy;
+ }
+
+ /**
+ * Returns a map from schema type to property paths to be used for projection.
+ *
+ * <p>If the map is empty, then all properties will be retrieved for all results.
+ *
+ * <p>A more efficient version of {@link #getProjections}, but it returns a modifiable map. This
+ * is not meant to be unhidden and should only be used by internal classes.
+ *
+ * @hide
+ */
+ @NonNull
+ public Map<String, List<String>> getProjectionsVisibleToPackagesInternal() {
+ return mTypePropertyPathsMap;
+ }
+
/** Builder for {@link GetByUriRequest} objects. */
public static final class Builder {
private String mNamespace = GenericDocument.DEFAULT_NAMESPACE;
private final Set<String> mUris = new ArraySet<>();
+ private final Map<String, List<String>> mProjectionTypePropertyPaths = new ArrayMap<>();
private boolean mBuilt = false;
/**
@@ -87,12 +136,63 @@
return this;
}
+ /**
+ * Adds property paths for the specified type to be used for projection. If property paths
+ * are added for a type, then only the properties referred to will be retrieved for results
+ * of that type. If a property path that is specified isn't present in a result, it will be
+ * ignored for that result. Property paths cannot be null.
+ *
+ * <p>If no property paths are added for a particular type, then all properties of results
+ * of that type will be retrieved.
+ *
+ * <p>If property path is added for the {@link
+ * GetByUriRequest#PROJECTION_SCHEMA_TYPE_WILDCARD}, then those property paths will apply to
+ * all results, excepting any types that have their own, specific property paths set.
+ *
+ * <p>{@see SearchSpec.Builder#addProjection(String, String...)}
+ */
+ @NonNull
+ public Builder addProjection(@NonNull String schemaType, @NonNull String... propertyPaths) {
+ Preconditions.checkNotNull(propertyPaths);
+ return addProjection(schemaType, Arrays.asList(propertyPaths));
+ }
+
+ /**
+ * Adds property paths for the specified type to be used for projection. If property paths
+ * are added for a type, then only the properties referred to will be retrieved for results
+ * of that type. If a property path that is specified isn't present in a result, it will be
+ * ignored for that result. Property paths cannot be null.
+ *
+ * <p>If no property paths are added for a particular type, then all properties of results
+ * of that type will be retrieved.
+ *
+ * <p>If property path is added for the {@link
+ * GetByUriRequest#PROJECTION_SCHEMA_TYPE_WILDCARD}, then those property paths will apply to
+ * all results, excepting any types that have their own, specific property paths set.
+ *
+ * <p>{@see SearchSpec.Builder#addProjection(String, String...)}
+ */
+ @NonNull
+ public Builder addProjection(
+ @NonNull String schemaType, @NonNull Collection<String> propertyPaths) {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ Preconditions.checkNotNull(schemaType);
+ Preconditions.checkNotNull(propertyPaths);
+ List<String> propertyPathsList = new ArrayList<>(propertyPaths.size());
+ for (String propertyPath : propertyPaths) {
+ Preconditions.checkNotNull(propertyPath);
+ propertyPathsList.add(propertyPath);
+ }
+ mProjectionTypePropertyPaths.put(schemaType, propertyPathsList);
+ return this;
+ }
+
/** Builds a new {@link GetByUriRequest}. */
@NonNull
public GetByUriRequest build() {
Preconditions.checkState(!mBuilt, "Builder has already been used");
mBuilt = true;
- return new GetByUriRequest(mNamespace, mUris);
+ return new GetByUriRequest(mNamespace, mUris, mProjectionTypePropertyPaths);
}
}
}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/ReportUsageRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/ReportUsageRequest.java
new file mode 100644
index 0000000..2bfcf28
--- /dev/null
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/ReportUsageRequest.java
@@ -0,0 +1,135 @@
+/*
+ * 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 android.app.appsearch;
+
+import android.annotation.NonNull;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * A request to report usage of a document.
+ *
+ * <p>See {@link AppSearchSession#reportUsage} for a detailed description of usage reporting.
+ *
+ * @see AppSearchSession#reportUsage
+ */
+public final class ReportUsageRequest {
+ private final String mNamespace;
+ private final String mUri;
+ private final long mUsageTimeMillis;
+
+ ReportUsageRequest(@NonNull String namespace, @NonNull String uri, long usageTimeMillis) {
+ mNamespace = Preconditions.checkNotNull(namespace);
+ mUri = Preconditions.checkNotNull(uri);
+ mUsageTimeMillis = usageTimeMillis;
+ }
+
+ /** Returns the namespace of the document that was used. */
+ @NonNull
+ public String getNamespace() {
+ return mNamespace;
+ }
+
+ /** Returns the URI of document that was used. */
+ @NonNull
+ public String getUri() {
+ return mUri;
+ }
+
+ /**
+ * Returns the timestamp in milliseconds of the usage report (the time at which the document was
+ * used).
+ *
+ * <p>The value is in the {@link System#currentTimeMillis} time base.
+ */
+ public long getUsageTimeMillis() {
+ return mUsageTimeMillis;
+ }
+
+ /** Builder for {@link ReportUsageRequest} objects. */
+ public static final class Builder {
+ private String mNamespace = GenericDocument.DEFAULT_NAMESPACE;
+ private String mUri;
+ private Long mUsageTimeMillis;
+ private boolean mBuilt = false;
+
+ /**
+ * Sets which namespace the document being used belongs to.
+ *
+ * <p>If this is not set, it defaults to {@link GenericDocument#DEFAULT_NAMESPACE}.
+ *
+ * @throws IllegalStateException if the builder has already been used
+ */
+ @NonNull
+ public ReportUsageRequest.Builder setNamespace(@NonNull String namespace) {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ Preconditions.checkNotNull(namespace);
+ mNamespace = namespace;
+ return this;
+ }
+
+ /**
+ * Sets the URI of the document being used.
+ *
+ * <p>This field is required.
+ *
+ * @throws IllegalStateException if the builder has already been used
+ */
+ @NonNull
+ public ReportUsageRequest.Builder setUri(@NonNull String uri) {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ Preconditions.checkNotNull(uri);
+ mUri = uri;
+ return this;
+ }
+
+ /**
+ * Sets the timestamp in milliseconds of the usage report (the time at which the document
+ * was used).
+ *
+ * <p>The value is in the {@link System#currentTimeMillis} time base.
+ *
+ * <p>If unset, this defaults to the current timestamp at the time that the {@link
+ * ReportUsageRequest} is constructed.
+ *
+ * @throws IllegalStateException if the builder has already been used
+ */
+ @NonNull
+ public ReportUsageRequest.Builder setUsageTimeMillis(long usageTimeMillis) {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ mUsageTimeMillis = usageTimeMillis;
+ return this;
+ }
+
+ /**
+ * Builds a new {@link ReportUsageRequest}.
+ *
+ * @throws NullPointerException if {@link #setUri} has never been called
+ * @throws IllegalStateException if the builder has already been used
+ */
+ @NonNull
+ public ReportUsageRequest build() {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ Preconditions.checkNotNull(mUri, "ReportUsageRequest is missing a URI");
+ if (mUsageTimeMillis == null) {
+ mUsageTimeMillis = System.currentTimeMillis();
+ }
+ mBuilt = true;
+ return new ReportUsageRequest(mNamespace, mUri, mUsageTimeMillis);
+ }
+ }
+}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java b/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java
index 62324b2..d792f45 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java
@@ -125,7 +125,6 @@
* Contains the database name that stored the {@link GenericDocument}.
*
* @return Database name that stored the document
- * @hide
*/
@NonNull
public String getDatabaseName() {
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java b/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java
index b5d5f04d..963062c 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java
@@ -106,7 +106,9 @@
RANKING_STRATEGY_NONE,
RANKING_STRATEGY_DOCUMENT_SCORE,
RANKING_STRATEGY_CREATION_TIMESTAMP,
- RANKING_STRATEGY_RELEVANCE_SCORE
+ RANKING_STRATEGY_RELEVANCE_SCORE,
+ RANKING_STRATEGY_USAGE_COUNT,
+ RANKING_STRATEGY_USAGE_LAST_USED_TIMESTAMP
})
@Retention(RetentionPolicy.SOURCE)
public @interface RankingStrategy {}
@@ -119,6 +121,10 @@
public static final int RANKING_STRATEGY_CREATION_TIMESTAMP = 2;
/** Ranked by document relevance score. */
public static final int RANKING_STRATEGY_RELEVANCE_SCORE = 3;
+ /** Ranked by number of usages. */
+ public static final int RANKING_STRATEGY_USAGE_COUNT = 4;
+ /** Ranked by timestamp of last usage. */
+ public static final int RANKING_STRATEGY_USAGE_LAST_USED_TIMESTAMP = 5;
/**
* Order for query result.
@@ -411,7 +417,7 @@
Preconditions.checkArgumentInRange(
rankingStrategy,
RANKING_STRATEGY_NONE,
- RANKING_STRATEGY_RELEVANCE_SCORE,
+ RANKING_STRATEGY_USAGE_LAST_USED_TIMESTAMP,
"Result ranking strategy");
mBundle.putInt(RANKING_STRATEGY_FIELD, rankingStrategy);
return this;
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
index e9c4cb4..1486df3 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
@@ -38,16 +38,19 @@
private final Set<AppSearchSchema> mSchemas;
private final Set<String> mSchemasNotVisibleToSystemUi;
private final Map<String, Set<PackageIdentifier>> mSchemasVisibleToPackages;
+ private final Map<String, AppSearchSchema.Migrator> mMigrators;
private final boolean mForceOverride;
SetSchemaRequest(
@NonNull Set<AppSearchSchema> schemas,
@NonNull Set<String> schemasNotVisibleToSystemUi,
@NonNull Map<String, Set<PackageIdentifier>> schemasVisibleToPackages,
+ @NonNull Map<String, AppSearchSchema.Migrator> migrators,
boolean forceOverride) {
mSchemas = Preconditions.checkNotNull(schemas);
mSchemasNotVisibleToSystemUi = Preconditions.checkNotNull(schemasNotVisibleToSystemUi);
mSchemasVisibleToPackages = Preconditions.checkNotNull(schemasVisibleToPackages);
+ mMigrators = Preconditions.checkNotNull(migrators);
mForceOverride = forceOverride;
}
@@ -81,6 +84,12 @@
return copy;
}
+ /** Returns the map of {@link android.app.appsearch.AppSearchSchema.Migrator}. */
+ @NonNull
+ public Map<String, AppSearchSchema.Migrator> getMigrators() {
+ return Collections.unmodifiableMap(mMigrators);
+ }
+
/**
* Returns a mapping of schema types to the set of packages that have access to that schema
* type. Each package is represented by a {@link PackageIdentifier}. name and byte[]
@@ -107,6 +116,7 @@
private final Set<String> mSchemasNotVisibleToSystemUi = new ArraySet<>();
private final Map<String, Set<PackageIdentifier>> mSchemasVisibleToPackages =
new ArrayMap<>();
+ private final Map<String, AppSearchSchema.Migrator> mMigrators = new ArrayMap<>();
private boolean mForceOverride = false;
private boolean mBuilt = false;
@@ -197,6 +207,23 @@
}
/**
+ * Sets the {@link android.app.appsearch.AppSearchSchema.Migrator}.
+ *
+ * @param schemaType The schema type to set migrator on.
+ * @param migrator The migrator translate a document from it's old version to a new
+ * incompatible version.
+ */
+ @NonNull
+ @SuppressLint("MissingGetterMatchingBuilder") // Getter return plural objects.
+ public Builder setMigrator(
+ @NonNull String schemaType, @NonNull AppSearchSchema.Migrator migrator) {
+ Preconditions.checkNotNull(schemaType);
+ Preconditions.checkNotNull(migrator);
+ mMigrators.put(schemaType, migrator);
+ return this;
+ }
+
+ /**
* Configures the {@link SetSchemaRequest} to delete any existing documents that don't
* follow the new schema.
*
@@ -241,6 +268,7 @@
mSchemas,
mSchemasNotVisibleToSystemUi,
mSchemasVisibleToPackages,
+ mMigrators,
mForceOverride);
}
}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java
new file mode 100644
index 0000000..90a6f60
--- /dev/null
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java
@@ -0,0 +1,258 @@
+/*
+ * 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 android.app.appsearch;
+
+import static android.app.appsearch.AppSearchResult.RESULT_OK;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.ArraySet;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+/** The response class of {@link AppSearchSession#setSchema} */
+public class SetSchemaResponse {
+ private final List<MigrationFailure> mMigrationFailures;
+ private final Set<String> mDeletedTypes;
+ private final Set<String> mMigratedTypes;
+ private final Set<String> mIncompatibleTypes;
+ private final @AppSearchResult.ResultCode int mResultCode;
+
+ SetSchemaResponse(
+ @NonNull List<MigrationFailure> migrationFailures,
+ @NonNull Set<String> deletedTypes,
+ @NonNull Set<String> migratedTypes,
+ @NonNull Set<String> incompatibleTypes,
+ @AppSearchResult.ResultCode int resultCode) {
+ mMigrationFailures = Preconditions.checkNotNull(migrationFailures);
+ mDeletedTypes = Preconditions.checkNotNull(deletedTypes);
+ mMigratedTypes = Preconditions.checkNotNull(migratedTypes);
+ mIncompatibleTypes = Preconditions.checkNotNull(incompatibleTypes);
+ mResultCode = resultCode;
+ }
+
+ /**
+ * Returns a {@link List} of all failed {@link MigrationFailure}.
+ *
+ * <p>A {@link MigrationFailure} will be generated if the system trying to save a post-migrated
+ * {@link GenericDocument} but fail.
+ *
+ * <p>{@link MigrationFailure} contains the uri, namespace and schemaType of the post-migrated
+ * {@link GenericDocument} and the error reason. Mostly it will be mismatch the schema it
+ * migrated to.
+ */
+ @NonNull
+ public List<MigrationFailure> getMigrationFailures() {
+ return Collections.unmodifiableList(mMigrationFailures);
+ }
+
+ /**
+ * Returns a {@link Set} of schema type that were deleted by the {@link
+ * AppSearchSession#setSchema} call.
+ */
+ @NonNull
+ public Set<String> getDeletedTypes() {
+ return Collections.unmodifiableSet(mDeletedTypes);
+ }
+
+ /**
+ * Returns a {@link Set} of schema type that were migrated by the {@link
+ * AppSearchSession#setSchema} call.
+ */
+ @NonNull
+ public Set<String> getMigratedTypes() {
+ return Collections.unmodifiableSet(mMigratedTypes);
+ }
+
+ /**
+ * Returns a {@link Set} of schema type whose new definitions set in the {@link
+ * AppSearchSession#setSchema} call were incompatible with the pre-existing schema.
+ *
+ * <p>If a {@link android.app.appsearch.AppSearchSchema.Migrator} is provided for this type and
+ * the migration is success triggered. The type will also appear in {@link #getMigratedTypes()}.
+ *
+ * @see AppSearchSession#setSchema
+ * @see SetSchemaRequest.Builder#setForceOverride
+ */
+ @NonNull
+ public Set<String> getIncompatibleTypes() {
+ return Collections.unmodifiableSet(mIncompatibleTypes);
+ }
+
+ /** Returns {@code true} if all {@link AppSearchSchema}s are successful set to the system. */
+ public boolean isSuccess() {
+ return mResultCode == RESULT_OK;
+ }
+
+ @Override
+ @NonNull
+ public String toString() {
+ return "{\n Does setSchema success? : "
+ + isSuccess()
+ + "\n failures: "
+ + mMigrationFailures
+ + "\n}";
+ }
+
+ /**
+ * Builder for {@link SetSchemaResponse} objects.
+ *
+ * @hide
+ */
+ public static class Builder {
+ private final List<MigrationFailure> mMigrationFailures = new ArrayList<>();
+ private final Set<String> mDeletedTypes = new ArraySet<>();
+ private final Set<String> mMigratedTypes = new ArraySet<>();
+ private final Set<String> mIncompatibleTypes = new ArraySet<>();
+ private @AppSearchResult.ResultCode int mResultCode = RESULT_OK;
+ private boolean mBuilt = false;
+
+ /** Adds a {@link MigrationFailure}. */
+ @NonNull
+ public Builder setFailure(
+ @NonNull String schemaType,
+ @NonNull String namespace,
+ @NonNull String uri,
+ @NonNull AppSearchResult<Void> failureResult) {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ Preconditions.checkNotNull(schemaType);
+ Preconditions.checkNotNull(namespace);
+ Preconditions.checkNotNull(uri);
+ Preconditions.checkNotNull(failureResult);
+ Preconditions.checkState(!failureResult.isSuccess());
+ mMigrationFailures.add(new MigrationFailure(schemaType, namespace, uri, failureResult));
+ return this;
+ }
+
+ /** Adds a {@link MigrationFailure}. */
+ @NonNull
+ public Builder setFailure(
+ @NonNull String schemaType,
+ @NonNull String namespace,
+ @NonNull String uri,
+ @AppSearchResult.ResultCode int resultCode,
+ @Nullable String errorMessage) {
+ mMigrationFailures.add(
+ new MigrationFailure(
+ schemaType,
+ namespace,
+ uri,
+ AppSearchResult.newFailedResult(resultCode, errorMessage)));
+ return this;
+ }
+
+ /** Adds deletedTypes to the list of deleted schema types. */
+ @NonNull
+ public Builder addDeletedType(@NonNull Collection<String> deletedTypes) {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ mDeletedTypes.addAll(Preconditions.checkNotNull(deletedTypes));
+ return this;
+ }
+
+ /** Adds incompatibleTypes to the list of incompatible schema types. */
+ @NonNull
+ public Builder addIncompatibleType(@NonNull Collection<String> incompatibleTypes) {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ mIncompatibleTypes.addAll(Preconditions.checkNotNull(incompatibleTypes));
+ return this;
+ }
+
+ /** Adds migratedTypes to the list of migrated schema types. */
+ @NonNull
+ public Builder addMigratedType(@NonNull String migratedType) {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ mMigratedTypes.add(Preconditions.checkNotNull(migratedType));
+ return this;
+ }
+
+ /** Sets the {@link AppSearchResult.ResultCode} of the response. */
+ @NonNull
+ public Builder setResultCode(@AppSearchResult.ResultCode int resultCode) {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ mResultCode = resultCode;
+ return this;
+ }
+
+ /** Builds a {@link SetSchemaResponse} object. */
+ @NonNull
+ public SetSchemaResponse build() {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ mBuilt = true;
+ return new SetSchemaResponse(
+ mMigrationFailures,
+ mDeletedTypes,
+ mMigratedTypes,
+ mIncompatibleTypes,
+ mResultCode);
+ }
+ }
+
+ /**
+ * The class represents a post-migrated {@link GenericDocument} that failed to be saved by
+ * {@link AppSearchSession#setSchema}.
+ */
+ public static class MigrationFailure {
+ private final String mSchemaType;
+ private final String mNamespace;
+ private final String mUri;
+ AppSearchResult<Void> mFailureResult;
+
+ MigrationFailure(
+ @NonNull String schemaType,
+ @NonNull String namespace,
+ @NonNull String uri,
+ @NonNull AppSearchResult<Void> result) {
+ mSchemaType = schemaType;
+ mNamespace = namespace;
+ mUri = uri;
+ mFailureResult = result;
+ }
+
+ /** Returns the schema type of the {@link GenericDocument} that fails to be migrated. */
+ @NonNull
+ public String getSchemaType() {
+ return mSchemaType;
+ }
+
+ /** Returns the namespace of the {@link GenericDocument} that fails to be migrated. */
+ @NonNull
+ public String getNamespace() {
+ return mNamespace;
+ }
+
+ /** Returns the uri of the {@link GenericDocument} that fails to be migrated. */
+ @NonNull
+ public String getUri() {
+ return mUri;
+ }
+
+ /**
+ * Returns the {@link AppSearchResult} that indicates why the post-migrated {@link
+ * GenericDocument} fails to be saved.
+ */
+ @NonNull
+ public AppSearchResult<Void> getAppSearchResult() {
+ return mFailureResult;
+ }
+ }
+}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResult.java b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResult.java
new file mode 100644
index 0000000..f04ace6
--- /dev/null
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResult.java
@@ -0,0 +1,125 @@
+/*
+ * 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 android.app.appsearch;
+
+import android.annotation.NonNull;
+import android.os.Bundle;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * This class represents the results of setSchema().
+ *
+ * @hide
+ */
+public class SetSchemaResult {
+
+ public static final String DELETED_SCHEMA_TYPES_FIELD = "deletedSchemaTypes";
+ public static final String INCOMPATIBLE_SCHEMA_TYPES_FIELD = "incompatibleSchemaTypes";
+ public static final String RESULT_CODE_FIELD = "resultCode";
+ private final List<String> mDeletedSchemaTypes;
+ private final List<String> mIncompatibleSchemaTypes;
+ private final Bundle mBundle;
+
+ SetSchemaResult(@NonNull Bundle bundle) {
+ mBundle = Preconditions.checkNotNull(bundle);
+ mDeletedSchemaTypes =
+ Preconditions.checkNotNull(mBundle.getStringArrayList(DELETED_SCHEMA_TYPES_FIELD));
+ mIncompatibleSchemaTypes =
+ Preconditions.checkNotNull(
+ mBundle.getStringArrayList(INCOMPATIBLE_SCHEMA_TYPES_FIELD));
+ }
+
+ /** Returns the {@link Bundle} of this class. */
+ @NonNull
+ public Bundle getBundle() {
+ return mBundle;
+ }
+
+ /** returns all deleted schema types in this setSchema call. */
+ @NonNull
+ public List<String> getDeletedSchemaTypes() {
+ return Collections.unmodifiableList(mDeletedSchemaTypes);
+ }
+
+ /** returns all incompatible schema types in this setSchema call. */
+ @NonNull
+ public List<String> getIncompatibleSchemaTypes() {
+ return Collections.unmodifiableList(mIncompatibleSchemaTypes);
+ }
+
+ /**
+ * returns the {@link android.app.appsearch.AppSearchResult.ResultCode} of the {@link
+ * AppSearchSession#setSchema} call.
+ */
+ public int getResultCode() {
+ return mBundle.getInt(RESULT_CODE_FIELD);
+ }
+
+ /** Builder for {@link SetSchemaResult} objects. */
+ public static final class Builder {
+ private final ArrayList<String> mDeletedSchemaTypes = new ArrayList<>();
+ private final ArrayList<String> mIncompatibleSchemaTypes = new ArrayList<>();
+ @AppSearchResult.ResultCode private int mResultCode;
+ private boolean mBuilt = false;
+
+ /** Adds a deletedSchemaTypes to the {@link SetSchemaResult}. */
+ @NonNull
+ public Builder addDeletedSchemaType(@NonNull String deletedSchemaType) {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ mDeletedSchemaTypes.add(Preconditions.checkNotNull(deletedSchemaType));
+ return this;
+ }
+
+ /** Adds a incompatible SchemaTypes to the {@link SetSchemaResult}. */
+ @NonNull
+ public Builder addIncompatibleSchemaType(@NonNull String incompatibleSchemaTypes) {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ mIncompatibleSchemaTypes.add(Preconditions.checkNotNull(incompatibleSchemaTypes));
+ return this;
+ }
+
+ /**
+ * Sets the {@link android.app.appsearch.AppSearchResult.ResultCode} of the {@link
+ * AppSearchSession#setSchema} call to the {@link SetSchemaResult}
+ */
+ @NonNull
+ public Builder setResultCode(@AppSearchResult.ResultCode int resultCode) {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ mResultCode = resultCode;
+ return this;
+ }
+
+ /** Builds a {@link SetSchemaResult}. */
+ @NonNull
+ public SetSchemaResult build() {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ Bundle bundle = new Bundle();
+ bundle.putStringArrayList(
+ SetSchemaResult.DELETED_SCHEMA_TYPES_FIELD, mDeletedSchemaTypes);
+ bundle.putStringArrayList(
+ SetSchemaResult.INCOMPATIBLE_SCHEMA_TYPES_FIELD, mIncompatibleSchemaTypes);
+ bundle.putInt(RESULT_CODE_FIELD, mResultCode);
+ mBuilt = true;
+ return new SetSchemaResult(bundle);
+ }
+ }
+}
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 1f1e9a1..ed55f00 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -31,26 +31,30 @@
import android.app.appsearch.SearchResultPage;
import android.app.appsearch.SearchSpec;
import android.content.Context;
+import android.content.pm.PackageManagerInternal;
import android.os.Binder;
import android.os.Bundle;
import android.os.ParcelableException;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Log;
import com.android.internal.util.Preconditions;
+import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.appsearch.external.localstorage.AppSearchImpl;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
-/**
- * TODO(b/142567528): add comments when implement this class
- */
+/** TODO(b/142567528): add comments when implement this class */
public class AppSearchManagerService extends SystemService {
private static final String TAG = "AppSearchManagerService";
+ private PackageManagerInternal mPackageManagerInternal;
+ private ImplInstanceManager mImplInstanceManager;
public AppSearchManagerService(Context context) {
super(context);
@@ -59,11 +63,14 @@
@Override
public void onStart() {
publishBinderService(Context.APP_SEARCH_SERVICE, new Stub());
+ mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
+ mImplInstanceManager = new ImplInstanceManager(getContext());
}
private class Stub extends IAppSearchManager.Stub {
@Override
public void setSchema(
+ @NonNull String packageName,
@NonNull String databaseName,
@NonNull List<Bundle> schemaBundles,
@NonNull List<String> schemasNotPlatformSurfaceable,
@@ -71,6 +78,7 @@
boolean forceOverride,
@UserIdInt int userId,
@NonNull IAppSearchResultCallback callback) {
+ Preconditions.checkNotNull(packageName);
Preconditions.checkNotNull(databaseName);
Preconditions.checkNotNull(schemaBundles);
Preconditions.checkNotNull(callback);
@@ -78,6 +86,7 @@
int callingUserId = handleIncomingUser(userId, callingUid);
final long callingIdentity = Binder.clearCallingIdentity();
try {
+ verifyCallingPackage(callingUid, packageName);
List<AppSearchSchema> schemas = new ArrayList<>(schemaBundles.size());
for (int i = 0; i < schemaBundles.size(); i++) {
schemas.add(new AppSearchSchema(schemaBundles.get(i)));
@@ -93,8 +102,7 @@
}
schemasPackageAccessible.put(entry.getKey(), packageIdentifiers);
}
- AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
- String packageName = convertUidToPackageName(callingUid);
+ AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
impl.setSchema(
packageName,
databaseName,
@@ -102,8 +110,8 @@
schemasNotPlatformSurfaceable,
schemasPackageAccessible,
forceOverride);
- invokeCallbackOnResult(callback,
- AppSearchResult.newSuccessfulResult(/*result=*/ null));
+ invokeCallbackOnResult(
+ callback, AppSearchResult.newSuccessfulResult(/*result=*/ null));
} catch (Throwable t) {
invokeCallbackOnError(callback, t);
} finally {
@@ -113,24 +121,26 @@
@Override
public void getSchema(
+ @NonNull String packageName,
@NonNull String databaseName,
@UserIdInt int userId,
@NonNull IAppSearchResultCallback callback) {
+ Preconditions.checkNotNull(packageName);
Preconditions.checkNotNull(databaseName);
Preconditions.checkNotNull(callback);
int callingUid = Binder.getCallingUidOrThrow();
int callingUserId = handleIncomingUser(userId, callingUid);
final long callingIdentity = Binder.clearCallingIdentity();
try {
- AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
- String packageName = convertUidToPackageName(callingUid);
+ verifyCallingPackage(callingUid, packageName);
+ AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
List<AppSearchSchema> schemas = impl.getSchema(packageName, databaseName);
List<Bundle> schemaBundles = new ArrayList<>(schemas.size());
for (int i = 0; i < schemas.size(); i++) {
schemaBundles.add(schemas.get(i).getBundle());
}
- invokeCallbackOnResult(callback,
- AppSearchResult.newSuccessfulResult(schemaBundles));
+ invokeCallbackOnResult(
+ callback, AppSearchResult.newSuccessfulResult(schemaBundles));
} catch (Throwable t) {
invokeCallbackOnError(callback, t);
} finally {
@@ -140,10 +150,12 @@
@Override
public void putDocuments(
+ @NonNull String packageName,
@NonNull String databaseName,
@NonNull List<Bundle> documentBundles,
@UserIdInt int userId,
@NonNull IAppSearchBatchResultCallback callback) {
+ Preconditions.checkNotNull(packageName);
Preconditions.checkNotNull(databaseName);
Preconditions.checkNotNull(documentBundles);
Preconditions.checkNotNull(callback);
@@ -151,10 +163,10 @@
int callingUserId = handleIncomingUser(userId, callingUid);
final long callingIdentity = Binder.clearCallingIdentity();
try {
+ verifyCallingPackage(callingUid, packageName);
AppSearchBatchResult.Builder<String, Void> resultBuilder =
new AppSearchBatchResult.Builder<>();
- AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
- String packageName = convertUidToPackageName(callingUid);
+ AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
for (int i = 0; i < documentBundles.size(); i++) {
GenericDocument document = new GenericDocument(documentBundles.get(i));
try {
@@ -176,11 +188,14 @@
@Override
public void getDocuments(
+ @NonNull String packageName,
@NonNull String databaseName,
@NonNull String namespace,
@NonNull List<String> uris,
+ @NonNull Map<String, List<String>> typePropertyPaths,
@UserIdInt int userId,
@NonNull IAppSearchBatchResultCallback callback) {
+ Preconditions.checkNotNull(packageName);
Preconditions.checkNotNull(databaseName);
Preconditions.checkNotNull(namespace);
Preconditions.checkNotNull(uris);
@@ -189,15 +204,15 @@
int callingUserId = handleIncomingUser(userId, callingUid);
final long callingIdentity = Binder.clearCallingIdentity();
try {
+ verifyCallingPackage(callingUid, packageName);
AppSearchBatchResult.Builder<String, Bundle> resultBuilder =
new AppSearchBatchResult.Builder<>();
- AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
- String packageName = convertUidToPackageName(callingUid);
+ AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
for (int i = 0; i < uris.size(); i++) {
String uri = uris.get(i);
try {
GenericDocument document = impl.getDocument(packageName, databaseName,
- namespace, uri);
+ namespace, uri, typePropertyPaths);
resultBuilder.setSuccess(uri, document.getBundle());
} catch (Throwable t) {
resultBuilder.setResult(uri, throwableToFailedResult(t));
@@ -214,11 +229,13 @@
// TODO(sidchhabra): Do this in a threadpool.
@Override
public void query(
+ @NonNull String packageName,
@NonNull String databaseName,
@NonNull String queryExpression,
@NonNull Bundle searchSpecBundle,
@UserIdInt int userId,
@NonNull IAppSearchResultCallback callback) {
+ Preconditions.checkNotNull(packageName);
Preconditions.checkNotNull(databaseName);
Preconditions.checkNotNull(queryExpression);
Preconditions.checkNotNull(searchSpecBundle);
@@ -227,14 +244,16 @@
int callingUserId = handleIncomingUser(userId, callingUid);
final long callingIdentity = Binder.clearCallingIdentity();
try {
- AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
- String packageName = convertUidToPackageName(callingUid);
- SearchResultPage searchResultPage = impl.query(
- packageName,
- databaseName,
- queryExpression,
- new SearchSpec(searchSpecBundle));
- invokeCallbackOnResult(callback,
+ verifyCallingPackage(callingUid, packageName);
+ AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
+ SearchResultPage searchResultPage =
+ impl.query(
+ packageName,
+ databaseName,
+ queryExpression,
+ new SearchSpec(searchSpecBundle));
+ invokeCallbackOnResult(
+ callback,
AppSearchResult.newSuccessfulResult(searchResultPage.getBundle()));
} catch (Throwable t) {
invokeCallbackOnError(callback, t);
@@ -245,10 +264,12 @@
@Override
public void globalQuery(
+ @NonNull String packageName,
@NonNull String queryExpression,
@NonNull Bundle searchSpecBundle,
@UserIdInt int userId,
@NonNull IAppSearchResultCallback callback) {
+ Preconditions.checkNotNull(packageName);
Preconditions.checkNotNull(queryExpression);
Preconditions.checkNotNull(searchSpecBundle);
Preconditions.checkNotNull(callback);
@@ -256,11 +277,15 @@
int callingUserId = handleIncomingUser(userId, callingUid);
final long callingIdentity = Binder.clearCallingIdentity();
try {
- AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
+ verifyCallingPackage(callingUid, packageName);
+ AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
SearchResultPage searchResultPage = impl.globalQuery(
queryExpression,
- new SearchSpec(searchSpecBundle));
- invokeCallbackOnResult(callback,
+ new SearchSpec(searchSpecBundle),
+ packageName,
+ callingUid);
+ invokeCallbackOnResult(
+ callback,
AppSearchResult.newSuccessfulResult(searchResultPage.getBundle()));
} catch (Throwable t) {
invokeCallbackOnError(callback, t);
@@ -270,7 +295,9 @@
}
@Override
- public void getNextPage(long nextPageToken, @UserIdInt int userId,
+ public void getNextPage(
+ long nextPageToken,
+ @UserIdInt int userId,
@NonNull IAppSearchResultCallback callback) {
Preconditions.checkNotNull(callback);
int callingUid = Binder.getCallingUid();
@@ -279,9 +306,10 @@
// TODO(b/162450968) check nextPageToken is being advanced by the same uid as originally
// opened it
try {
- AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
+ AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
SearchResultPage searchResultPage = impl.getNextPage(nextPageToken);
- invokeCallbackOnResult(callback,
+ invokeCallbackOnResult(
+ callback,
AppSearchResult.newSuccessfulResult(searchResultPage.getBundle()));
} catch (Throwable t) {
invokeCallbackOnError(callback, t);
@@ -296,7 +324,7 @@
int callingUserId = handleIncomingUser(userId, callingUid);
final long callingIdentity = Binder.clearCallingIdentity();
try {
- AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
+ AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
impl.invalidateNextPageToken(nextPageToken);
} catch (Throwable t) {
Log.e(TAG, "Unable to invalidate the query page token", t);
@@ -306,12 +334,47 @@
}
@Override
+ public void reportUsage(
+ @NonNull String packageName,
+ @NonNull String databaseName,
+ @NonNull String namespace,
+ @NonNull String uri,
+ long usageTimeMillis,
+ @UserIdInt int userId,
+ @NonNull IAppSearchResultCallback callback) {
+ Objects.requireNonNull(databaseName);
+ Objects.requireNonNull(namespace);
+ Objects.requireNonNull(uri);
+ Objects.requireNonNull(callback);
+ int callingUid = Binder.getCallingUid();
+ int callingUserId = handleIncomingUser(userId, callingUid);
+ final long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
+ impl.reportUsage(
+ packageName,
+ databaseName,
+ namespace,
+ uri,
+ usageTimeMillis);
+ invokeCallbackOnResult(callback,
+ AppSearchResult.newSuccessfulResult(/*result=*/ null));
+ } catch (Throwable t) {
+ invokeCallbackOnError(callback, t);
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentity);
+ }
+ }
+
+ @Override
public void removeByUri(
+ @NonNull String packageName,
@NonNull String databaseName,
@NonNull String namespace,
@NonNull List<String> uris,
@UserIdInt int userId,
@NonNull IAppSearchBatchResultCallback callback) {
+ Preconditions.checkNotNull(packageName);
Preconditions.checkNotNull(databaseName);
Preconditions.checkNotNull(uris);
Preconditions.checkNotNull(callback);
@@ -319,15 +382,15 @@
int callingUserId = handleIncomingUser(userId, callingUid);
final long callingIdentity = Binder.clearCallingIdentity();
try {
+ verifyCallingPackage(callingUid, packageName);
AppSearchBatchResult.Builder<String, Void> resultBuilder =
new AppSearchBatchResult.Builder<>();
- AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
- String packageName = convertUidToPackageName(callingUid);
+ AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
for (int i = 0; i < uris.size(); i++) {
String uri = uris.get(i);
try {
impl.remove(packageName, databaseName, namespace, uri);
- resultBuilder.setSuccess(uri, /*result= */null);
+ resultBuilder.setSuccess(uri, /*result= */ null);
} catch (Throwable t) {
resultBuilder.setResult(uri, throwableToFailedResult(t));
}
@@ -342,11 +405,13 @@
@Override
public void removeByQuery(
+ @NonNull String packageName,
@NonNull String databaseName,
@NonNull String queryExpression,
@NonNull Bundle searchSpecBundle,
@UserIdInt int userId,
@NonNull IAppSearchResultCallback callback) {
+ Preconditions.checkNotNull(packageName);
Preconditions.checkNotNull(databaseName);
Preconditions.checkNotNull(queryExpression);
Preconditions.checkNotNull(searchSpecBundle);
@@ -355,9 +420,12 @@
int callingUserId = handleIncomingUser(userId, callingUid);
final long callingIdentity = Binder.clearCallingIdentity();
try {
- AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
- String packageName = convertUidToPackageName(callingUid);
- impl.removeByQuery(packageName, databaseName, queryExpression,
+ verifyCallingPackage(callingUid, packageName);
+ AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
+ impl.removeByQuery(
+ packageName,
+ databaseName,
+ queryExpression,
new SearchSpec(searchSpecBundle));
invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
} catch (Throwable t) {
@@ -373,7 +441,7 @@
int callingUserId = handleIncomingUser(userId, callingUid);
final long callingIdentity = Binder.clearCallingIdentity();
try {
- AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
+ AppSearchImpl impl = mImplInstanceManager.getInstance(callingUserId);
impl.persistToDisk();
} catch (Throwable t) {
Log.e(TAG, "Unable to persist the data to disk", t);
@@ -389,7 +457,7 @@
int callingUserId = handleIncomingUser(userId, callingUid);
final long callingIdentity = Binder.clearCallingIdentity();
try {
- ImplInstanceManager.getInstance(getContext(), callingUserId);
+ mImplInstanceManager.getInstance(callingUserId);
invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
} catch (Throwable t) {
invokeCallbackOnError(callback, t);
@@ -398,28 +466,22 @@
}
}
- /**
- * Returns a package name for the given uid.
- *
- * <p>The current implementation returns the package name of the app with this uid in a
- * format like {@code com.example.package} or {@code com.example.sharedname:5678}.
- */
- @NonNull
- private String convertUidToPackageName(int callingUid) {
- // For regular apps, this call will return the package name. If callingUid is an
- // android:sharedUserId, this value may be another type of name and have a :uid suffix.
- String callingUidName = getContext().getPackageManager().getNameForUid(callingUid);
- if (callingUidName == null) {
- // Not sure how this is possible --- maybe app was uninstalled?
- throw new IllegalStateException(
- "Failed to look up package name for uid " + callingUid);
+ private void verifyCallingPackage(int callingUid, @NonNull String callingPackage) {
+ Preconditions.checkNotNull(callingPackage);
+ if (mPackageManagerInternal.getPackageUid(
+ callingPackage, /*flags=*/ 0, UserHandle.getUserId(callingUid))
+ != callingUid) {
+ throw new SecurityException(
+ "Specified calling package ["
+ + callingPackage
+ + "] does not match the calling uid "
+ + callingUid);
}
- return callingUidName;
}
/** Invokes the {@link IAppSearchResultCallback} with the result. */
- private void invokeCallbackOnResult(IAppSearchResultCallback callback,
- AppSearchResult<?> result) {
+ private void invokeCallbackOnResult(
+ IAppSearchResultCallback callback, AppSearchResult<?> result) {
try {
callback.onResult(result);
} catch (RemoteException e) {
@@ -428,8 +490,8 @@
}
/** Invokes the {@link IAppSearchBatchResultCallback} with the result. */
- private void invokeCallbackOnResult(IAppSearchBatchResultCallback callback,
- AppSearchBatchResult<?, ?> result) {
+ private void invokeCallbackOnResult(
+ IAppSearchBatchResultCallback callback, AppSearchBatchResult<?, ?> result) {
try {
callback.onResult(result);
} catch (RemoteException e) {
@@ -455,8 +517,8 @@
*
* <p>The throwable is converted to {@link ParcelableException}.
*/
- private void invokeCallbackOnError(IAppSearchBatchResultCallback callback,
- Throwable throwable) {
+ private void invokeCallbackOnError(
+ IAppSearchBatchResultCallback callback, Throwable throwable) {
try {
callback.onSystemError(new ParcelableException(throwable));
} catch (RemoteException e) {
@@ -465,13 +527,18 @@
}
}
- //TODO(b/173553485) verifying that the caller has permission to access target user's data
- //TODO(b/173553485) Handle ACTION_USER_REMOVED broadcast
- //TODO(b/173553485) Implement SystemService.onUserStopping()
+ // TODO(b/173553485) verifying that the caller has permission to access target user's data
+ // TODO(b/173553485) Handle ACTION_USER_REMOVED broadcast
+ // TODO(b/173553485) Implement SystemService.onUserStopping()
private static int handleIncomingUser(@UserIdInt int userId, int callingUid) {
int callingPid = Binder.getCallingPid();
- return ActivityManager.handleIncomingUser(callingPid, callingUid, userId,
- /*allowAll=*/ false, /*requireFull=*/ false,
- /*name=*/ null, /*callerPackage=*/ null);
+ return ActivityManager.handleIncomingUser(
+ callingPid,
+ callingUid,
+ userId,
+ /*allowAll=*/ false,
+ /*requireFull=*/ false,
+ /*name=*/ null,
+ /*callerPackage=*/ null);
}
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
index 2871eb6..fe3c2e1 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
@@ -16,14 +16,19 @@
package com.android.server.appsearch;
+import static android.content.pm.PackageManager.MATCH_FACTORY_ONLY;
+
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.appsearch.exceptions.AppSearchException;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.os.Environment;
+import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.util.SparseArray;
+import com.android.internal.R;
import com.android.server.appsearch.external.localstorage.AppSearchImpl;
import java.io.File;
@@ -38,7 +43,13 @@
private static final SparseArray<AppSearchImpl> sInstances = new SparseArray<>();
- private ImplInstanceManager() {}
+ private final Context mContext;
+ private final String mGlobalQuerierPackage;
+
+ public ImplInstanceManager(@NonNull Context context) {
+ mContext = context;
+ mGlobalQuerierPackage = getGlobalAppSearchDataQuerierPackageName(mContext);
+ }
/**
* Gets an instance of AppSearchImpl for the given user.
@@ -46,19 +57,18 @@
* <p>If no AppSearchImpl instance exists for this user, Icing will be initialized and one will
* be created.
*
- * @param context The Android context
* @param userId The multi-user userId of the device user calling AppSearch
* @return An initialized {@link AppSearchImpl} for this user
*/
@NonNull
- public static AppSearchImpl getInstance(@NonNull Context context, @UserIdInt int userId)
+ public AppSearchImpl getInstance(@UserIdInt int userId)
throws AppSearchException {
AppSearchImpl instance = sInstances.get(userId);
if (instance == null) {
synchronized (ImplInstanceManager.class) {
instance = sInstances.get(userId);
if (instance == null) {
- instance = createImpl(context, userId);
+ instance = createImpl(userId);
sInstances.put(userId, instance);
}
}
@@ -66,16 +76,41 @@
return instance;
}
- private static AppSearchImpl createImpl(@NonNull Context context, @UserIdInt int userId)
+ private AppSearchImpl createImpl(@UserIdInt int userId)
throws AppSearchException {
- File appSearchDir = getAppSearchDir(context, userId);
- return AppSearchImpl.create(appSearchDir);
+ File appSearchDir = getAppSearchDir(mContext, userId);
+ return AppSearchImpl.create(
+ appSearchDir, mContext, userId, mGlobalQuerierPackage);
}
private static File getAppSearchDir(@NonNull Context context, @UserIdInt int userId) {
// See com.android.internal.app.ChooserActivity::getPinnedSharedPrefs
- File userCeDir = Environment.getDataUserCePackageDirectory(
- StorageManager.UUID_PRIVATE_INTERNAL, userId, context.getPackageName());
+ File userCeDir =
+ Environment.getDataUserCePackageDirectory(
+ StorageManager.UUID_PRIVATE_INTERNAL, userId, context.getPackageName());
return new File(userCeDir, APP_SEARCH_DIR);
}
+
+ /**
+ * Returns the global querier package if it's a system package. Otherwise, empty string.
+ *
+ * @param context Context of the system service.
+ */
+ private static String getGlobalAppSearchDataQuerierPackageName(Context context) {
+ String globalAppSearchDataQuerierPackage =
+ context.getString(R.string.config_globalAppSearchDataQuerierPackage);
+ try {
+ if (context.getPackageManager()
+ .getPackageInfoAsUser(
+ globalAppSearchDataQuerierPackage,
+ MATCH_FACTORY_ONLY,
+ UserHandle.USER_SYSTEM)
+ == null) {
+ return "";
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ return "";
+ }
+ return globalAppSearchDataQuerierPackage;
+ }
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/VisibilityStore.java b/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java
similarity index 69%
rename from apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/VisibilityStore.java
rename to apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java
index a940ec1..64dc972 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/VisibilityStore.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/VisibilityStore.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,18 +14,26 @@
* limitations under the License.
*/
+// TODO(b/169883602): This is purposely a different package from the path so that it can access
+// AppSearchImpl's methods without having to make them public. This should be moved into a proper
+// package once AppSearchImpl-VisibilityStore's dependencies are refactored.
package com.android.server.appsearch.external.localstorage;
import android.annotation.NonNull;
+import android.annotation.UserIdInt;
import android.app.appsearch.AppSearchResult;
import android.app.appsearch.AppSearchSchema;
import android.app.appsearch.GenericDocument;
import android.app.appsearch.PackageIdentifier;
import android.app.appsearch.exceptions.AppSearchException;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Process;
+import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Log;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import java.util.ArrayList;
@@ -52,10 +60,18 @@
*
* <p>NOTE: This class holds an instance of AppSearchImpl and AppSearchImpl holds an instance of
* this class. Take care to not cause any circular dependencies.
+ *
+ * @hide
*/
-class VisibilityStore {
+public class VisibilityStore {
+
+ private static final String TAG = "AppSearchVisibilityStore";
+
+ /** No-op user id that won't have any visibility settings. */
+ public static final int NO_OP_USER_ID = -1;
+
/** Schema type for documents that hold AppSearch's metadata, e.g. visibility settings */
- @VisibleForTesting static final String VISIBILITY_TYPE = "VisibilityType";
+ private static final String VISIBILITY_TYPE = "VisibilityType";
/**
* Property that holds the list of platform-hidden schemas, as part of the visibility settings.
@@ -81,15 +97,14 @@
private static final AppSearchSchema VISIBILITY_SCHEMA =
new AppSearchSchema.Builder(VISIBILITY_TYPE)
.addProperty(
- new AppSearchSchema.PropertyConfig.Builder(
+ new AppSearchSchema.StringPropertyConfig.Builder(
NOT_PLATFORM_SURFACEABLE_PROPERTY)
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
.setCardinality(
AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
.build())
.addProperty(
- new AppSearchSchema.PropertyConfig.Builder(PACKAGE_ACCESSIBLE_PROPERTY)
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOCUMENT)
+ new AppSearchSchema.DocumentPropertyConfig.Builder(
+ PACKAGE_ACCESSIBLE_PROPERTY)
.setSchemaType(PACKAGE_ACCESSIBLE_TYPE)
.setCardinality(
AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
@@ -103,28 +118,26 @@
private static final AppSearchSchema PACKAGE_ACCESSIBLE_SCHEMA =
new AppSearchSchema.Builder(PACKAGE_ACCESSIBLE_TYPE)
.addProperty(
- new AppSearchSchema.PropertyConfig.Builder(PACKAGE_NAME_PROPERTY)
+ new AppSearchSchema.StringPropertyConfig.Builder(PACKAGE_NAME_PROPERTY)
.setCardinality(
AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
.build())
.addProperty(
- new AppSearchSchema.PropertyConfig.Builder(SHA_256_CERT_PROPERTY)
+ new AppSearchSchema.BytesPropertyConfig.Builder(SHA_256_CERT_PROPERTY)
.setCardinality(
AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
.build())
.addProperty(
- new AppSearchSchema.PropertyConfig.Builder(ACCESSIBLE_SCHEMA_PROPERTY)
+ new AppSearchSchema.StringPropertyConfig.Builder(
+ ACCESSIBLE_SCHEMA_PROPERTY)
.setCardinality(
AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
.build())
.build();
/**
- * These cannot have any of the special characters used by AppSearchImpl (e.g. {@link
- * AppSearchImpl#PACKAGE_DELIMITER} or {@link AppSearchImpl#DATABASE_DELIMITER}.
+ * These cannot have any of the special characters used by AppSearchImpl (e.g. {@code
+ * AppSearchImpl#PACKAGE_DELIMITER} or {@code AppSearchImpl#DATABASE_DELIMITER}.
*/
static final String PACKAGE_NAME = "VS#Pkg";
@@ -148,6 +161,16 @@
private final AppSearchImpl mAppSearchImpl;
+ // Context of the system service.
+ private final Context mContext;
+
+ // User ID of the caller who we're checking visibility settings for.
+ private final int mUserId;
+
+ // UID of the package that has platform-query privileges, i.e. can query for all
+ // platform-surfaceable content.
+ private int mGlobalQuerierUid;
+
/**
* Maps prefixes to the set of schemas that are platform-hidden within that prefix. All schemas
* in the map are prefixed.
@@ -173,8 +196,15 @@
*
* @param appSearchImpl AppSearchImpl instance
*/
- VisibilityStore(@NonNull AppSearchImpl appSearchImpl) {
+ public VisibilityStore(
+ @NonNull AppSearchImpl appSearchImpl,
+ @NonNull Context context,
+ @UserIdInt int userId,
+ @NonNull String globalQuerierPackage) {
mAppSearchImpl = appSearchImpl;
+ mContext = context;
+ mUserId = userId;
+ mGlobalQuerierUid = getGlobalQuerierUid(globalQuerierPackage);
}
/**
@@ -216,7 +246,8 @@
PACKAGE_NAME,
DATABASE_NAME,
NAMESPACE,
- /*uri=*/ addUriPrefix(prefix));
+ /*uri=*/ addUriPrefix(prefix),
+ /*typePropertyPaths=*/ Collections.emptyMap());
// Update platform visibility settings
String[] schemas =
@@ -302,8 +333,7 @@
schemasPackageAccessible.entrySet()) {
for (int i = 0; i < entry.getValue().size(); i++) {
// TODO(b/169883602): remove the "placeholder" uri once upstream changes to relax
- // nested
- // document uri rules gets synced down.
+ // nested document uri rules gets synced down.
GenericDocument packageAccessibleDocument =
new GenericDocument.Builder(/*uri=*/ "placeholder", PACKAGE_ACCESSIBLE_TYPE)
.setNamespace(NAMESPACE)
@@ -332,42 +362,93 @@
mPackageAccessibleMap.put(prefix, schemaToPackageIdentifierMap);
}
- /** Returns if the schema is surfaceable by the platform. */
- // TODO(b/169883602): check permissions against the allowlisted global querier package name.
- public boolean isSchemaPlatformSurfaceable(
- @NonNull String prefix, @NonNull String prefixedSchema) {
+ /** Checks whether {@code prefixedSchema} can be searched over by the {@code callerUid}. */
+ public boolean isSchemaSearchableByCaller(
+ @NonNull String prefix, @NonNull String prefixedSchema, int callerUid) {
Preconditions.checkNotNull(prefix);
Preconditions.checkNotNull(prefixedSchema);
- Set<String> notPlatformSurfaceableSchemas = mNotPlatformSurfaceableMap.get(prefix);
- if (notPlatformSurfaceableSchemas == null) {
+
+ // We compare appIds here rather than direct uids because the package's uid may change based
+ // on the user that's running.
+ if (UserHandle.isSameApp(mGlobalQuerierUid, callerUid)
+ && isSchemaPlatformSurfaceable(prefix, prefixedSchema)) {
return true;
}
+
+ // May not be platform surfaceable, but might still be accessible through 3p access.
+ return isSchemaPackageAccessible(prefix, prefixedSchema, callerUid);
+ }
+
+ /**
+ * Returns whether the caller has platform query privileges, and if so, that the schema is
+ * surfaceable on the platform.
+ */
+ private boolean isSchemaPlatformSurfaceable(
+ @NonNull String prefix, @NonNull String prefixedSchema) {
+ if (prefix.equals(VISIBILITY_STORE_PREFIX)) {
+ // VisibilityStore schemas are for internal bookkeeping.
+ return false;
+ }
+
+ Set<String> notPlatformSurfaceableSchemas = mNotPlatformSurfaceableMap.get(prefix);
+ if (notPlatformSurfaceableSchemas == null) {
+ // No schemas were opted out of being platform-surfaced. So by default, it can be
+ // surfaced.
+ return true;
+ }
+
+ // Some schemas were opted out of being platform-surfaced. As long as this schema
+ // isn't one of those opt-outs, it's surfaceable.
return !notPlatformSurfaceableSchemas.contains(prefixedSchema);
}
- /** Returns whether the schema is accessible by {@code accessingPackage}. */
- // TODO(b/169883602): check certificate and package against the incoming querier's uid/package.
- public boolean isSchemaPackageAccessible(
- @NonNull String prefix,
- @NonNull String prefixedSchema,
- @NonNull PackageIdentifier accessingPackage) {
- Preconditions.checkNotNull(prefix);
- Preconditions.checkNotNull(prefixedSchema);
- Preconditions.checkNotNull(accessingPackage);
-
+ /**
+ * Returns whether the schema is accessible by the {@code callerUid}. Checks that the callerUid
+ * has one of the allowed PackageIdentifier's package. And if so, that the package also has the
+ * matching certificate.
+ *
+ * <p>This supports packages that have certificate rotation. As long as the specified
+ * 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(
+ @NonNull String prefix, @NonNull String prefixedSchema, int callerUid) {
Map<String, Set<PackageIdentifier>> schemaToPackageIdentifierMap =
mPackageAccessibleMap.get(prefix);
if (schemaToPackageIdentifierMap == null) {
+ // No schemas under this prefix have granted package access, return early.
return false;
}
Set<PackageIdentifier> packageIdentifiers =
schemaToPackageIdentifierMap.get(prefixedSchema);
if (packageIdentifiers == null) {
+ // No package identifiers were granted access for this schema, return early.
return false;
}
- return packageIdentifiers.contains(accessingPackage);
+ for (PackageIdentifier packageIdentifier : packageIdentifiers) {
+ // Check that the caller uid matches this allowlisted PackageIdentifier.
+ // TODO(b/169883602): Consider caching the UIDs of packages. Looking this up in the
+ // package manager could be costly. We would also need to update the cache on
+ // package-removals.
+ if (getPackageUidAsUser(packageIdentifier.getPackageName()) != callerUid) {
+ continue;
+ }
+
+ // Check that the package also has the matching certificate
+ if (mContext.getPackageManager()
+ .hasSigningCertificate(
+ packageIdentifier.getPackageName(),
+ packageIdentifier.getSha256Certificate(),
+ PackageManager.CERT_INPUT_SHA256)) {
+ // The caller has the right package name and right certificate!
+ return true;
+ }
+ }
+
+ // If we can't verify the schema is package accessible, default to no access.
+ return false;
}
/**
@@ -375,7 +456,7 @@
*
* <p>{@link #initialize()} must be called after this.
*/
- void handleReset() {
+ public void handleReset() {
mNotPlatformSurfaceableMap.clear();
mPackageAccessibleMap.clear();
}
@@ -389,4 +470,42 @@
private static String addUriPrefix(String uri) {
return URI_PREFIX + uri;
}
+
+ /**
+ * Finds the uid of the {@code globalQuerierPackage}. {@code globalQuerierPackage} must be a
+ * pre-installed, system app. Returns {@link Process#INVALID_UID} if unable to find the UID.
+ */
+ private int getGlobalQuerierUid(@NonNull String globalQuerierPackage) {
+ try {
+ int flags =
+ PackageManager.MATCH_DISABLED_COMPONENTS
+ | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
+ | PackageManager.MATCH_SYSTEM_ONLY;
+ // It doesn't matter that we're using the caller's userId here. We'll eventually check
+ // that the two uids in question belong to the same appId.
+ return mContext.getPackageManager()
+ .getPackageUidAsUser(globalQuerierPackage, flags, mUserId);
+ } catch (PackageManager.NameNotFoundException e) {
+ // Global querier doesn't exist.
+ Log.i(
+ TAG,
+ "AppSearch global querier package not found on device: '"
+ + globalQuerierPackage
+ + "'");
+ }
+ return Process.INVALID_UID;
+ }
+
+ /**
+ * Finds the UID of the {@code packageName}. Returns {@link Process#INVALID_UID} if unable to
+ * find the UID.
+ */
+ private int getPackageUidAsUser(@NonNull String packageName) {
+ try {
+ return mContext.getPackageManager().getPackageUidAsUser(packageName, mUserId);
+ } catch (PackageManager.NameNotFoundException e) {
+ // Package doesn't exist, continue
+ }
+ return Process.INVALID_UID;
+ }
}
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 674f199..592b8b9 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
@@ -21,10 +21,13 @@
import android.app.appsearch.AppSearchResult;
import android.app.appsearch.AppSearchSchema;
import android.app.appsearch.GenericDocument;
+import android.app.appsearch.GetByUriRequest;
import android.app.appsearch.PackageIdentifier;
import android.app.appsearch.SearchResultPage;
import android.app.appsearch.SearchSpec;
+import android.app.appsearch.SetSchemaResult;
import android.app.appsearch.exceptions.AppSearchException;
+import android.content.Context;
import android.os.Bundle;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -34,9 +37,12 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import com.android.server.appsearch.external.localstorage.converter.GenericDocumentToProtoConverter;
+import com.android.server.appsearch.external.localstorage.converter.ResultCodeToProtoConverter;
import com.android.server.appsearch.external.localstorage.converter.SchemaToProtoConverter;
import com.android.server.appsearch.external.localstorage.converter.SearchResultToProtoConverter;
import com.android.server.appsearch.external.localstorage.converter.SearchSpecToProtoConverter;
+import com.android.server.appsearch.external.localstorage.converter.SetSchemaResultToProtoConverter;
+import com.android.server.appsearch.external.localstorage.converter.TypePropertyPathToProtoConverter;
import com.google.android.icing.IcingSearchEngine;
import com.google.android.icing.proto.DeleteByQueryResultProto;
@@ -54,6 +60,7 @@
import com.google.android.icing.proto.PropertyConfigProto;
import com.google.android.icing.proto.PropertyProto;
import com.google.android.icing.proto.PutResultProto;
+import com.google.android.icing.proto.ReportUsageResultProto;
import com.google.android.icing.proto.ResetResultProto;
import com.google.android.icing.proto.ResultSpecProto;
import com.google.android.icing.proto.SchemaProto;
@@ -64,6 +71,7 @@
import com.google.android.icing.proto.SetSchemaResultProto;
import com.google.android.icing.proto.StatusProto;
import com.google.android.icing.proto.TypePropertyMask;
+import com.google.android.icing.proto.UsageReport;
import java.io.File;
import java.util.ArrayList;
@@ -154,14 +162,27 @@
* folder.
*/
@NonNull
- public static AppSearchImpl create(@NonNull File icingDir) throws AppSearchException {
+ public static AppSearchImpl create(
+ @NonNull File icingDir,
+ @NonNull Context context,
+ int userId,
+ @NonNull String globalQuerierPackage)
+ throws AppSearchException {
Preconditions.checkNotNull(icingDir);
- AppSearchImpl appSearchImpl = new AppSearchImpl(icingDir);
+ Preconditions.checkNotNull(context);
+ Preconditions.checkNotNull(globalQuerierPackage);
+ AppSearchImpl appSearchImpl =
+ new AppSearchImpl(icingDir, context, userId, globalQuerierPackage);
appSearchImpl.initializeVisibilityStore();
return appSearchImpl;
}
- private AppSearchImpl(@NonNull File icingDir) throws AppSearchException {
+ private AppSearchImpl(
+ @NonNull File icingDir,
+ @NonNull Context context,
+ int userId,
+ @NonNull String globalQuerierPackage)
+ throws AppSearchException {
mReadWriteLock.writeLock().lock();
try {
@@ -173,7 +194,9 @@
.build();
mIcingSearchEngineLocked = new IcingSearchEngine(options);
- mVisibilityStoreLocked = new VisibilityStore(this);
+ mVisibilityStoreLocked =
+ new VisibilityStore(
+ this, context, userId, globalQuerierPackage);
InitializeResultProto initializeResultProto = mIcingSearchEngineLocked.initialize();
SchemaProto schemaProto;
@@ -239,7 +262,8 @@
* which do not comply with the new schema will be deleted.
* @throws AppSearchException on IcingSearchEngine error.
*/
- public void setSchema(
+ @NonNull
+ public SetSchemaResult setSchema(
@NonNull String packageName,
@NonNull String databaseName,
@NonNull List<AppSearchSchema> schemas,
@@ -253,8 +277,9 @@
SchemaProto.Builder newSchemaBuilder = SchemaProto.newBuilder();
for (int i = 0; i < schemas.size(); i++) {
+ AppSearchSchema schema = schemas.get(i);
SchemaTypeConfigProto schemaTypeProto =
- SchemaToProtoConverter.toSchemaTypeConfigProto(schemas.get(i));
+ SchemaToProtoConverter.toSchemaTypeConfigProto(schema);
newSchemaBuilder.addTypes(schemaTypeProto);
}
@@ -273,16 +298,10 @@
try {
checkSuccess(setSchemaResultProto.getStatus());
} catch (AppSearchException e) {
- // Improve the error message by merging in information about incompatible types.
if (setSchemaResultProto.getDeletedSchemaTypesCount() > 0
|| setSchemaResultProto.getIncompatibleSchemaTypesCount() > 0) {
- String newMessage =
- e.getMessage()
- + "\n Deleted types: "
- + setSchemaResultProto.getDeletedSchemaTypesList()
- + "\n Incompatible types: "
- + setSchemaResultProto.getIncompatibleSchemaTypesList();
- throw new AppSearchException(e.getResultCode(), newMessage, e.getCause());
+ return SetSchemaResultToProtoConverter.toSetSchemaResult(
+ setSchemaResultProto, prefix);
} else {
throw e;
}
@@ -319,6 +338,7 @@
// incompatible schemas.
checkForOptimizeLocked(/* force= */ true);
}
+ return SetSchemaResultToProtoConverter.toSetSchemaResult(setSchemaResultProto, prefix);
} finally {
mReadWriteLock.writeLock().unlock();
}
@@ -419,6 +439,8 @@
* @param databaseName The databaseName this document resides in.
* @param namespace The namespace this document resides in.
* @param uri The URI of the document to get.
+ * @param typePropertyPaths A map of schema type to a list of property paths to return in the
+ * result.
* @return The Document contents
* @throws AppSearchException on IcingSearchEngine error.
*/
@@ -427,16 +449,35 @@
@NonNull String packageName,
@NonNull String databaseName,
@NonNull String namespace,
- @NonNull String uri)
+ @NonNull String uri,
+ @NonNull Map<String, List<String>> typePropertyPaths)
throws AppSearchException {
GetResultProto getResultProto;
+ List<TypePropertyMask> nonPrefixedPropertyMasks =
+ TypePropertyPathToProtoConverter.toTypePropertyMaskList(typePropertyPaths);
+ List<TypePropertyMask> prefixedPropertyMasks =
+ new ArrayList<>(nonPrefixedPropertyMasks.size());
+ for (int i = 0; i < nonPrefixedPropertyMasks.size(); ++i) {
+ TypePropertyMask typePropertyMask = nonPrefixedPropertyMasks.get(i);
+ String nonPrefixedType = typePropertyMask.getSchemaType();
+ String prefixedType =
+ nonPrefixedType.equals(GetByUriRequest.PROJECTION_SCHEMA_TYPE_WILDCARD)
+ ? nonPrefixedType
+ : createPrefix(packageName, databaseName) + nonPrefixedType;
+ prefixedPropertyMasks.add(
+ typePropertyMask.toBuilder().setSchemaType(prefixedType).build());
+ }
+ GetResultSpecProto getResultSpec =
+ GetResultSpecProto.newBuilder()
+ .addAllTypePropertyMasks(prefixedPropertyMasks)
+ .build();
mReadWriteLock.readLock().lock();
try {
getResultProto =
mIcingSearchEngineLocked.get(
createPrefix(packageName, databaseName) + namespace,
uri,
- GetResultSpecProto.getDefaultInstance());
+ getResultSpec);
} finally {
mReadWriteLock.readLock().unlock();
}
@@ -476,8 +517,12 @@
mReadWriteLock.readLock().lock();
try {
+ String prefix = createPrefix(packageName, databaseName);
+ Set<String> allowedPrefixedSchemas = getAllowedPrefixSchemas(prefix, searchSpec);
+
return doQueryLocked(
Collections.singleton(createPrefix(packageName, databaseName)),
+ allowedPrefixedSchemas,
queryExpression,
searchSpec);
} finally {
@@ -493,40 +538,72 @@
*
* @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 callerUid}.
+ * @param callerUid UID of the client making the globalQuery call.
* @return The results of performing this search. It may contain an empty list of results if no
* documents matched the query.
* @throws AppSearchException on IcingSearchEngine error.
*/
@NonNull
public SearchResultPage globalQuery(
- @NonNull String queryExpression, @NonNull SearchSpec searchSpec)
+ @NonNull String queryExpression,
+ @NonNull SearchSpec searchSpec,
+ @NonNull String callerPackageName,
+ int callerUid)
throws AppSearchException {
- // TODO(b/169883602): Check if the platform is querying us at a higher level. At this
- // point, we should add all platform-surfaceable schemas assuming the querier has been
- // verified.
mReadWriteLock.readLock().lock();
try {
- Set<String> prefixes = new ArraySet<>();
Set<String> packageFilters = new ArraySet<>(searchSpec.getPackageNames());
-
- for (String prefix : mNamespaceMapLocked.keySet()) {
- if (prefix.equals(VisibilityStore.VISIBILITY_STORE_PREFIX)) {
- // Filter out any VisibilityStore documents which are AppSearch-internal only.
- continue;
+ Set<String> prefixFilters = new ArraySet<>();
+ Set<String> allPrefixes = mNamespaceMapLocked.keySet();
+ if (packageFilters.isEmpty()) {
+ // Client didn't restrict their search over packages. Try to query over all
+ // packages/prefixes
+ prefixFilters = allPrefixes;
+ } else {
+ // Client did restrict their search over packages. Only include the prefixes that
+ // belong to the specified packages.
+ for (String prefix : allPrefixes) {
+ String packageName = getPackageName(prefix);
+ if (packageFilters.contains(packageName)) {
+ prefixFilters.add(prefix);
+ }
}
-
- if (!packageFilters.isEmpty() && !packageFilters.contains(getPackageName(prefix))) {
- // Client wanted to restrict search over specified packages. Since the
- // specified packages don't include this prefix, don't add it to our search
- // filters.
- continue;
- }
-
- // Otherwise, include this prefix in our global search.
- prefixes.add(prefix);
}
- return doQueryLocked(prefixes, queryExpression, searchSpec);
+ // Find which schemas the client is allowed to query over.
+ Set<String> allowedPrefixedSchemas = new ArraySet<>();
+ List<String> schemaFilters = searchSpec.getSchemaTypes();
+ for (String prefix : prefixFilters) {
+ String packageName = getPackageName(prefix);
+
+ if (!schemaFilters.isEmpty()) {
+ for (String schema : schemaFilters) {
+ // Client specified some schemas to search over, check each one
+ String prefixedSchema = prefix + schema;
+ if (packageName.equals(callerPackageName)
+ || mVisibilityStoreLocked.isSchemaSearchableByCaller(
+ prefix, prefixedSchema, callerUid)) {
+ allowedPrefixedSchemas.add(prefixedSchema);
+ }
+ }
+ } else {
+ // Client didn't specify certain schemas to search over, check all schemas
+ Set<String> prefixedSchemas = mSchemaMapLocked.get(prefix);
+ if (prefixedSchemas != null) {
+ for (String prefixedSchema : prefixedSchemas) {
+ if (packageName.equals(callerPackageName)
+ || mVisibilityStoreLocked.isSchemaSearchableByCaller(
+ prefix, prefixedSchema, callerUid)) {
+ allowedPrefixedSchemas.add(prefixedSchema);
+ }
+ }
+ }
+ }
+ }
+
+ return doQueryLocked(
+ prefixFilters, allowedPrefixedSchemas, queryExpression, searchSpec);
} finally {
mReadWriteLock.readLock().unlock();
}
@@ -535,28 +612,25 @@
@GuardedBy("mReadWriteLock")
private SearchResultPage doQueryLocked(
@NonNull Set<String> prefixes,
+ @NonNull Set<String> allowedPrefixedSchemas,
@NonNull String queryExpression,
@NonNull SearchSpec searchSpec)
throws AppSearchException {
SearchSpecProto.Builder searchSpecBuilder =
SearchSpecToProtoConverter.toSearchSpecProto(searchSpec).toBuilder()
.setQuery(queryExpression);
- // rewriteSearchSpecForPrefixesLocked will return false if none of the prefixes that the
- // client is trying to search on exist, so we can return an empty SearchResult and skip
+ // rewriteSearchSpecForPrefixesLocked will return false if there is nothing to search
+ // over given their search filters, so we can return an empty SearchResult and skip
// sending request to Icing.
- if (!rewriteSearchSpecForPrefixesLocked(searchSpecBuilder, prefixes)) {
+ if (!rewriteSearchSpecForPrefixesLocked(
+ searchSpecBuilder, prefixes, allowedPrefixedSchemas)) {
return new SearchResultPage(Bundle.EMPTY);
}
ResultSpecProto.Builder resultSpecBuilder =
SearchSpecToProtoConverter.toResultSpecProto(searchSpec).toBuilder();
- // rewriteResultSpecForPrefixesLocked will return false if none of the prefixes that the
- // client is trying to search on exist, so we can return an empty SearchResult and skip
- // sending request to Icing.
- if (!rewriteResultSpecForPrefixesLocked(resultSpecBuilder, prefixes)) {
- return new SearchResultPage(Bundle.EMPTY);
- }
+ rewriteResultSpecForPrefixesLocked(resultSpecBuilder, prefixes, allowedPrefixedSchemas);
ScoringSpecProto scoringSpec = SearchSpecToProtoConverter.toScoringSpecProto(searchSpec);
SearchResultProto searchResultProto =
@@ -607,6 +681,31 @@
}
}
+ /** Reports a usage of the given document at the given timestamp. */
+ public void reportUsage(
+ @NonNull String packageName,
+ @NonNull String databaseName,
+ @NonNull String namespace,
+ @NonNull String uri,
+ long usageTimestampMillis)
+ throws AppSearchException {
+ String prefixedNamespace = createPrefix(packageName, databaseName) + namespace;
+ UsageReport report =
+ UsageReport.newBuilder()
+ .setDocumentNamespace(prefixedNamespace)
+ .setDocumentUri(uri)
+ .setUsageTimestampMs(usageTimestampMillis)
+ .setUsageType(UsageReport.UsageType.USAGE_TYPE1)
+ .build();
+ mReadWriteLock.writeLock().lock();
+ try {
+ ReportUsageResultProto result = mIcingSearchEngineLocked.reportUsage(report);
+ checkSuccess(result.getStatus());
+ } finally {
+ mReadWriteLock.writeLock().unlock();
+ }
+ }
+
/**
* Removes the given document by URI.
*
@@ -667,12 +766,14 @@
DeleteByQueryResultProto deleteResultProto;
mReadWriteLock.writeLock().lock();
try {
- // Only rewrite SearchSpec for non empty prefixes.
- // rewriteSearchSpecForPrefixesLocked will return false for empty prefixes, we
- // should skip sending request to Icing and return in here.
+ String prefix = createPrefix(packageName, databaseName);
+ Set<String> allowedPrefixedSchemas = getAllowedPrefixSchemas(prefix, searchSpec);
+
+ // rewriteSearchSpecForPrefixesLocked will return false if there is nothing to search
+ // over given their search filters, so we can return early and skip sending request
+ // to Icing.
if (!rewriteSearchSpecForPrefixesLocked(
- searchSpecBuilder,
- Collections.singleton(createPrefix(packageName, databaseName)))) {
+ searchSpecBuilder, Collections.singleton(prefix), allowedPrefixedSchemas)) {
return;
}
deleteResultProto = mIcingSearchEngineLocked.deleteByQuery(searchSpecBuilder.build());
@@ -695,6 +796,8 @@
* <p>If the app crashes before a call to PersistToDisk(), Icing would trigger a costly recovery
* process in next initialization. After that, Icing would still be able to recover all written
* data.
+ *
+ * @throws AppSearchException on any error that AppSearch persist data to disk.
*/
public void persistToDisk() throws AppSearchException {
PersistToDiskResultProto persistToDiskResultProto =
@@ -904,19 +1007,23 @@
}
/**
- * Rewrites the schemaTypeFilters and namespacesFilters that exist with {@code prefixes}.
- *
- * <p>If the searchSpec has empty filter lists, all prefixes filters will be added.
+ * Rewrites the search spec filters with {@code prefixes}.
*
* <p>This method should be only called in query methods and get the READ lock to keep thread
* safety.
*
- * @return false if none of the requested prefixes exist.
+ * @param searchSpecBuilder Client-provided SearchSpec
+ * @param prefixes Prefixes that we should prepend to all our filters
+ * @param allowedPrefixedSchemas Prefixed schemas that the client is allowed to query over. This
+ * supersedes the schema filters that may exist on the {@code searchSpecBuilder}.
+ * @return false if none there would be nothing to search over.
*/
@VisibleForTesting
@GuardedBy("mReadWriteLock")
boolean rewriteSearchSpecForPrefixesLocked(
- @NonNull SearchSpecProto.Builder searchSpecBuilder, @NonNull Set<String> prefixes) {
+ @NonNull SearchSpecProto.Builder searchSpecBuilder,
+ @NonNull Set<String> prefixes,
+ @NonNull Set<String> allowedPrefixedSchemas) {
// Create a copy since retainAll() modifies the original set.
Set<String> existingPrefixes = new ArraySet<>(mNamespaceMapLocked.keySet());
existingPrefixes.retainAll(prefixes);
@@ -926,29 +1033,28 @@
return false;
}
- // Cache the schema type filters and namespaces before clearing everything.
- List<String> schemaTypeFilters = searchSpecBuilder.getSchemaTypeFiltersList();
- searchSpecBuilder.clearSchemaTypeFilters();
+ if (allowedPrefixedSchemas.isEmpty()) {
+ // Not allowed to search over any schemas, empty query.
+ return false;
+ }
+ // Clear the schema type filters since we'll be rewriting them with the
+ // allowedPrefixedSchemas.
+ searchSpecBuilder.clearSchemaTypeFilters();
+ searchSpecBuilder.addAllSchemaTypeFilters(allowedPrefixedSchemas);
+
+ // Cache the namespaces before clearing everything.
List<String> namespaceFilters = searchSpecBuilder.getNamespaceFiltersList();
searchSpecBuilder.clearNamespaceFilters();
- // Rewrite filters to include a prefix.
+ // Rewrite non-schema filters to include a prefix.
for (String prefix : existingPrefixes) {
- Set<String> existingSchemaTypes = mSchemaMapLocked.get(prefix);
- if (schemaTypeFilters.isEmpty()) {
- // Include all schema types
- searchSpecBuilder.addAllSchemaTypeFilters(existingSchemaTypes);
- } else {
- // Add the prefix to the given schema types
- for (int i = 0; i < schemaTypeFilters.size(); i++) {
- String prefixedType = prefix + schemaTypeFilters.get(i);
- if (existingSchemaTypes.contains(prefixedType)) {
- searchSpecBuilder.addSchemaTypeFilters(prefixedType);
- }
- }
- }
+ // TODO(b/169883602): We currently grab every namespace for every prefix. We can
+ // optimize this by checking if a prefix has any allowedSchemaTypes. If not, that
+ // means we don't want to query over anything in that prefix anyways, so we don't
+ // need to grab its namespaces either.
+ // Empty namespaces on the search spec means to query over all namespaces.
Set<String> existingNamespaces = mNamespaceMapLocked.get(prefix);
if (namespaceFilters.isEmpty()) {
// Include all namespaces
@@ -968,43 +1074,70 @@
}
/**
+ * Returns the set of allowed prefixed schemas that the {@code prefix} can query while taking
+ * into account the {@code searchSpec} schema filters.
+ *
+ * <p>This only checks intersection of schema filters on the search spec with those that the
+ * prefix owns itself. This does not check global query permissions.
+ */
+ private Set<String> getAllowedPrefixSchemas(
+ @NonNull String prefix, @NonNull SearchSpec searchSpec) {
+ Set<String> allowedPrefixedSchemas = new ArraySet<>();
+
+ // Add all the schema filters the client specified.
+ List<String> schemaFilters = searchSpec.getSchemaTypes();
+ for (int i = 0; i < schemaFilters.size(); i++) {
+ allowedPrefixedSchemas.add(prefix + schemaFilters.get(i));
+ }
+
+ if (allowedPrefixedSchemas.isEmpty()) {
+ // If the client didn't specify any schema filters, search over all of their schemas
+ Set<String> prefixedSchemas = mSchemaMapLocked.get(prefix);
+ if (prefixedSchemas != null) {
+ allowedPrefixedSchemas.addAll(prefixedSchemas);
+ }
+ }
+ return allowedPrefixedSchemas;
+ }
+
+ /**
* Rewrites the typePropertyMasks that exist in {@code prefixes}.
*
* <p>This method should be only called in query methods and get the READ lock to keep thread
* safety.
*
- * @return false if none of the requested prefixes exist.
+ * @param resultSpecBuilder ResultSpecs as specified by client
+ * @param prefixes Prefixes that we should prepend to all our filters
+ * @param allowedPrefixedSchemas Prefixed schemas that the client is allowed to query over.
*/
@VisibleForTesting
@GuardedBy("mReadWriteLock")
- boolean rewriteResultSpecForPrefixesLocked(
- @NonNull ResultSpecProto.Builder resultSpecBuilder, @NonNull Set<String> prefixes) {
+ void rewriteResultSpecForPrefixesLocked(
+ @NonNull ResultSpecProto.Builder resultSpecBuilder,
+ @NonNull Set<String> prefixes,
+ @NonNull Set<String> allowedPrefixedSchemas) {
// Create a copy since retainAll() modifies the original set.
Set<String> existingPrefixes = new ArraySet<>(mNamespaceMapLocked.keySet());
existingPrefixes.retainAll(prefixes);
- if (existingPrefixes.isEmpty()) {
- // None of the prefixes exist, empty query.
- return false;
- }
-
List<TypePropertyMask> prefixedTypePropertyMasks = new ArrayList<>();
// Rewrite filters to include a database prefix.
for (String prefix : existingPrefixes) {
- Set<String> existingSchemaTypes = mSchemaMapLocked.get(prefix);
// Qualify the given schema types
for (TypePropertyMask typePropertyMask : resultSpecBuilder.getTypePropertyMasksList()) {
- String qualifiedType = prefix + typePropertyMask.getSchemaType();
- if (existingSchemaTypes.contains(qualifiedType)) {
+ String unprefixedType = typePropertyMask.getSchemaType();
+ boolean isWildcard =
+ unprefixedType.equals(SearchSpec.PROJECTION_SCHEMA_TYPE_WILDCARD);
+ String prefixedType = isWildcard ? unprefixedType : prefix + unprefixedType;
+ if (isWildcard || allowedPrefixedSchemas.contains(prefixedType)) {
prefixedTypePropertyMasks.add(
- typePropertyMask.toBuilder().setSchemaType(qualifiedType).build());
+ typePropertyMask.toBuilder().setSchemaType(prefixedType).build());
}
}
}
resultSpecBuilder
.clearTypePropertyMasks()
.addAllTypePropertyMasks(prefixedTypePropertyMasks);
- return true;
}
@VisibleForTesting
@@ -1228,6 +1361,7 @@
}
@GuardedBy("mReadWriteLock")
+ @NonNull
@VisibleForTesting
VisibilityStore getVisibilityStoreLocked() {
return mVisibilityStoreLocked;
@@ -1242,28 +1376,8 @@
* @return AppSearchException with the parallel error code.
*/
private static AppSearchException statusProtoToAppSearchException(StatusProto statusProto) {
- switch (statusProto.getCode()) {
- case INVALID_ARGUMENT:
- return new AppSearchException(
- AppSearchResult.RESULT_INVALID_ARGUMENT, statusProto.getMessage());
- case NOT_FOUND:
- return new AppSearchException(
- AppSearchResult.RESULT_NOT_FOUND, statusProto.getMessage());
- case FAILED_PRECONDITION:
- // Fallthrough
- case ABORTED:
- // Fallthrough
- case INTERNAL:
- return new AppSearchException(
- AppSearchResult.RESULT_INTERNAL_ERROR, statusProto.getMessage());
- case OUT_OF_SPACE:
- return new AppSearchException(
- AppSearchResult.RESULT_OUT_OF_SPACE, statusProto.getMessage());
- default:
- // Some unknown/unsupported error
- return new AppSearchException(
- AppSearchResult.RESULT_UNKNOWN_ERROR,
- "Unknown IcingSearchEngine status code: " + statusProto.getCode());
- }
+ return new AppSearchException(
+ ResultCodeToProtoConverter.toResultCode(statusProto.getCode()),
+ statusProto.getMessage());
}
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/ResultCodeToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/ResultCodeToProtoConverter.java
new file mode 100644
index 0000000..e340de0
--- /dev/null
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/ResultCodeToProtoConverter.java
@@ -0,0 +1,62 @@
+/*
+ * 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.converter;
+
+import android.annotation.NonNull;
+import android.app.appsearch.AppSearchResult;
+import android.util.Log;
+
+import com.google.android.icing.proto.StatusProto;
+
+/**
+ * Translates an {@link StatusProto.Code} into a {@link AppSearchResult.ResultCode}
+ *
+ * @hide
+ */
+public final class ResultCodeToProtoConverter {
+
+ private static final String TAG = "AppSearchResultCodeToPr";
+
+ private ResultCodeToProtoConverter() {}
+
+ /** Converts an {@link StatusProto.Code} into a {@link AppSearchResult.ResultCode}. */
+ public static @AppSearchResult.ResultCode int toResultCode(
+ @NonNull StatusProto.Code statusCode) {
+ switch (statusCode) {
+ case OK:
+ return AppSearchResult.RESULT_OK;
+ case OUT_OF_SPACE:
+ return AppSearchResult.RESULT_OUT_OF_SPACE;
+ case INTERNAL:
+ return AppSearchResult.RESULT_INTERNAL_ERROR;
+ case UNKNOWN:
+ return AppSearchResult.RESULT_UNKNOWN_ERROR;
+ case NOT_FOUND:
+ return AppSearchResult.RESULT_NOT_FOUND;
+ case INVALID_ARGUMENT:
+ return AppSearchResult.RESULT_INVALID_ARGUMENT;
+ default:
+ // Some unknown/unsupported error
+ Log.e(
+ TAG,
+ "Cannot convert IcingSearchEngine status code: "
+ + statusCode
+ + " to AppSearchResultCode.");
+ return AppSearchResult.RESULT_INTERNAL_ERROR;
+ }
+ }
+}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverter.java
index 4165af3..ce1c9f4 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverter.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverter.java
@@ -22,6 +22,7 @@
import com.android.internal.util.Preconditions;
+import com.google.android.icing.proto.DocumentIndexingConfig;
import com.google.android.icing.proto.PropertyConfigProto;
import com.google.android.icing.proto.SchemaTypeConfigProto;
import com.google.android.icing.proto.SchemaTypeConfigProtoOrBuilder;
@@ -48,7 +49,9 @@
public static SchemaTypeConfigProto toSchemaTypeConfigProto(@NonNull AppSearchSchema schema) {
Preconditions.checkNotNull(schema);
SchemaTypeConfigProto.Builder protoBuilder =
- SchemaTypeConfigProto.newBuilder().setSchemaType(schema.getSchemaType());
+ SchemaTypeConfigProto.newBuilder()
+ .setSchemaType(schema.getSchemaType())
+ .setVersion(schema.getVersion());
List<AppSearchSchema.PropertyConfig> properties = schema.getProperties();
for (int i = 0; i < properties.size(); i++) {
PropertyConfigProto propertyProto = toPropertyConfigProto(properties.get(i));
@@ -63,7 +66,6 @@
Preconditions.checkNotNull(property);
PropertyConfigProto.Builder builder =
PropertyConfigProto.newBuilder().setPropertyName(property.getName());
- StringIndexingConfig.Builder indexingConfig = StringIndexingConfig.newBuilder();
// Set dataType
@AppSearchSchema.PropertyConfig.DataType int dataType = property.getDataType();
@@ -74,12 +76,6 @@
}
builder.setDataType(dataTypeProto);
- // Set schemaType
- String schemaType = property.getSchemaType();
- if (schemaType != null) {
- builder.setSchemaType(schemaType);
- }
-
// Set cardinality
@AppSearchSchema.PropertyConfig.Cardinality int cardinality = property.getCardinality();
PropertyConfigProto.Cardinality.Code cardinalityProto =
@@ -89,36 +85,27 @@
}
builder.setCardinality(cardinalityProto);
- // Set indexingType
- @AppSearchSchema.PropertyConfig.IndexingType int indexingType = property.getIndexingType();
- TermMatchType.Code termMatchTypeProto;
- switch (indexingType) {
- case AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE:
- termMatchTypeProto = TermMatchType.Code.UNKNOWN;
- break;
- case AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS:
- termMatchTypeProto = TermMatchType.Code.EXACT_ONLY;
- break;
- case AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES:
- termMatchTypeProto = TermMatchType.Code.PREFIX;
- break;
- default:
- throw new IllegalArgumentException("Invalid indexingType: " + indexingType);
- }
- indexingConfig.setTermMatchType(termMatchTypeProto);
+ if (property instanceof AppSearchSchema.StringPropertyConfig) {
+ AppSearchSchema.StringPropertyConfig stringProperty =
+ (AppSearchSchema.StringPropertyConfig) property;
+ StringIndexingConfig stringIndexingConfig =
+ StringIndexingConfig.newBuilder()
+ .setTermMatchType(
+ convertTermMatchTypeToProto(stringProperty.getIndexingType()))
+ .setTokenizerType(
+ convertTokenizerTypeToProto(stringProperty.getTokenizerType()))
+ .build();
+ builder.setStringIndexingConfig(stringIndexingConfig);
- // Set tokenizerType
- @AppSearchSchema.PropertyConfig.TokenizerType
- int tokenizerType = property.getTokenizerType();
- StringIndexingConfig.TokenizerType.Code tokenizerTypeProto =
- StringIndexingConfig.TokenizerType.Code.forNumber(tokenizerType);
- if (tokenizerTypeProto == null) {
- throw new IllegalArgumentException("Invalid tokenizerType: " + tokenizerType);
+ } else if (property instanceof AppSearchSchema.DocumentPropertyConfig) {
+ AppSearchSchema.DocumentPropertyConfig documentProperty =
+ (AppSearchSchema.DocumentPropertyConfig) property;
+ builder.setSchemaType(documentProperty.getSchemaType())
+ .setDocumentIndexingConfig(
+ DocumentIndexingConfig.newBuilder()
+ .setIndexNestedProperties(
+ documentProperty.isIndexNestedProperties()));
}
- indexingConfig.setTokenizerType(tokenizerTypeProto);
-
- // Build!
- builder.setStringIndexingConfig(indexingConfig);
return builder.build();
}
@@ -129,7 +116,8 @@
@NonNull
public static AppSearchSchema toAppSearchSchema(@NonNull SchemaTypeConfigProtoOrBuilder proto) {
Preconditions.checkNotNull(proto);
- AppSearchSchema.Builder builder = new AppSearchSchema.Builder(proto.getSchemaType());
+ AppSearchSchema.Builder builder =
+ new AppSearchSchema.Builder(proto.getSchemaType()).setVersion(proto.getVersion());
List<PropertyConfigProto> properties = proto.getPropertiesList();
for (int i = 0; i < properties.size(); i++) {
AppSearchSchema.PropertyConfig propertyConfig = toPropertyConfig(properties.get(i));
@@ -142,39 +130,99 @@
private static AppSearchSchema.PropertyConfig toPropertyConfig(
@NonNull PropertyConfigProto proto) {
Preconditions.checkNotNull(proto);
- AppSearchSchema.PropertyConfig.Builder builder =
- new AppSearchSchema.PropertyConfig.Builder(proto.getPropertyName())
- .setDataType(proto.getDataType().getNumber())
+ switch (proto.getDataType()) {
+ case STRING:
+ return toStringPropertyConfig(proto);
+ case INT64:
+ return new AppSearchSchema.Int64PropertyConfig.Builder(proto.getPropertyName())
+ .setCardinality(proto.getCardinality().getNumber())
+ .build();
+ case DOUBLE:
+ return new AppSearchSchema.DoublePropertyConfig.Builder(proto.getPropertyName())
+ .setCardinality(proto.getCardinality().getNumber())
+ .build();
+ case BOOLEAN:
+ return new AppSearchSchema.BooleanPropertyConfig.Builder(proto.getPropertyName())
+ .setCardinality(proto.getCardinality().getNumber())
+ .build();
+ case BYTES:
+ return new AppSearchSchema.BytesPropertyConfig.Builder(proto.getPropertyName())
+ .setCardinality(proto.getCardinality().getNumber())
+ .build();
+ case DOCUMENT:
+ return toDocumentPropertyConfig(proto);
+ default:
+ throw new IllegalArgumentException("Invalid dataType: " + proto.getDataType());
+ }
+ }
+
+ @NonNull
+ private static AppSearchSchema.StringPropertyConfig toStringPropertyConfig(
+ @NonNull PropertyConfigProto proto) {
+ AppSearchSchema.StringPropertyConfig.Builder builder =
+ new AppSearchSchema.StringPropertyConfig.Builder(proto.getPropertyName())
.setCardinality(proto.getCardinality().getNumber())
.setTokenizerType(
proto.getStringIndexingConfig().getTokenizerType().getNumber());
- // Set schema
- if (!proto.getSchemaType().isEmpty()) {
- builder.setSchemaType(proto.getSchemaType());
- }
-
// Set indexingType
- @AppSearchSchema.PropertyConfig.IndexingType int indexingType;
TermMatchType.Code termMatchTypeProto = proto.getStringIndexingConfig().getTermMatchType();
- switch (termMatchTypeProto) {
+ builder.setIndexingType(convertTermMatchTypeFromProto(termMatchTypeProto));
+
+ return builder.build();
+ }
+
+ @NonNull
+ private static AppSearchSchema.DocumentPropertyConfig toDocumentPropertyConfig(
+ @NonNull PropertyConfigProto proto) {
+ return new AppSearchSchema.DocumentPropertyConfig.Builder(proto.getPropertyName())
+ .setCardinality(proto.getCardinality().getNumber())
+ .setSchemaType(proto.getSchemaType())
+ .setIndexNestedProperties(
+ proto.getDocumentIndexingConfig().getIndexNestedProperties())
+ .build();
+ }
+
+ @NonNull
+ private static TermMatchType.Code convertTermMatchTypeToProto(
+ @AppSearchSchema.StringPropertyConfig.IndexingType int indexingType) {
+ switch (indexingType) {
+ case AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE:
+ return TermMatchType.Code.UNKNOWN;
+ case AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS:
+ return TermMatchType.Code.EXACT_ONLY;
+ case AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES:
+ return TermMatchType.Code.PREFIX;
+ default:
+ throw new IllegalArgumentException("Invalid indexingType: " + indexingType);
+ }
+ }
+
+ @AppSearchSchema.StringPropertyConfig.IndexingType
+ private static int convertTermMatchTypeFromProto(@NonNull TermMatchType.Code termMatchType) {
+ switch (termMatchType) {
case UNKNOWN:
- indexingType = AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE;
- break;
+ return AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE;
case EXACT_ONLY:
- indexingType = AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS;
- break;
+ return AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS;
case PREFIX:
- indexingType = AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES;
- break;
+ return AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES;
default:
// Avoid crashing in the 'read' path; we should try to interpret the document to the
// extent possible.
- Log.w(TAG, "Invalid indexingType: " + termMatchTypeProto.getNumber());
- indexingType = AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE;
+ Log.w(TAG, "Invalid indexingType: " + termMatchType.getNumber());
+ return AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE;
}
- builder.setIndexingType(indexingType);
+ }
- return builder.build();
+ @NonNull
+ private static StringIndexingConfig.TokenizerType.Code convertTokenizerTypeToProto(
+ @AppSearchSchema.StringPropertyConfig.TokenizerType int tokenizerType) {
+ StringIndexingConfig.TokenizerType.Code tokenizerTypeProto =
+ StringIndexingConfig.TokenizerType.Code.forNumber(tokenizerType);
+ if (tokenizerTypeProto == null) {
+ throw new IllegalArgumentException("Invalid tokenizerType: " + tokenizerType);
+ }
+ return tokenizerTypeProto;
}
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchSpecToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchSpecToProtoConverter.java
index 0d7d3e1..07d50ae 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchSpecToProtoConverter.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchSpecToProtoConverter.java
@@ -25,10 +25,6 @@
import com.google.android.icing.proto.ScoringSpecProto;
import com.google.android.icing.proto.SearchSpecProto;
import com.google.android.icing.proto.TermMatchType;
-import com.google.android.icing.proto.TypePropertyMask;
-
-import java.util.List;
-import java.util.Map;
/**
* Translates a {@link SearchSpec} into icing search protos.
@@ -61,22 +57,17 @@
@NonNull
public static ResultSpecProto toResultSpecProto(@NonNull SearchSpec spec) {
Preconditions.checkNotNull(spec);
- ResultSpecProto.Builder builder =
- ResultSpecProto.newBuilder()
- .setNumPerPage(spec.getResultCountPerPage())
- .setSnippetSpec(
- ResultSpecProto.SnippetSpecProto.newBuilder()
- .setNumToSnippet(spec.getSnippetCount())
- .setNumMatchesPerProperty(spec.getSnippetCountPerProperty())
- .setMaxWindowBytes(spec.getMaxSnippetSize()));
- Map<String, List<String>> projectionTypePropertyPaths = spec.getProjections();
- for (Map.Entry<String, List<String>> e : projectionTypePropertyPaths.entrySet()) {
- builder.addTypePropertyMasks(
- TypePropertyMask.newBuilder()
- .setSchemaType(e.getKey())
- .addAllPaths(e.getValue()));
- }
- return builder.build();
+ return ResultSpecProto.newBuilder()
+ .setNumPerPage(spec.getResultCountPerPage())
+ .setSnippetSpec(
+ ResultSpecProto.SnippetSpecProto.newBuilder()
+ .setNumToSnippet(spec.getSnippetCount())
+ .setNumMatchesPerProperty(spec.getSnippetCountPerProperty())
+ .setMaxWindowBytes(spec.getMaxSnippetSize()))
+ .addAllTypePropertyMasks(
+ TypePropertyPathToProtoConverter.toTypePropertyMaskList(
+ spec.getProjections()))
+ .build();
}
/** Extracts {@link ScoringSpecProto} information from a {@link SearchSpec}. */
@@ -109,6 +100,10 @@
return ScoringSpecProto.RankingStrategy.Code.CREATION_TIMESTAMP;
case SearchSpec.RANKING_STRATEGY_RELEVANCE_SCORE:
return ScoringSpecProto.RankingStrategy.Code.RELEVANCE_SCORE;
+ case SearchSpec.RANKING_STRATEGY_USAGE_COUNT:
+ return ScoringSpecProto.RankingStrategy.Code.USAGE_TYPE1_COUNT;
+ case SearchSpec.RANKING_STRATEGY_USAGE_LAST_USED_TIMESTAMP:
+ return ScoringSpecProto.RankingStrategy.Code.USAGE_TYPE1_LAST_USED_TIMESTAMP;
default:
throw new IllegalArgumentException(
"Invalid result ranking strategy: " + rankingStrategyCode);
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SetSchemaResultToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SetSchemaResultToProtoConverter.java
new file mode 100644
index 0000000..e1e7d46
--- /dev/null
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SetSchemaResultToProtoConverter.java
@@ -0,0 +1,64 @@
+/*
+ * 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.converter;
+
+import android.annotation.NonNull;
+import android.app.appsearch.SetSchemaResult;
+
+import com.android.internal.util.Preconditions;
+
+import com.google.android.icing.proto.SetSchemaResultProto;
+
+/**
+ * Translates a {@link SetSchemaResultProto} into {@link SetSchemaResult}.
+ *
+ * @hide
+ */
+public class SetSchemaResultToProtoConverter {
+
+ private SetSchemaResultToProtoConverter() {}
+
+ /**
+ * Translate a {@link SetSchemaResultProto} into {@link SetSchemaResult}.
+ *
+ * @param proto The {@link SetSchemaResultProto} containing results.
+ * @param prefix The prefix need to removed from schemaTypes
+ * @return {@link SetSchemaResult} of results.
+ */
+ @NonNull
+ public static SetSchemaResult toSetSchemaResult(
+ @NonNull SetSchemaResultProto proto, @NonNull String prefix) {
+ Preconditions.checkNotNull(proto);
+ Preconditions.checkNotNull(prefix);
+ SetSchemaResult.Builder builder =
+ new SetSchemaResult.Builder()
+ .setResultCode(
+ ResultCodeToProtoConverter.toResultCode(
+ proto.getStatus().getCode()));
+
+ for (int i = 0; i < proto.getDeletedSchemaTypesCount(); i++) {
+ builder.addDeletedSchemaType(proto.getDeletedSchemaTypes(i).substring(prefix.length()));
+ }
+
+ for (int i = 0; i < proto.getIncompatibleSchemaTypesCount(); i++) {
+ builder.addIncompatibleSchemaType(
+ proto.getIncompatibleSchemaTypes(i).substring(prefix.length()));
+ }
+
+ return builder.build();
+ }
+}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/TypePropertyPathToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/TypePropertyPathToProtoConverter.java
new file mode 100644
index 0000000..6f6dad2
--- /dev/null
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/TypePropertyPathToProtoConverter.java
@@ -0,0 +1,52 @@
+/*
+ * 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.converter;
+
+import android.annotation.NonNull;
+
+import com.android.internal.util.Preconditions;
+
+import com.google.android.icing.proto.TypePropertyMask;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Translates a <code>Map<String, List<String>></code> into <code>List<TypePropertyMask></code>.
+ *
+ * @hide
+ */
+public final class TypePropertyPathToProtoConverter {
+ private TypePropertyPathToProtoConverter() {}
+
+ /** Extracts {@link TypePropertyMask} information from a {@link Map}. */
+ @NonNull
+ public static List<TypePropertyMask> toTypePropertyMaskList(
+ @NonNull Map<String, List<String>> typePropertyPaths) {
+ Preconditions.checkNotNull(typePropertyPaths);
+ List<TypePropertyMask> typePropertyMasks = new ArrayList<>(typePropertyPaths.size());
+ for (Map.Entry<String, List<String>> e : typePropertyPaths.entrySet()) {
+ typePropertyMasks.add(
+ TypePropertyMask.newBuilder()
+ .setSchemaType(e.getKey())
+ .addAllPaths(e.getValue())
+ .build());
+ }
+ return typePropertyMasks;
+ }
+}
diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt
index 9be3049..2774181 100644
--- a/apex/appsearch/synced_jetpack_changeid.txt
+++ b/apex/appsearch/synced_jetpack_changeid.txt
@@ -1 +1 @@
-Icd58005ad659b6b3d03f683f8954939175324685
+I3fd4c96bf775c2539d744c416cdbf1d3c9544f03
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShimImpl.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShimImpl.java
index b0478d5..f8d0d80 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShimImpl.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShimImpl.java
@@ -28,10 +28,12 @@
import android.app.appsearch.GetByUriRequest;
import android.app.appsearch.PutDocumentsRequest;
import android.app.appsearch.RemoveByUriRequest;
+import android.app.appsearch.ReportUsageRequest;
import android.app.appsearch.SearchResults;
import android.app.appsearch.SearchResultsShim;
import android.app.appsearch.SearchSpec;
import android.app.appsearch.SetSchemaRequest;
+import android.app.appsearch.SetSchemaResponse;
import android.app.appsearch.exceptions.AppSearchException;
import android.content.Context;
@@ -84,8 +86,8 @@
@Override
@NonNull
- public ListenableFuture<Void> setSchema(@NonNull SetSchemaRequest request) {
- SettableFuture<AppSearchResult<Void>> future = SettableFuture.create();
+ public ListenableFuture<SetSchemaResponse> setSchema(@NonNull SetSchemaRequest request) {
+ SettableFuture<AppSearchResult<SetSchemaResponse>> future = SettableFuture.create();
mAppSearchSession.setSchema(request, mExecutor, future::set);
return Futures.transformAsync(future, this::transformResult, mExecutor);
}
@@ -129,6 +131,14 @@
@Override
@NonNull
+ public ListenableFuture<Void> reportUsage(@NonNull ReportUsageRequest request) {
+ SettableFuture<AppSearchResult<Void>> future = SettableFuture.create();
+ mAppSearchSession.reportUsage(request, mExecutor, future::set);
+ return Futures.transformAsync(future, this::transformResult, mExecutor);
+ }
+
+ @Override
+ @NonNull
public ListenableFuture<AppSearchBatchResult<String, Void>> removeByUri(
@NonNull RemoveByUriRequest request) {
SettableFuture<AppSearchBatchResult<String, Void>> future = SettableFuture.create();
@@ -150,6 +160,16 @@
mAppSearchSession.close();
}
+ @Override
+ @NonNull
+ public ListenableFuture<Void> maybeFlush() {
+ SettableFuture<AppSearchResult<Void>> future = SettableFuture.create();
+ // The data in platform will be flushed by scheduled task. AppSearchSession won't do
+ // anything extra flush.
+ future.set(AppSearchResult.newSuccessfulResult(null));
+ return Futures.transformAsync(future, this::transformResult, mExecutor);
+ }
+
private <T> ListenableFuture<T> transformResult(
@NonNull AppSearchResult<T> result) throws AppSearchException {
if (!result.isSuccess()) {
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 3e81968..e8ea6ef 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
@@ -69,12 +69,19 @@
* {@link AppSearchResult#RESULT_INVALID_SCHEMA} and a message describing the incompatibility.
* In this case the previously set schema will remain active.
*
- * <p>If you need to make non-backwards-compatible changes as described above, you can set the
- * {@link SetSchemaRequest.Builder#setForceOverride} method to {@code true}. In this case,
- * instead of completing its future with an {@link
- * android.app.appsearch.exceptions.AppSearchException} with the {@link
- * AppSearchResult#RESULT_INVALID_SCHEMA} error code, all documents which are not compatible
- * with the new schema will be deleted and the incompatible schema will be applied.
+ * <p>If you need to make non-backwards-compatible changes as described above, you can either:
+ *
+ * <ul>
+ * <li>Set the {@link SetSchemaRequest.Builder#setForceOverride} method to {@code true}. In
+ * this case, instead of completing its future with an {@link
+ * android.app.appsearch.exceptions.AppSearchException} with the {@link
+ * AppSearchResult#RESULT_INVALID_SCHEMA} error code, all documents which are not
+ * compatible with the new schema will be deleted and the incompatible schema will be
+ * applied.
+ * <li>Add a {@link android.app.appsearch.AppSearchSchema.Migrator} for each incompatible type
+ * and make no deletion. The migrator will migrate documents from it's old schema version
+ * to the new version. See the migration section below.
+ * </ul>
*
* <p>It is a no-op to set the same schema as has been previously set; this is handled
* efficiently.
@@ -85,13 +92,34 @@
* Visibility settings for a schema type do not apply or persist across {@link
* SetSchemaRequest}s.
*
+ * <p>Migration: make non-backwards-compatible changes will delete all stored documents in old
+ * schema. You can save your documents by setting {@link
+ * android.app.appsearch.AppSearchSchema.Migrator} via the {@link
+ * SetSchemaRequest.Builder#setMigrator} for each type you want to save.
+ *
+ * <p>{@link android.app.appsearch.AppSearchSchema.Migrator#onDowngrade} or {@link
+ * android.app.appsearch.AppSearchSchema.Migrator#onUpgrade} will be triggered if the version
+ * number of the schema stored in AppSearch is different with the version in the request.
+ *
+ * <p>If any error or Exception occurred in the {@link
+ * android.app.appsearch.AppSearchSchema.Migrator#onDowngrade}, {@link
+ * android.app.appsearch.AppSearchSchema.Migrator#onUpgrade} or {@link
+ * android.app.appsearch.AppSearchMigrationHelper.Transformer#transform}, the migration will be
+ * terminated, the setSchema request will be rejected unless the schema changes are
+ * backwards-compatible, and stored documents won't have any observable changes.
+ *
* @param request The schema update request.
- * @return The pending result of performing this operation.
+ * @return The pending {@link SetSchemaResponse} of performing this operation. Success if the
+ * the schema has been set and any migrations has been done. Otherwise, the failure {@link
+ * android.app.appsearch.SetSchemaResponse.MigrationFailure} indicates which document is
+ * fail to be migrated.
+ * @see android.app.appsearch.AppSearchSchema.Migrator
+ * @see android.app.appsearch.AppSearchMigrationHelper.Transformer
*/
// TODO(b/169883602): Change @code references to @link when setPlatformSurfaceable APIs are
// exposed.
@NonNull
- ListenableFuture<Void> setSchema(@NonNull SetSchemaRequest request);
+ ListenableFuture<SetSchemaResponse> setSchema(@NonNull SetSchemaRequest request);
/**
* Retrieves the schema most recently successfully provided to {@link #setSchema}.
@@ -175,6 +203,25 @@
SearchResultsShim query(@NonNull String queryExpression, @NonNull SearchSpec searchSpec);
/**
+ * Reports usage of a particular document by URI and namespace.
+ *
+ * <p>A usage report represents an event in which a user interacted with or viewed a document.
+ *
+ * <p>For each call to {@link #reportUsage}, AppSearch updates usage count and usage recency
+ * metrics for that particular document. These metrics are used for ordering {@link #query}
+ * results by the {@link SearchSpec#RANKING_STRATEGY_USAGE_COUNT} and {@link
+ * SearchSpec#RANKING_STRATEGY_USAGE_LAST_USED_TIMESTAMP} ranking strategies.
+ *
+ * <p>Reporting usage of a document is optional.
+ *
+ * @param request The usage reporting request.
+ * @return The pending result of performing this operation which resolves to {@code null} on
+ * success.
+ */
+ @NonNull
+ ListenableFuture<Void> reportUsage(@NonNull ReportUsageRequest request);
+
+ /**
* Removes {@link GenericDocument}s from the index by URI.
*
* @param request Request containing URIs to be removed.
@@ -208,6 +255,17 @@
@NonNull String queryExpression, @NonNull SearchSpec searchSpec);
/**
+ * Flush all schema and document updates, additions, and deletes to disk if possible.
+ *
+ * @return The pending result of performing this operation. {@link
+ * android.app.appsearch.exceptions.AppSearchException} with {@link
+ * AppSearchResult#RESULT_INTERNAL_ERROR} will be set to the future if we hit error when
+ * save to disk.
+ */
+ @NonNull
+ ListenableFuture<Void> maybeFlush();
+
+ /**
* Closes the {@link AppSearchSessionShim} to persist all schema and document updates,
* additions, and deletes to disk.
*/
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchTestUtils.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchTestUtils.java
index 459fd151..20fb909 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchTestUtils.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchTestUtils.java
@@ -25,9 +25,11 @@
import android.app.appsearch.GetByUriRequest;
import android.app.appsearch.SearchResult;
import android.app.appsearch.SearchResultsShim;
+import android.app.appsearch.SetSchemaResponse;
import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.Future;
public class AppSearchTestUtils {
@@ -41,6 +43,15 @@
return result;
}
+ // TODO(b/151178558) check setSchemaResponse.xxxtypes for the test need to verify.
+ public static void checkIsSetSchemaResponseSuccess(Future<SetSchemaResponse> future)
+ throws Exception {
+ SetSchemaResponse setSchemaResponse = future.get();
+ assertWithMessage("SetSchemaResponse not successful.")
+ .that(setSchemaResponse.isSuccess())
+ .isTrue();
+ }
+
public static List<GenericDocument> doGet(
AppSearchSessionShim session, String namespace, String... uris) throws Exception {
AppSearchBatchResult<String, GenericDocument> result =
@@ -59,6 +70,20 @@
return list;
}
+ public static List<GenericDocument> doGet(AppSearchSessionShim session, GetByUriRequest request)
+ throws Exception {
+ AppSearchBatchResult<String, GenericDocument> result =
+ checkIsBatchResultSuccess(session.getByUri(request));
+ Set<String> uris = request.getUris();
+ assertThat(result.getSuccesses()).hasSize(uris.size());
+ assertThat(result.getFailures()).isEmpty();
+ List<GenericDocument> list = new ArrayList<>(uris.size());
+ for (String uri : uris) {
+ list.add(result.getSuccesses().get(uri));
+ }
+ return list;
+ }
+
public static List<GenericDocument> convertSearchResultsToDocuments(
SearchResultsShim searchResults) throws Exception {
List<SearchResult> results = searchResults.getNextPage().get();
diff --git a/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
index 484fec3..56aa590 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
@@ -40,6 +40,13 @@
"options": [
{"include-filter": "com.android.server.job"}
]
+ },
+ {
+ "name": "CtsHostsideNetworkTests",
+ "options": [
+ {"include-filter": "com.android.cts.net.HostsideRestrictBackgroundNetworkTests#testMeteredNetworkAccess_expeditedJob"},
+ {"include-filter": "com.android.cts.net.HostsideRestrictBackgroundNetworkTests#testNonMeteredNetworkAccess_expeditedJob"}
+ ]
}
]
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
index 04d6947..58396eb 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
@@ -203,7 +203,7 @@
isActive = (activeState == KNOWN_ACTIVE);
}
if (isActive && jobStatus.getStandbyBucket() == NEVER_INDEX) {
- Slog.wtf(TAG, "App " + packageName + " became active but still in NEVER bucket");
+ jobStatus.maybeLogBucketMismatch();
}
boolean didChange = jobStatus.setBackgroundNotRestrictedConstraintSatisfied(canRun);
didChange |= jobStatus.setUidActive(isActive);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index 51525e0..09dc7d2 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -206,6 +206,11 @@
private int standbyBucket;
/**
+ * Whether we've logged an error due to standby bucket mismatch with active uid state.
+ */
+ private boolean mLoggedBucketMismatch;
+
+ /**
* Debugging: timestamp if we ever defer this job based on standby bucketing, this
* is when we did so.
*/
@@ -805,6 +810,18 @@
}
standbyBucket = newBucket;
+ mLoggedBucketMismatch = false;
+ }
+
+ /**
+ * Log a bucket mismatch if this is the first time for this job.
+ */
+ public void maybeLogBucketMismatch() {
+ if (!mLoggedBucketMismatch) {
+ Slog.wtf(TAG,
+ "App " + getSourcePackageName() + " became active but still in NEVER bucket");
+ mLoggedBucketMismatch = true;
+ }
}
// Called only by the standby monitoring code
diff --git a/apex/media/framework/api/current.txt b/apex/media/framework/api/current.txt
index 103bb47..2543a9c 100644
--- a/apex/media/framework/api/current.txt
+++ b/apex/media/framework/api/current.txt
@@ -22,7 +22,6 @@
method @NonNull public android.media.ApplicationMediaCapabilities.Builder addUnsupportedHdrType(@NonNull String);
method @NonNull public android.media.ApplicationMediaCapabilities.Builder addUnsupportedVideoMimeType(@NonNull String);
method @NonNull public android.media.ApplicationMediaCapabilities build();
- method @NonNull public android.media.ApplicationMediaCapabilities.Builder setSlowMotionSupported(boolean);
}
public static class ApplicationMediaCapabilities.FormatNotFoundException extends android.util.AndroidException {
diff --git a/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java b/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java
index 24c9e78..e1a8596 100644
--- a/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java
+++ b/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java
@@ -56,16 +56,10 @@
* <h4>Capability of handling HDR(high dynamic range) video</h4>
* There are four types of HDR video(Dolby-Vision, HDR10, HDR10+, HLG) supported by the platform,
* application will only need to specify individual types they supported.
- *
- * <h4>Capability of handling Slow Motion video</h4>
- * There is no standard format for slow motion yet. If an application indicates support for slow
- * motion, it is application's responsibility to parse the slow motion videos using their own parser
- * or using support library.
*/
// TODO(huang): Correct openTypedAssetFileDescriptor with the new API after it is added.
// TODO(hkuang): Add a link to seamless transcoding detail when it is published
// TODO(hkuang): Add code sample on how to build a capability object with MediaCodecList
-// TODO(hkuang): Add the support library page on parsing slow motion video.
public final class ApplicationMediaCapabilities implements Parcelable {
private static final String TAG = "ApplicationMediaCapabilities";
@@ -260,6 +254,7 @@
/*
* Whether handling of slow-motion video is supported
+ * @hide
*/
public boolean isSlowMotionSupported() {
return mIsSlowMotionSupported;
@@ -578,6 +573,7 @@
* If an application indicates support for slow-motion, it is application's responsibility
* to parse the slow-motion videos using their own parser or using support library.
* @see android.media.MediaFormat#KEY_SLOW_MOTION_MARKERS
+ * @hide
*/
@NonNull
public Builder setSlowMotionSupported(boolean slowMotionSupported) {
diff --git a/apex/media/framework/java/android/media/MediaTranscodeManager.java b/apex/media/framework/java/android/media/MediaTranscodeManager.java
index 55c4629..0852fdf 100644
--- a/apex/media/framework/java/android/media/MediaTranscodeManager.java
+++ b/apex/media/framework/java/android/media/MediaTranscodeManager.java
@@ -1023,10 +1023,13 @@
"Source Width and height must be larger than 0");
}
- float frameRate = mSrcVideoFormatHint.getFloat(MediaFormat.KEY_FRAME_RATE);
- if (frameRate <= 0) {
- throw new IllegalArgumentException(
- "frameRate must be larger than 0");
+ float frameRate = 30.0f; // default to 30fps.
+ if (mSrcVideoFormatHint.containsKey(MediaFormat.KEY_FRAME_RATE)) {
+ frameRate = mSrcVideoFormatHint.getFloat(MediaFormat.KEY_FRAME_RATE);
+ if (frameRate <= 0) {
+ throw new IllegalArgumentException(
+ "frameRate must be larger than 0");
+ }
}
int bitrate = getAVCBitrate(width, height, frameRate);
diff --git a/api/Android.bp b/api/Android.bp
index 69f03b8..1a58a16f 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -52,10 +52,7 @@
dest: "current.txt",
},
{
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk", "win_sdk"],
dir: "apistubs/android/public/api",
dest: "android.txt",
},
@@ -112,6 +109,11 @@
dir: "api",
dest: "removed.txt",
},
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/public/api",
+ dest: "removed.txt",
+ },
],
}
@@ -139,10 +141,7 @@
dest: "system-current.txt",
},
{
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk", "win_sdk"],
dir: "apistubs/android/system/api",
dest: "android.txt",
},
@@ -173,6 +172,11 @@
dir: "api",
dest: "system-removed.txt",
},
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/system/api",
+ dest: "removed.txt",
+ },
],
visibility: ["//visibility:public"],
}
@@ -201,10 +205,7 @@
dest: "module-lib-current.txt",
},
{
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk", "win_sdk"],
dir: "apistubs/android/module-lib/api",
dest: "android.txt",
},
@@ -234,6 +235,11 @@
dir: "api",
dest: "module-lib-removed.txt",
},
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/module-lib/api",
+ dest: "removed.txt",
+ },
],
}
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index ebe6199..4e46aa3 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -174,10 +174,6 @@
instrument.noWindowAnimation = true;
} else if (opt.equals("--no-hidden-api-checks")) {
instrument.disableHiddenApiChecks = true;
- } else if (opt.equals("--no-test-api-checks")) {
- // TODO(satayev): remove this option, only kept for backwards compatibility with
- // cached tradefed instance
- instrument.disableTestApiChecks = false;
} else if (opt.equals("--no-test-api-access")) {
instrument.disableTestApiChecks = false;
} else if (opt.equals("--no-isolated-storage")) {
@@ -200,7 +196,6 @@
}
instrument.componentNameArg = nextArgRequired();
-
instrument.run();
}
}
diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java
index 9088db8..260c8a4 100644
--- a/cmds/sm/src/com/android/commands/sm/Sm.java
+++ b/cmds/sm/src/com/android/commands/sm/Sm.java
@@ -20,6 +20,7 @@
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemProperties;
import android.os.storage.DiskInfo;
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
@@ -30,6 +31,8 @@
public final class Sm {
private static final String TAG = "Sm";
+ private static final String ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY =
+ "persist.sys.vold_app_data_isolation_enabled";
IStorageManager mSm;
@@ -254,6 +257,10 @@
}
public void runDisableAppDataIsolation() throws RemoteException {
+ if (!SystemProperties.getBoolean(
+ ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false)) {
+ throw new IllegalStateException("Storage app data isolation is not enabled.");
+ }
final String pkgName = nextArg();
final int pid = Integer.parseInt(nextArg());
final int userId = Integer.parseInt(nextArg());
diff --git a/core/api/current.txt b/core/api/current.txt
index 9da670f..892ddf4 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -10311,6 +10311,7 @@
method public void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public abstract void sendOrderedBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public abstract void sendStickyBroadcast(@RequiresPermission android.content.Intent);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public void sendStickyBroadcast(@NonNull @RequiresPermission android.content.Intent, @Nullable android.os.Bundle);
method @Deprecated @RequiresPermission(allOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.BROADCAST_STICKY}) public abstract void sendStickyBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle);
method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public abstract void sendStickyOrderedBroadcast(@RequiresPermission android.content.Intent, android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
method @Deprecated @RequiresPermission(allOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.BROADCAST_STICKY}) public abstract void sendStickyOrderedBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
@@ -12383,6 +12384,7 @@
field public static final String FEATURE_SCREEN_PORTRAIT = "android.hardware.screen.portrait";
field public static final String FEATURE_SECURELY_REMOVES_USERS = "android.software.securely_removes_users";
field public static final String FEATURE_SECURE_LOCK_SCREEN = "android.software.secure_lock_screen";
+ field public static final String FEATURE_SECURITY_MODEL_COMPATIBLE = "android.hardware.security.model.compatible";
field public static final String FEATURE_SENSOR_ACCELEROMETER = "android.hardware.sensor.accelerometer";
field public static final String FEATURE_SENSOR_AMBIENT_TEMPERATURE = "android.hardware.sensor.ambient_temperature";
field public static final String FEATURE_SENSOR_BAROMETER = "android.hardware.sensor.barometer";
@@ -31281,6 +31283,7 @@
method @NonNull public android.os.StrictMode.VmPolicy.Builder detectLeakedRegistrationObjects();
method @NonNull public android.os.StrictMode.VmPolicy.Builder detectLeakedSqlLiteObjects();
method @NonNull public android.os.StrictMode.VmPolicy.Builder detectNonSdkApiUsage();
+ method @NonNull public android.os.StrictMode.VmPolicy.Builder detectUnsafeIntentLaunch();
method @NonNull public android.os.StrictMode.VmPolicy.Builder detectUntaggedSockets();
method @NonNull public android.os.StrictMode.VmPolicy.Builder penaltyDeath();
method @NonNull public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnCleartextNetwork();
@@ -31289,6 +31292,7 @@
method @NonNull public android.os.StrictMode.VmPolicy.Builder penaltyListener(@NonNull java.util.concurrent.Executor, @NonNull android.os.StrictMode.OnVmViolationListener);
method @NonNull public android.os.StrictMode.VmPolicy.Builder penaltyLog();
method @NonNull public android.os.StrictMode.VmPolicy.Builder permitNonSdkApiUsage();
+ method @NonNull public android.os.StrictMode.VmPolicy.Builder permitUnsafeIntentLaunch();
method @NonNull public android.os.StrictMode.VmPolicy.Builder setClassInstanceLimit(Class, int);
}
@@ -31815,6 +31819,9 @@
public final class UnbufferedIoViolation extends android.os.strictmode.Violation {
}
+ public final class UnsafeIntentLaunchViolation extends android.os.strictmode.Violation {
+ }
+
public final class UntaggedSocketViolation extends android.os.strictmode.Violation {
}
@@ -36454,6 +36461,9 @@
method @NonNull public String getVersion();
method public boolean isConnected();
method public void shutdown();
+ field public static final String ACTION_SECURE_ELEMENT_STATE_CHANGED = "android.se.omapi.action.SECURE_ELEMENT_STATE_CHANGED";
+ field public static final String EXTRA_READER_NAME = "android.se.omapi.extra.READER_NAME";
+ field public static final String EXTRA_READER_STATE = "android.se.omapi.extra.READER_STATE";
}
public static interface SEService.OnConnectedListener {
@@ -38197,6 +38207,7 @@
ctor public SpellCheckerService.Session();
method public android.os.Bundle getBundle();
method public String getLocale();
+ method public int getSupportedAttributes();
method public void onCancel();
method public void onClose();
method public abstract void onCreate();
@@ -41469,6 +41480,7 @@
public final class SignalStrengthUpdateRequest implements android.os.Parcelable {
method public int describeContents();
+ method @NonNull public android.os.IBinder getLiveToken();
method @NonNull public java.util.Collection<android.telephony.SignalThresholdInfo> getSignalThresholdInfos();
method public boolean isReportingRequestedWhileIdle();
method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -41771,7 +41783,9 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void removeSubscriptionsFromGroup(@NonNull java.util.List<java.lang.Integer>, @NonNull android.os.ParcelUuid);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunistic(boolean, int);
method public void setSubscriptionOverrideCongested(int, boolean, long);
+ method public void setSubscriptionOverrideCongested(int, boolean, @NonNull int[], long);
method public void setSubscriptionOverrideUnmetered(int, boolean, long);
+ method public void setSubscriptionOverrideUnmetered(int, boolean, @NonNull int[], long);
method public void setSubscriptionPlans(int, @NonNull java.util.List<android.telephony.SubscriptionPlan>);
method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void switchToSubscription(int, @NonNull android.app.PendingIntent);
field public static final String ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED = "android.telephony.action.DEFAULT_SMS_SUBSCRIPTION_CHANGED";
@@ -41847,6 +41861,7 @@
public class TelephonyManager {
method public boolean canChangeDtmfToneLength();
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void clearSignalStrengthUpdateRequest(@NonNull android.telephony.SignalStrengthUpdateRequest);
method @Nullable public android.telephony.TelephonyManager createForPhoneAccountHandle(android.telecom.PhoneAccountHandle);
method public android.telephony.TelephonyManager createForSubscriptionId(int);
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean doesSwitchMultiSimConfigTriggerReboot();
@@ -41926,7 +41941,7 @@
method @Deprecated public String iccTransmitApduLogicalChannel(int, int, int, int, int, int, String);
method public boolean isConcurrentVoiceAndDataSupported();
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE"}) public boolean isDataConnectionAllowed();
- method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean isDataEnabled();
+ method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataEnabled();
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataEnabledForReason(int);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataRoamingEnabled();
method public boolean isEmergencyNumber(@NonNull String);
@@ -41960,6 +41975,7 @@
method public boolean setOperatorBrandOverride(String);
method public boolean setPreferredNetworkTypeToGlobal();
method public void setPreferredOpportunisticDataSubscription(int, boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSignalStrengthUpdateRequest(@NonNull android.telephony.SignalStrengthUpdateRequest);
method public void setVisualVoicemailSmsFilterSettings(android.telephony.VisualVoicemailSmsFilterSettings);
method public boolean setVoiceMailNumber(String, String);
method @Deprecated public void setVoicemailRingtoneUri(android.telecom.PhoneAccountHandle, android.net.Uri);
@@ -42625,6 +42641,7 @@
field public static final int CODE_MEDIA_NO_DATA = 402; // 0x192
field public static final int CODE_MEDIA_UNSPECIFIED = 404; // 0x194
field public static final int CODE_MULTIENDPOINT_NOT_SUPPORTED = 902; // 0x386
+ field public static final int CODE_NETWORK_CONGESTION = 1624; // 0x658
field public static final int CODE_NETWORK_DETACH = 1513; // 0x5e9
field public static final int CODE_NETWORK_REJECT = 1504; // 0x5e0
field public static final int CODE_NETWORK_RESP_TIMEOUT = 1503; // 0x5df
@@ -51789,7 +51806,8 @@
method @Nullable public android.view.textservice.SpellCheckerSubtype getCurrentSpellCheckerSubtype(boolean);
method @Nullable public java.util.List<android.view.textservice.SpellCheckerInfo> getEnabledSpellCheckersList();
method public boolean isSpellCheckerEnabled();
- method public android.view.textservice.SpellCheckerSession newSpellCheckerSession(android.os.Bundle, java.util.Locale, android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener, boolean);
+ method @Nullable public android.view.textservice.SpellCheckerSession newSpellCheckerSession(@Nullable android.os.Bundle, @Nullable java.util.Locale, @NonNull android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener, boolean);
+ method @Nullable public android.view.textservice.SpellCheckerSession newSpellCheckerSession(@Nullable android.os.Bundle, @Nullable java.util.Locale, @NonNull android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener, boolean, int);
}
}
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index bf92b34..061dc87 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -136,6 +136,14 @@
package android.net {
+ public class ConnectivityManager {
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle);
+ }
+
+ public final class NetworkCapabilities implements android.os.Parcelable {
+ field public static final int TRANSPORT_TEST = 7; // 0x7
+ }
+
public final class TcpRepairWindow {
ctor public TcpRepairWindow(int, int, int, int, int, int);
field public final int maxWindow;
@@ -146,6 +154,22 @@
field public final int sndWnd;
}
+ public final class TestNetworkInterface implements android.os.Parcelable {
+ ctor public TestNetworkInterface(@NonNull android.os.ParcelFileDescriptor, @NonNull String);
+ method public int describeContents();
+ method @NonNull public android.os.ParcelFileDescriptor getFileDescriptor();
+ method @NonNull public String getInterfaceName();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.TestNetworkInterface> CREATOR;
+ }
+
+ public class TestNetworkManager {
+ method @NonNull public android.net.TestNetworkInterface createTapInterface();
+ method @NonNull public android.net.TestNetworkInterface createTunInterface(@NonNull java.util.Collection<android.net.LinkAddress>);
+ method public void setupTestNetwork(@NonNull String, @NonNull android.os.IBinder);
+ method public void teardownTestNetwork(@NonNull android.net.Network);
+ }
+
}
package android.os {
@@ -154,6 +178,10 @@
method public final void markVintfStability();
}
+ public static class Build.VERSION {
+ field public static final int FIRST_SDK_INT;
+ }
+
public interface Parcelable {
method public default int getStability();
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 2ca07ee..21da2fb 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -45,6 +45,7 @@
field public static final String BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE = "android.permission.BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE";
field public static final String BIND_PRINT_RECOMMENDATION_SERVICE = "android.permission.BIND_PRINT_RECOMMENDATION_SERVICE";
field public static final String BIND_RESOLVER_RANKER_SERVICE = "android.permission.BIND_RESOLVER_RANKER_SERVICE";
+ field public static final String BIND_RESUME_ON_REBOOT_SERVICE = "android.permission.BIND_RESUME_ON_REBOOT_SERVICE";
field public static final String BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE = "android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE";
field public static final String BIND_SETTINGS_SUGGESTIONS_SERVICE = "android.permission.BIND_SETTINGS_SUGGESTIONS_SERVICE";
field public static final String BIND_SOUND_TRIGGER_DETECTION_SERVICE = "android.permission.BIND_SOUND_TRIGGER_DETECTION_SERVICE";
@@ -136,6 +137,7 @@
field public static final String MANAGE_SENSOR_PRIVACY = "android.permission.MANAGE_SENSOR_PRIVACY";
field public static final String MANAGE_SOUND_TRIGGER = "android.permission.MANAGE_SOUND_TRIGGER";
field public static final String MANAGE_SUBSCRIPTION_PLANS = "android.permission.MANAGE_SUBSCRIPTION_PLANS";
+ field public static final String MANAGE_TEST_NETWORKS = "android.permission.MANAGE_TEST_NETWORKS";
field public static final String MANAGE_TIME_AND_ZONE_DETECTION = "android.permission.MANAGE_TIME_AND_ZONE_DETECTION";
field public static final String MANAGE_UI_TRANSLATION = "android.permission.MANAGE_UI_TRANSLATION";
field public static final String MANAGE_USB = "android.permission.MANAGE_USB";
@@ -1656,8 +1658,14 @@
package android.bluetooth {
public final class BluetoothA2dp implements android.bluetooth.BluetoothProfile {
+ method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public android.bluetooth.BufferConstraints getBufferConstraints();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getDynamicBufferSupport();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setBufferMillis(int, int);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
+ field public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD = 1; // 0x1
+ field public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING = 2; // 0x2
+ field public static final int DYNAMIC_BUFFER_SUPPORT_NONE = 0; // 0x0
field public static final int OPTIONAL_CODECS_NOT_SUPPORTED = 0; // 0x0
field public static final int OPTIONAL_CODECS_PREF_DISABLED = 0; // 0x0
field public static final int OPTIONAL_CODECS_PREF_ENABLED = 1; // 0x1
@@ -1839,6 +1847,25 @@
field public static final int UUID_BYTES_32_BIT = 4; // 0x4
}
+ public final class BufferConstraint implements android.os.Parcelable {
+ ctor public BufferConstraint(int, int, int);
+ method public int describeContents();
+ method public int getDefaultMillis();
+ method public int getMaxMillis();
+ method public int getMinMillis();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BufferConstraint> CREATOR;
+ }
+
+ public final class BufferConstraints implements android.os.Parcelable {
+ ctor public BufferConstraints(@NonNull java.util.List<android.bluetooth.BufferConstraint>);
+ method public int describeContents();
+ method @Nullable public android.bluetooth.BufferConstraint getCodec(int);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int BUFFER_CODEC_MAX_NUM = 32; // 0x20
+ field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BufferConstraints> CREATOR;
+ }
+
}
package android.bluetooth.le {
@@ -6820,6 +6847,7 @@
method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public int registerNetworkProvider(@NonNull android.net.NetworkProvider);
+ method public void registerQosCallback(@NonNull android.net.QosSocketInfo, @NonNull android.net.QosCallback, @NonNull java.util.concurrent.Executor);
method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void requestNetwork(@NonNull android.net.NetworkRequest, int, int, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_AIRPLANE_MODE, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void setAirplaneMode(boolean);
@@ -6829,6 +6857,7 @@
method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public void unregisterNetworkProvider(@NonNull android.net.NetworkProvider);
+ method public void unregisterQosCallback(@NonNull android.net.QosCallback);
method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void unregisterTetheringEventCallback(@NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
@@ -7022,6 +7051,8 @@
method public void onAddKeepalivePacketFilter(int, @NonNull android.net.KeepalivePacketData);
method public void onAutomaticReconnectDisabled();
method public void onNetworkUnwanted();
+ method public void onQosCallbackRegistered(int, @NonNull android.net.QosFilter);
+ method public void onQosCallbackUnregistered(int);
method public void onRemoveKeepalivePacketFilter(int);
method public void onSaveAcceptUnvalidated(boolean);
method public void onSignalStrengthThresholdsUpdated(@NonNull int[]);
@@ -7032,6 +7063,9 @@
method public final void sendLinkProperties(@NonNull android.net.LinkProperties);
method public final void sendNetworkCapabilities(@NonNull android.net.NetworkCapabilities);
method public final void sendNetworkScore(@IntRange(from=0, to=99) int);
+ method public final void sendQosCallbackError(int, int);
+ method public final void sendQosSessionAvailable(int, int, @NonNull android.telephony.data.EpsBearerQosSessionAttributes);
+ method public final void sendQosSessionLost(int, int);
method public final void sendSocketKeepaliveEvent(int, int);
method public final void setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>);
method public void unregister();
@@ -7118,6 +7152,9 @@
method public abstract void onRequestScores(android.net.NetworkKey[]);
}
+ public class NetworkReleasedException extends java.lang.Exception {
+ }
+
public class NetworkRequest implements android.os.Parcelable {
method @Nullable public String getRequestorPackageName();
method public int getRequestorUid();
@@ -7190,6 +7227,46 @@
ctor public NetworkStats.Entry(@Nullable String, int, int, int, int, int, int, long, long, long, long, long);
}
+ public abstract class QosCallback {
+ ctor public QosCallback();
+ method public void onError(@NonNull android.net.QosCallbackException);
+ method public void onQosSessionAvailable(@NonNull android.net.QosSession, @NonNull android.net.QosSessionAttributes);
+ method public void onQosSessionLost(@NonNull android.net.QosSession);
+ }
+
+ public static class QosCallback.QosCallbackRegistrationException extends java.lang.RuntimeException {
+ }
+
+ public final class QosCallbackException extends java.lang.Exception {
+ }
+
+ public abstract class QosFilter {
+ method @NonNull public abstract android.net.Network getNetwork();
+ }
+
+ public final class QosSession implements android.os.Parcelable {
+ ctor public QosSession(int, int);
+ method public int describeContents();
+ method public int getSessionId();
+ method public int getSessionType();
+ method public long getUniqueId();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSession> CREATOR;
+ field public static final int TYPE_EPS_BEARER = 1; // 0x1
+ }
+
+ public interface QosSessionAttributes {
+ }
+
+ public final class QosSocketInfo implements android.os.Parcelable {
+ ctor public QosSocketInfo(@NonNull android.net.Network, @NonNull java.net.Socket) throws java.io.IOException;
+ method public int describeContents();
+ method @NonNull public java.net.InetSocketAddress getLocalSocketAddress();
+ method @NonNull public android.net.Network getNetwork();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSocketInfo> CREATOR;
+ }
+
public final class RouteInfo implements android.os.Parcelable {
ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int);
ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int, int);
@@ -7235,6 +7312,12 @@
field public static final int SUCCESS = 0; // 0x0
}
+ public class SocketLocalAddressChangedException extends java.lang.Exception {
+ }
+
+ public class SocketNotBoundException extends java.lang.Exception {
+ }
+
public final class StaticIpConfiguration implements android.os.Parcelable {
ctor public StaticIpConfiguration();
ctor public StaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
@@ -9346,8 +9429,8 @@
public abstract class ImpressionAttestationService extends android.app.Service {
ctor public ImpressionAttestationService();
method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
- method @Nullable public abstract android.service.attestation.ImpressionToken onGenerateImpressionToken(@NonNull String, @NonNull android.hardware.HardwareBuffer, @NonNull android.graphics.Rect, @NonNull String);
- method public abstract boolean onVerifyImpressionToken(@NonNull String, @NonNull android.service.attestation.ImpressionToken);
+ method @Nullable public abstract android.service.attestation.ImpressionToken onGenerateImpressionToken(@NonNull byte[], @NonNull android.hardware.HardwareBuffer, @NonNull android.graphics.Rect, @NonNull String);
+ method public abstract boolean onVerifyImpressionToken(@NonNull byte[], @NonNull android.service.attestation.ImpressionToken);
}
public final class ImpressionToken implements android.os.Parcelable {
@@ -9885,6 +9968,18 @@
}
+package android.service.resumeonreboot {
+
+ public abstract class ResumeOnRebootService extends android.app.Service {
+ ctor public ResumeOnRebootService();
+ method @Nullable public android.os.IBinder onBind(@Nullable android.content.Intent);
+ method @NonNull public abstract byte[] onUnwrap(@NonNull byte[]) throws java.io.IOException;
+ method @NonNull public abstract byte[] onWrap(@NonNull byte[], long) throws java.io.IOException;
+ field public static final String SERVICE_INTERFACE = "android.service.resumeonreboot.ResumeOnRebootService";
+ }
+
+}
+
package android.service.search {
public abstract class SearchUiService extends android.app.Service {
@@ -11831,6 +11926,19 @@
field public static final int RESULT_SUCCESS = 0; // 0x0
}
+ public final class EpsBearerQosSessionAttributes implements android.os.Parcelable android.net.QosSessionAttributes {
+ method @NonNull public static android.telephony.data.EpsBearerQosSessionAttributes create(@NonNull android.os.Parcel);
+ method public int describeContents();
+ method public long getGuaranteedDownlinkBitRate();
+ method public long getGuaranteedUplinkBitRate();
+ method public long getMaxDownlinkBitRate();
+ method public long getMaxUplinkBitRate();
+ method public int getQci();
+ method @NonNull public java.util.List<java.net.InetSocketAddress> getRemoteAddresses();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.EpsBearerQosSessionAttributes> CREATOR;
+ }
+
public abstract class QualifiedNetworksService extends android.app.Service {
ctor public QualifiedNetworksService();
method @NonNull public abstract android.telephony.data.QualifiedNetworksService.NetworkAvailabilityProvider onCreateNetworkAvailabilityProvider(int);
@@ -13383,15 +13491,16 @@
public static class WindowManager.LayoutParams extends android.view.ViewGroup.LayoutParams implements android.os.Parcelable {
method public final long getUserActivityTimeout();
+ method public boolean isSystemApplicationOverlay();
+ method @RequiresPermission(android.Manifest.permission.SYSTEM_APPLICATION_OVERLAY) public void setSystemApplicationOverlay(boolean);
method public final void setUserActivityTimeout(long);
field @RequiresPermission(android.Manifest.permission.USE_BACKGROUND_BLUR) public static final int FLAG_BLUR_BEHIND = 4; // 0x4
field @RequiresPermission(android.Manifest.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS) public static final int SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS = 524288; // 0x80000
field @RequiresPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW) public static final int SYSTEM_FLAG_SHOW_FOR_ALL_USERS = 16; // 0x10
- field @RequiresPermission(android.Manifest.permission.SYSTEM_APPLICATION_OVERLAY) public static final int SYSTEM_FLAG_SYSTEM_APPLICATION_OVERLAY = 8; // 0x8
field @RequiresPermission(android.Manifest.permission.USE_BACKGROUND_BLUR) public int backgroundBlurRadius;
}
- @IntDef(flag=true, prefix={"SYSTEM_FLAG_"}, value={android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS, android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS, android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SYSTEM_APPLICATION_OVERLAY}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface WindowManager.LayoutParams.SystemFlags {
+ @IntDef(flag=true, prefix={"SYSTEM_FLAG_"}, value={android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS, android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface WindowManager.LayoutParams.SystemFlags {
}
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 1f94143..a11ee06 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -377,6 +377,8 @@
package android.app.admin {
public class DevicePolicyManager {
+ method public int checkProvisioningPreCondition(@Nullable String, @NonNull String);
+ method @Nullable public android.os.UserHandle createAndProvisionManagedProfile(@NonNull android.app.admin.ManagedProfileProvisioningParams) throws android.app.admin.ProvisioningException;
method public void forceUpdateUserSetupComplete();
method public long getLastBugReportRequestTime();
method public long getLastNetworkLogRetrievalTime();
@@ -385,8 +387,27 @@
method public boolean isCurrentInputMethodSetByOwner();
method public boolean isFactoryResetProtectionPolicySupported();
method @NonNull public static String operationToString(int);
+ method @RequiresPermission("android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS") public void provisionFullyManagedDevice(@NonNull android.app.admin.FullyManagedDeviceProvisioningParams) throws android.app.admin.ProvisioningException;
method @RequiresPermission("android.permission.MANAGE_DEVICE_ADMINS") public void setNextOperationSafety(int, boolean);
field public static final String ACTION_DATA_SHARING_RESTRICTION_APPLIED = "android.app.action.DATA_SHARING_RESTRICTION_APPLIED";
+ field public static final String ACTION_MANAGED_PROFILE_CREATED = "android.app.action.MANAGED_PROFILE_CREATED";
+ field public static final String ACTION_PROVISIONED_MANAGED_DEVICE = "android.app.action.PROVISIONED_MANAGED_DEVICE";
+ field public static final int CODE_ACCOUNTS_NOT_EMPTY = 6; // 0x6
+ field public static final int CODE_CANNOT_ADD_MANAGED_PROFILE = 11; // 0xb
+ field public static final int CODE_DEVICE_ADMIN_NOT_SUPPORTED = 13; // 0xd
+ field public static final int CODE_HAS_DEVICE_OWNER = 1; // 0x1
+ field public static final int CODE_HAS_PAIRED = 8; // 0x8
+ field public static final int CODE_MANAGED_USERS_NOT_SUPPORTED = 9; // 0x9
+ field public static final int CODE_NONSYSTEM_USER_EXISTS = 5; // 0x5
+ field public static final int CODE_NOT_SYSTEM_USER = 7; // 0x7
+ field public static final int CODE_NOT_SYSTEM_USER_SPLIT = 12; // 0xc
+ field public static final int CODE_OK = 0; // 0x0
+ field public static final int CODE_PROVISIONING_NOT_ALLOWED_FOR_NON_DEVELOPER_USERS = 15; // 0xf
+ field public static final int CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER = 14; // 0xe
+ field public static final int CODE_SYSTEM_USER = 10; // 0xa
+ field public static final int CODE_USER_HAS_PROFILE_OWNER = 2; // 0x2
+ field public static final int CODE_USER_NOT_RUNNING = 3; // 0x3
+ field public static final int CODE_USER_SETUP_COMPLETED = 4; // 0x4
field public static final int OPERATION_CLEAR_APPLICATION_USER_DATA = 23; // 0x17
field public static final int OPERATION_CREATE_AND_MANAGE_USER = 5; // 0x5
field public static final int OPERATION_INSTALL_CA_CERT = 24; // 0x18
@@ -427,6 +448,62 @@
field public static final int OPERATION_SWITCH_USER = 2; // 0x2
field public static final int OPERATION_UNINSTALL_CA_CERT = 40; // 0x28
field public static final int OPERATION_WIPE_DATA = 8; // 0x8
+ field public static final int PROVISIONING_RESULT_ADMIN_PACKAGE_INSTALLATION_FAILED = 3; // 0x3
+ field public static final int PROVISIONING_RESULT_PRE_CONDITION_FAILED = 1; // 0x1
+ field public static final int PROVISIONING_RESULT_PROFILE_CREATION_FAILED = 2; // 0x2
+ field public static final int PROVISIONING_RESULT_REMOVE_NON_REQUIRED_APPS_FAILED = 6; // 0x6
+ field public static final int PROVISIONING_RESULT_SETTING_PROFILE_OWNER_FAILED = 4; // 0x4
+ field public static final int PROVISIONING_RESULT_SET_DEVICE_OWNER_FAILED = 7; // 0x7
+ field public static final int PROVISIONING_RESULT_STARTING_PROFILE_FAILED = 5; // 0x5
+ }
+
+ public final class FullyManagedDeviceProvisioningParams implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.content.ComponentName getDeviceAdminComponentName();
+ method public long getLocalTime();
+ method @Nullable public java.util.Locale getLocale();
+ method @NonNull public String getOwnerName();
+ method @Nullable public String getTimeZone();
+ method public boolean isLeaveAllSystemAppsEnabled();
+ method public void writeToParcel(@NonNull android.os.Parcel, @Nullable int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.FullyManagedDeviceProvisioningParams> CREATOR;
+ }
+
+ public static final class FullyManagedDeviceProvisioningParams.Builder {
+ ctor public FullyManagedDeviceProvisioningParams.Builder(@NonNull android.content.ComponentName, @NonNull String);
+ method @NonNull public android.app.admin.FullyManagedDeviceProvisioningParams build();
+ method @NonNull public android.app.admin.FullyManagedDeviceProvisioningParams.Builder setLeaveAllSystemAppsEnabled(boolean);
+ method @NonNull public android.app.admin.FullyManagedDeviceProvisioningParams.Builder setLocalTime(long);
+ method @NonNull public android.app.admin.FullyManagedDeviceProvisioningParams.Builder setLocale(@Nullable java.util.Locale);
+ method @NonNull public android.app.admin.FullyManagedDeviceProvisioningParams.Builder setTimeZone(@Nullable String);
+ }
+
+ public final class ManagedProfileProvisioningParams implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public android.accounts.Account getAccountToMigrate();
+ method @NonNull public String getOwnerName();
+ method @NonNull public android.content.ComponentName getProfileAdminComponentName();
+ method @Nullable public String getProfileName();
+ method public boolean isKeepAccountMigrated();
+ method public boolean isLeaveAllSystemAppsEnabled();
+ method public boolean isOrganizationOwnedProvisioning();
+ method public void writeToParcel(@NonNull android.os.Parcel, @Nullable int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.ManagedProfileProvisioningParams> CREATOR;
+ }
+
+ public static final class ManagedProfileProvisioningParams.Builder {
+ ctor public ManagedProfileProvisioningParams.Builder(@NonNull android.content.ComponentName, @NonNull String);
+ method @NonNull public android.app.admin.ManagedProfileProvisioningParams build();
+ method @NonNull public android.app.admin.ManagedProfileProvisioningParams.Builder setAccountToMigrate(@Nullable android.accounts.Account);
+ method @NonNull public android.app.admin.ManagedProfileProvisioningParams.Builder setKeepAccountMigrated(boolean);
+ method @NonNull public android.app.admin.ManagedProfileProvisioningParams.Builder setLeaveAllSystemAppsEnabled(boolean);
+ method @NonNull public android.app.admin.ManagedProfileProvisioningParams.Builder setOrganizationOwnedProvisioning(boolean);
+ method @NonNull public android.app.admin.ManagedProfileProvisioningParams.Builder setProfileName(@Nullable String);
+ }
+
+ public class ProvisioningException extends android.util.AndroidException {
+ ctor public ProvisioningException(@NonNull Exception, int);
+ method public int getProvisioningResult();
}
public static final class SecurityLog.SecurityEvent implements android.os.Parcelable {
@@ -1095,6 +1172,11 @@
method public void forceResourceLost();
}
+ public final class MediaCodec implements android.media.metrics.PlaybackComponent {
+ method public String getPlaybackId();
+ method public void setPlaybackId(@NonNull String);
+ }
+
public static final class MediaCodecInfo.VideoCapabilities.PerformancePoint {
ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(int, int, int, int, @NonNull android.util.Size);
ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(@NonNull android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint, @NonNull android.util.Size);
@@ -1103,6 +1185,10 @@
method public int getMaxMacroBlocks();
}
+ public final class MediaDrm implements java.lang.AutoCloseable {
+ method @Nullable public android.media.metrics.PlaybackComponent getPlaybackComponent(@NonNull byte[]);
+ }
+
public final class MediaRoute2Info implements android.os.Parcelable {
method @NonNull public String getOriginalId();
}
@@ -1165,6 +1251,15 @@
}
+package android.media.metrics {
+
+ public interface PlaybackComponent {
+ method @NonNull public String getPlaybackId();
+ method public void setPlaybackId(@NonNull String);
+ }
+
+}
+
package android.media.tv {
public final class TvInputManager {
@@ -1187,10 +1282,6 @@
package android.net {
- public class ConnectivityManager {
- method @RequiresPermission(anyOf={"android.permission.MANAGE_TEST_NETWORKS", android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle);
- }
-
public class EthernetManager {
method public void setIncludeTestInterfaces(boolean);
}
@@ -1199,31 +1290,10 @@
field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
}
- public final class NetworkCapabilities implements android.os.Parcelable {
- method public int[] getCapabilities();
- field public static final int TRANSPORT_TEST = 7; // 0x7
- }
-
public class NetworkStack {
method public static void setServiceForTest(@Nullable android.os.IBinder);
}
- public final class TestNetworkInterface implements android.os.Parcelable {
- ctor public TestNetworkInterface(android.os.ParcelFileDescriptor, String);
- method public int describeContents();
- method public android.os.ParcelFileDescriptor getFileDescriptor();
- method public String getInterfaceName();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.net.TestNetworkInterface> CREATOR;
- }
-
- public class TestNetworkManager {
- method public android.net.TestNetworkInterface createTapInterface();
- method public android.net.TestNetworkInterface createTunInterface(@NonNull android.net.LinkAddress[]);
- method public void setupTestNetwork(@NonNull String, @NonNull android.os.IBinder);
- method public void teardownTestNetwork(@NonNull android.net.Network);
- }
-
public class TrafficStats {
method public static long getLoopbackRxBytes();
method public static long getLoopbackRxPackets();
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index d0d5df9..baf21ed 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -199,6 +199,14 @@
"android.activity.launchTaskDisplayAreaToken";
/**
+ * The root task token the activity should be launched into.
+ * @see #setLaunchRootTask(WindowContainerToken)
+ * @hide
+ */
+ public static final String KEY_LAUNCH_ROOT_TASK_TOKEN =
+ "android.activity.launchRootTaskToken";
+
+ /**
* The windowing mode the activity should be launched into.
* @hide
*/
@@ -306,7 +314,7 @@
* @see #setLaunchCookie
* @hide
*/
- private static final String KEY_LAUNCH_COOKIE = "android.activity.launchCookie";
+ public static final String KEY_LAUNCH_COOKIE = "android.activity.launchCookie";
/** @hide */
public static final int ANIM_UNDEFINED = -1;
@@ -362,6 +370,7 @@
private int mLaunchDisplayId = INVALID_DISPLAY;
private int mCallerDisplayId = INVALID_DISPLAY;
private WindowContainerToken mLaunchTaskDisplayArea;
+ private WindowContainerToken mLaunchRootTask;
@WindowConfiguration.WindowingMode
private int mLaunchWindowingMode = WINDOWING_MODE_UNDEFINED;
@WindowConfiguration.ActivityType
@@ -1050,6 +1059,7 @@
mLaunchDisplayId = opts.getInt(KEY_LAUNCH_DISPLAY_ID, INVALID_DISPLAY);
mCallerDisplayId = opts.getInt(KEY_CALLER_DISPLAY_ID, INVALID_DISPLAY);
mLaunchTaskDisplayArea = opts.getParcelable(KEY_LAUNCH_TASK_DISPLAY_AREA_TOKEN);
+ mLaunchRootTask = opts.getParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN);
mLaunchWindowingMode = opts.getInt(KEY_LAUNCH_WINDOWING_MODE, WINDOWING_MODE_UNDEFINED);
mLaunchActivityType = opts.getInt(KEY_LAUNCH_ACTIVITY_TYPE, ACTIVITY_TYPE_UNDEFINED);
mLaunchTaskId = opts.getInt(KEY_LAUNCH_TASK_ID, -1);
@@ -1342,6 +1352,17 @@
}
/** @hide */
+ public WindowContainerToken getLaunchRootTask() {
+ return mLaunchRootTask;
+ }
+
+ /** @hide */
+ public ActivityOptions setLaunchRootTask(WindowContainerToken windowContainerToken) {
+ mLaunchRootTask = windowContainerToken;
+ return this;
+ }
+
+ /** @hide */
public int getLaunchWindowingMode() {
return mLaunchWindowingMode;
}
@@ -1692,6 +1713,9 @@
if (mLaunchTaskDisplayArea != null) {
b.putParcelable(KEY_LAUNCH_TASK_DISPLAY_AREA_TOKEN, mLaunchTaskDisplayArea);
}
+ if (mLaunchRootTask != null) {
+ b.putParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN, mLaunchRootTask);
+ }
if (mLaunchWindowingMode != WINDOWING_MODE_UNDEFINED) {
b.putInt(KEY_LAUNCH_WINDOWING_MODE, mLaunchWindowingMode);
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index bd437f4..e5c34c5 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -64,12 +64,14 @@
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.pm.ComponentInfo;
import android.content.pm.IPackageManager;
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ParceledListSlice;
+import android.content.pm.PermissionInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ProviderInfoList;
import android.content.pm.ServiceInfo;
@@ -346,6 +348,7 @@
private int mPendingProcessState = PROCESS_STATE_UNKNOWN;
ArrayList<WeakReference<AssistStructure>> mLastAssistStructures = new ArrayList<>();
private int mLastSessionId;
+ final ArrayMap<IBinder, CreateServiceData> mServicesData = new ArrayMap<>();
@UnsupportedAppUsage
final ArrayMap<IBinder, Service> mServices = new ArrayMap<>();
@UnsupportedAppUsage
@@ -3412,7 +3415,7 @@
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
- r.intent.prepareToEnterProcess();
+ r.intent.prepareToEnterProcess(isProtectedComponent(r.activityInfo));
if (r.state != null) {
r.state.setClassLoader(cl);
}
@@ -3717,7 +3720,7 @@
for (int i=0; i<N; i++) {
ReferrerIntent intent = intents.get(i);
intent.setExtrasClassLoader(r.activity.getClassLoader());
- intent.prepareToEnterProcess();
+ intent.prepareToEnterProcess(isProtectedComponent(r.activityInfo));
r.activity.mFragments.noteStateNotSaved();
mInstrumentation.callActivityOnNewIntent(r.activity, intent);
}
@@ -4052,7 +4055,8 @@
}
java.lang.ClassLoader cl = context.getClassLoader();
data.intent.setExtrasClassLoader(cl);
- data.intent.prepareToEnterProcess();
+ data.intent.prepareToEnterProcess(
+ isProtectedComponent(data.info) || isProtectedBroadcast(data.intent));
data.setExtrasClassLoader(cl);
receiver = packageInfo.getAppFactory()
.instantiateReceiver(cl, data.info.name, data.intent);
@@ -4249,6 +4253,7 @@
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
service.onCreate();
+ mServicesData.put(data.token, data);
mServices.put(data.token, service);
try {
ActivityManager.getService().serviceDoneExecuting(
@@ -4266,13 +4271,14 @@
}
private void handleBindService(BindServiceData data) {
+ CreateServiceData createData = mServicesData.get(data.token);
Service s = mServices.get(data.token);
if (DEBUG_SERVICE)
Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind);
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
- data.intent.prepareToEnterProcess();
+ data.intent.prepareToEnterProcess(isProtectedComponent(createData.info));
try {
if (!data.rebind) {
IBinder binder = s.onBind(data.intent);
@@ -4297,11 +4303,12 @@
}
private void handleUnbindService(BindServiceData data) {
+ CreateServiceData createData = mServicesData.get(data.token);
Service s = mServices.get(data.token);
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
- data.intent.prepareToEnterProcess();
+ data.intent.prepareToEnterProcess(isProtectedComponent(createData.info));
boolean doRebind = s.onUnbind(data.intent);
try {
if (doRebind) {
@@ -4373,12 +4380,13 @@
}
private void handleServiceArgs(ServiceArgsData data) {
+ CreateServiceData createData = mServicesData.get(data.token);
Service s = mServices.get(data.token);
if (s != null) {
try {
if (data.args != null) {
data.args.setExtrasClassLoader(s.getClassLoader());
- data.args.prepareToEnterProcess();
+ data.args.prepareToEnterProcess(isProtectedComponent(createData.info));
}
int res;
if (!data.taskRemoved) {
@@ -4407,6 +4415,7 @@
}
private void handleStopService(IBinder token) {
+ mServicesData.remove(token);
Service s = mServices.remove(token);
if (s != null) {
try {
@@ -5026,7 +5035,7 @@
try {
if (ri.mData != null) {
ri.mData.setExtrasClassLoader(r.activity.getClassLoader());
- ri.mData.prepareToEnterProcess();
+ ri.mData.prepareToEnterProcess(isProtectedComponent(r.activityInfo));
}
if (DEBUG_RESULTS) Slog.v(TAG,
"Delivering result to activity " + r + " : " + ri);
@@ -7739,6 +7748,66 @@
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
+ /**
+ * Returns whether the provided {@link ActivityInfo} {@code ai} is a protected component.
+ *
+ * @see #isProtectedComponent(ComponentInfo, String)
+ */
+ public static boolean isProtectedComponent(@NonNull ActivityInfo ai) {
+ return isProtectedComponent(ai, ai.permission);
+ }
+
+ /**
+ * Returns whether the provided {@link ServiceInfo} {@code si} is a protected component.
+ *
+ * @see #isProtectedComponent(ComponentInfo, String)
+ */
+ public static boolean isProtectedComponent(@NonNull ServiceInfo si) {
+ return isProtectedComponent(si, si.permission);
+ }
+
+ /**
+ * Returns whether the provided {@link ComponentInfo} {@code ci} with the specified {@code
+ * permission} is a protected component.
+ *
+ * <p>A component is protected if it is not exported, or if the specified {@code permission} is
+ * a signature permission.
+ */
+ private static boolean isProtectedComponent(@NonNull ComponentInfo ci,
+ @Nullable String permission) {
+ // Bail early when this process isn't looking for violations
+ if (!StrictMode.vmUnsafeIntentLaunchEnabled()) return false;
+
+ // TODO: consider optimizing by having AMS pre-calculate this value
+ if (!ci.exported) {
+ return true;
+ }
+ if (permission != null) {
+ try {
+ PermissionInfo pi = getPermissionManager().getPermissionInfo(permission,
+ currentOpPackageName(), 0);
+ return (pi != null) && pi.getProtection() == PermissionInfo.PROTECTION_SIGNATURE;
+ } catch (RemoteException ignored) {
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns whether the action within the provided {@code intent} is a protected broadcast.
+ */
+ public static boolean isProtectedBroadcast(@NonNull Intent intent) {
+ // Bail early when this process isn't looking for violations
+ if (!StrictMode.vmUnsafeIntentLaunchEnabled()) return false;
+
+ // TODO: consider optimizing by having AMS pre-calculate this value
+ try {
+ return getPackageManager().isProtectedBroadcast(intent.getAction());
+ } catch (RemoteException ignored) {
+ }
+ return false;
+ }
+
// ------------------ Regular JNI ------------------------
private native void nPurgePendingResources();
private native void nDumpGraphicsInfo(FileDescriptor fd);
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 161b731..b85b186 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -7689,8 +7689,8 @@
if (code != OP_RECORD_AUDIO) {
return false;
}
- final String voiceRecognitionComponent = Settings.Secure.getString(
- context.getContentResolver(), Settings.Secure.VOICE_RECOGNITION_SERVICE);
+ final String voiceRecognitionComponent = Settings.Secure.getStringForUser(
+ context.getContentResolver(), Settings.Secure.VOICE_RECOGNITION_SERVICE, userId);
final String voiceRecognitionServicePackageName =
getComponentPackageNameFromString(voiceRecognitionComponent);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index bac5025..4ddeb8f 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1469,6 +1469,45 @@
}
}
+ /**
+ * <p>Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the
+ * Intent you are sending stays around after the broadcast is complete,
+ * so that others can quickly retrieve that data through the return
+ * value of {@link #registerReceiver(BroadcastReceiver, IntentFilter)}. In
+ * all other ways, this behaves the same as
+ * {@link #sendBroadcast(Intent)}.
+ *
+ * @deprecated Sticky broadcasts should not be used. They provide no security (anyone
+ * can access them), no protection (anyone can modify them), and many other problems.
+ * The recommended pattern is to use a non-sticky broadcast to report that <em>something</em>
+ * has changed, with another mechanism for apps to retrieve the current value whenever
+ * desired.
+ *
+ * @param intent The Intent to broadcast; all receivers matching this
+ * Intent will receive the broadcast, and the Intent will be held to
+ * be re-broadcast to future receivers.
+ * @param options (optional) Additional sending options, generated from a
+ * {@link android.app.BroadcastOptions}.
+ *
+ * @see #sendBroadcast(Intent)
+ * @see #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)
+ */
+ @Override
+ @Deprecated
+ public void sendStickyBroadcast(@NonNull Intent intent, @Nullable Bundle options) {
+ warnIfCallingFromSystemProcess();
+ String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+ try {
+ intent.prepareToLeaveProcess(this);
+ ActivityManager.getService().broadcastIntentWithFeature(
+ mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+ null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, options,
+ false, true, getUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
@Override
@Deprecated
public void sendStickyOrderedBroadcast(Intent intent,
@@ -1670,7 +1709,9 @@
flags);
if (intent != null) {
intent.setExtrasClassLoader(getClassLoader());
- intent.prepareToEnterProcess();
+ // TODO: determine at registration time if caller is
+ // protecting themselves with signature permission
+ intent.prepareToEnterProcess(ActivityThread.isProtectedBroadcast(intent));
}
return intent;
} catch (RemoteException e) {
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index e9d63d2..8d1076e 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -139,6 +139,20 @@
}
/**
+ * Returns if it is being called in an instrumentation environment.
+ *
+ * @hide
+ */
+ public boolean isInstrumenting() {
+ // Check if we have an instrumentation context, as init should only get called by
+ // the system in startup processes that are being instrumented.
+ if (mInstrContext == null) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
* Called when the instrumentation is starting, before any application code
* has been loaded. Usually this will be implemented to simply call
* {@link #start} to begin the instrumentation thread, which will then
diff --git a/core/java/android/app/IntentService.java b/core/java/android/app/IntentService.java
index 71b28fb..856c13c 100644
--- a/core/java/android/app/IntentService.java
+++ b/core/java/android/app/IntentService.java
@@ -27,8 +27,9 @@
import android.os.Message;
/**
- * IntentService is a base class for {@link Service}s that handle asynchronous
- * requests (expressed as {@link Intent}s) on demand. Clients send requests
+ * IntentService is an extension of the {@link Service} component class that
+ * handles asynchronous requests (expressed as {@link Intent}s) on demand.
+ * Clients send requests
* through {@link android.content.Context#startService(Intent)} calls; the
* service is started as needed, handles each Intent in turn using a worker
* thread, and stops itself when it runs out of work.
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 50853a3..c01b5a3 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -1617,7 +1617,9 @@
try {
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
- intent.prepareToEnterProcess();
+ // TODO: determine at registration time if caller is
+ // protecting themselves with signature permission
+ intent.prepareToEnterProcess(ActivityThread.isProtectedBroadcast(intent));
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent);
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index 6d79e2d..60bfac5 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -42,8 +42,10 @@
# Multiuser
per-file *User* = file:/MULTIUSER_OWNERS
-# Notification
+# Notification, DND, Status bar
per-file *Notification* = file:/packages/SystemUI/OWNERS
+per-file *Zen* = file:/packages/SystemUI/OWNERS
+per-file *StatusBar* = file:/packages/SystemUI/OWNERS
# ResourcesManager
per-file ResourcesManager = rtmitchell@google.com, toddke@google.com
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 602e9a3..6d75d0f 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -352,9 +352,20 @@
"Cannot set both FLAG_IMMUTABLE and FLAG_MUTABLE for PendingIntent");
}
+ // TODO(b/178092897) Remove the below instrumentation check and enforce
+ // the explicit mutability requirement for apps under instrumentation.
+ ActivityThread thread = ActivityThread.currentActivityThread();
+ Instrumentation mInstrumentation = thread.getInstrumentation();
+
if (Compatibility.isChangeEnabled(PENDING_INTENT_EXPLICIT_MUTABILITY_REQUIRED)
&& !flagImmutableSet && !flagMutableSet) {
- Log.e(TAG, msg);
+
+ //TODO(b/178065720) Remove check for chrome and enforce this requirement
+ if (packageName.equals("com.android.chrome") || mInstrumentation.isInstrumenting()) {
+ Log.e(TAG, msg);
+ } else {
+ throw new IllegalArgumentException(msg);
+ }
}
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 7e8fb91..530cfd5 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -88,6 +88,7 @@
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.Log;
+import android.util.Pair;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.net.NetworkUtilsInternal;
@@ -148,6 +149,7 @@
*/
@SystemService(Context.DEVICE_POLICY_SERVICE)
@RequiresFeature(PackageManager.FEATURE_DEVICE_ADMIN)
+@SuppressLint("UseIcu")
public class DevicePolicyManager {
private static String TAG = "DevicePolicyManager";
@@ -1992,6 +1994,7 @@
*
* @hide
*/
+ @TestApi
public static final int CODE_OK = 0;
/**
@@ -2003,6 +2006,7 @@
*
* @hide
*/
+ @TestApi
public static final int CODE_HAS_DEVICE_OWNER = 1;
/**
@@ -2014,6 +2018,7 @@
*
* @hide
*/
+ @TestApi
public static final int CODE_USER_HAS_PROFILE_OWNER = 2;
/**
@@ -2024,6 +2029,7 @@
*
* @hide
*/
+ @TestApi
public static final int CODE_USER_NOT_RUNNING = 3;
/**
@@ -2035,6 +2041,7 @@
*
* @hide
*/
+ @TestApi
public static final int CODE_USER_SETUP_COMPLETED = 4;
/**
@@ -2042,6 +2049,7 @@
*
* @hide
*/
+ @TestApi
public static final int CODE_NONSYSTEM_USER_EXISTS = 5;
/**
@@ -2049,6 +2057,7 @@
*
* @hide
*/
+ @TestApi
public static final int CODE_ACCOUNTS_NOT_EMPTY = 6;
/**
@@ -2059,6 +2068,7 @@
*
* @hide
*/
+ @TestApi
public static final int CODE_NOT_SYSTEM_USER = 7;
/**
@@ -2070,6 +2080,7 @@
*
* @hide
*/
+ @TestApi
public static final int CODE_HAS_PAIRED = 8;
/**
@@ -2081,6 +2092,7 @@
* @see {@link PackageManager#FEATURE_MANAGED_USERS}
* @hide
*/
+ @TestApi
public static final int CODE_MANAGED_USERS_NOT_SUPPORTED = 9;
/**
@@ -2092,6 +2104,7 @@
*
* @hide
*/
+ @TestApi
public static final int CODE_SYSTEM_USER = 10;
/**
@@ -2102,6 +2115,7 @@
*
* @hide
*/
+ @TestApi
public static final int CODE_CANNOT_ADD_MANAGED_PROFILE = 11;
/**
@@ -2114,6 +2128,7 @@
*
* @hide
*/
+ @TestApi
public static final int CODE_NOT_SYSTEM_USER_SPLIT = 12;
/**
@@ -2121,11 +2136,12 @@
*
* <p>Returned for {@link #ACTION_PROVISION_MANAGED_DEVICE},
* {@link #ACTION_PROVISION_MANAGED_PROFILE}, {@link #ACTION_PROVISION_MANAGED_USER} and
- * {@link #ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE} on devices which do no support device
+ * {@link #ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE} on devices which do not support device
* admins.
*
* @hide
*/
+ @TestApi
public static final int CODE_DEVICE_ADMIN_NOT_SUPPORTED = 13;
/**
@@ -2137,9 +2153,21 @@
*
* @hide
*/
+ @TestApi
public static final int CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER = 14;
/**
+ * Result code for {@link #checkProvisioningPreCondition}.
+ *
+ * <p>Returned for {@link #ACTION_PROVISION_MANAGED_DEVICE} and
+ * {@link #ACTION_PROVISION_MANAGED_PROFILE} on devices which do not support provisioning.
+ *
+ * @hide
+ */
+ @TestApi
+ public static final int CODE_PROVISIONING_NOT_ALLOWED_FOR_NON_DEVELOPER_USERS = 15;
+
+ /**
* Result codes for {@link #checkProvisioningPreCondition} indicating all the provisioning pre
* conditions.
*
@@ -2151,11 +2179,94 @@
CODE_USER_SETUP_COMPLETED, CODE_NOT_SYSTEM_USER, CODE_HAS_PAIRED,
CODE_MANAGED_USERS_NOT_SUPPORTED, CODE_SYSTEM_USER, CODE_CANNOT_ADD_MANAGED_PROFILE,
CODE_NOT_SYSTEM_USER_SPLIT, CODE_DEVICE_ADMIN_NOT_SUPPORTED,
- CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER
+ CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER,
+ CODE_PROVISIONING_NOT_ALLOWED_FOR_NON_DEVELOPER_USERS
})
public @interface ProvisioningPreCondition {}
/**
+ * Service-specific error code for {@link #provisionFullyManagedDevice} and
+ * {@link #createAndProvisionManagedProfile}:
+ * Indicates the call to {@link #checkProvisioningPreCondition} returned an error code.
+ *
+ * @hide
+ */
+ @TestApi
+ public static final int PROVISIONING_RESULT_PRE_CONDITION_FAILED = 1;
+
+ /**
+ * Service-specific error code for {@link #createAndProvisionManagedProfile}:
+ * Indicates the call to {@link UserManager#createProfileForUserEvenWhenDisallowed}
+ * returned {@code null}.
+ *
+ * @hide
+ */
+ @TestApi
+ public static final int PROVISIONING_RESULT_PROFILE_CREATION_FAILED = 2;
+
+ /**
+ * Service-specific error code for {@link #createAndProvisionManagedProfile}:
+ * Indicates the call to {@link PackageManager#installExistingPackageAsUser} has failed.
+ *
+ * @hide
+ */
+ @TestApi
+ public static final int PROVISIONING_RESULT_ADMIN_PACKAGE_INSTALLATION_FAILED = 3;
+
+ /**
+ * Service-specific error code for {@link #createAndProvisionManagedProfile}:
+ * Indicates the call to {@link #setProfileOwner} returned {@code false}.
+ *
+ * @hide
+ */
+ @TestApi
+ public static final int PROVISIONING_RESULT_SETTING_PROFILE_OWNER_FAILED = 4;
+
+ /**
+ * Service-specific error code for {@link #createAndProvisionManagedProfile}:
+ * Indicates that starting the newly created profile has failed.
+ *
+ * @hide
+ */
+ @TestApi
+ public static final int PROVISIONING_RESULT_STARTING_PROFILE_FAILED = 5;
+
+ /**
+ * Service-specific error code for {@link #provisionFullyManagedDevice}:
+ * Indicates that removing the non required apps have failed.
+ *
+ * @hide
+ */
+ @TestApi
+ public static final int PROVISIONING_RESULT_REMOVE_NON_REQUIRED_APPS_FAILED = 6;
+
+ /**
+ * Service-specific error code for {@link #provisionFullyManagedDevice}:
+ * Indicates the call to {@link #setDeviceOwner} returned {@code false}.
+ *
+ * @hide
+ */
+ @TestApi
+ public static final int PROVISIONING_RESULT_SET_DEVICE_OWNER_FAILED = 7;
+
+ /**
+ * Service-specific error codes for {@link #createAndProvisionManagedProfile} and
+ * {@link #provisionFullyManagedDevice} indicating all the errors during provisioning.
+ *
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "PROVISIONING_RESULT_" }, value = {
+ PROVISIONING_RESULT_PRE_CONDITION_FAILED, PROVISIONING_RESULT_PROFILE_CREATION_FAILED,
+ PROVISIONING_RESULT_ADMIN_PACKAGE_INSTALLATION_FAILED,
+ PROVISIONING_RESULT_SETTING_PROFILE_OWNER_FAILED,
+ PROVISIONING_RESULT_STARTING_PROFILE_FAILED,
+ PROVISIONING_RESULT_REMOVE_NON_REQUIRED_APPS_FAILED,
+ PROVISIONING_RESULT_SET_DEVICE_OWNER_FAILED
+ })
+ public @interface ProvisioningResult {}
+
+ /**
* Disable all configurable SystemUI features during LockTask mode. This includes,
* <ul>
* <li>system info area in the status bar (connectivity icons, clock, etc.)
@@ -5215,30 +5326,10 @@
if (!proxySpec.type().equals(Proxy.Type.HTTP)) {
throw new IllegalArgumentException();
}
- InetSocketAddress sa = (InetSocketAddress)proxySpec.address();
- String hostName = sa.getHostName();
- int port = sa.getPort();
- StringBuilder hostBuilder = new StringBuilder();
- hostSpec = hostBuilder.append(hostName)
- .append(":").append(Integer.toString(port)).toString();
- if (exclusionList == null) {
- exclSpec = "";
- } else {
- StringBuilder listBuilder = new StringBuilder();
- boolean firstDomain = true;
- for (String exclDomain : exclusionList) {
- if (!firstDomain) {
- listBuilder = listBuilder.append(",");
- } else {
- firstDomain = false;
- }
- listBuilder = listBuilder.append(exclDomain.trim());
- }
- exclSpec = listBuilder.toString();
- }
- if (android.net.Proxy.validate(hostName, Integer.toString(port), exclSpec)
- != android.net.Proxy.PROXY_VALID)
- throw new IllegalArgumentException();
+ final Pair<String, String> proxyParams =
+ getProxyParameters(proxySpec, exclusionList);
+ hostSpec = proxyParams.first;
+ exclSpec = proxyParams.second;
}
return mService.setGlobalProxy(admin, hostSpec, exclSpec);
} catch (RemoteException e) {
@@ -5249,6 +5340,41 @@
}
/**
+ * Build HTTP proxy parameters for {@link IDevicePolicyManager#setGlobalProxy}.
+ * @throws IllegalArgumentException Invalid proxySpec
+ * @hide
+ */
+ @VisibleForTesting
+ public Pair<String, String> getProxyParameters(Proxy proxySpec, List<String> exclusionList) {
+ InetSocketAddress sa = (InetSocketAddress) proxySpec.address();
+ String hostName = sa.getHostName();
+ int port = sa.getPort();
+ StringBuilder hostBuilder = new StringBuilder();
+ final String hostSpec = hostBuilder.append(hostName)
+ .append(":").append(Integer.toString(port)).toString();
+ final String exclSpec;
+ if (exclusionList == null) {
+ exclSpec = "";
+ } else {
+ StringBuilder listBuilder = new StringBuilder();
+ boolean firstDomain = true;
+ for (String exclDomain : exclusionList) {
+ if (!firstDomain) {
+ listBuilder = listBuilder.append(",");
+ } else {
+ firstDomain = false;
+ }
+ listBuilder = listBuilder.append(exclDomain.trim());
+ }
+ exclSpec = listBuilder.toString();
+ }
+ if (android.net.Proxy.validate(hostName, Integer.toString(port), exclSpec)
+ != android.net.Proxy.PROXY_VALID) throw new IllegalArgumentException();
+
+ return new Pair<>(hostSpec, exclSpec);
+ }
+
+ /**
* Set a network-independent global HTTP proxy. This is not normally what you want for typical
* HTTP proxies - they are generally network dependent. However if you're doing something
* unusual like general internal filtering this may be useful. On a private network where the
@@ -5383,6 +5509,26 @@
"android.app.action.ACTION_SHOW_NEW_USER_DISCLAIMER";
/**
+ * Broadcast action: notify managed provisioning that the device has been provisioned.
+ *
+ * @hide
+ */
+ @TestApi
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_PROVISIONED_MANAGED_DEVICE =
+ "android.app.action.PROVISIONED_MANAGED_DEVICE";
+
+ /**
+ * Broadcast action: notify managed provisioning that a new managed profile is created.
+ *
+ * @hide
+ */
+ @TestApi
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_MANAGED_PROFILE_CREATED =
+ "android.app.action.MANAGED_PROFILE_CREATED";
+
+ /**
* Widgets are enabled in keyguard
*/
public static final int KEYGUARD_DISABLE_FEATURES_NONE = 0;
@@ -10598,8 +10744,9 @@
* @return A {@link ProvisioningPreCondition} value indicating whether provisioning is allowed.
* @hide
*/
+ @TestApi
public @ProvisioningPreCondition int checkProvisioningPreCondition(
- String action, @NonNull String packageName) {
+ @Nullable String action, @NonNull String packageName) {
try {
return mService.checkProvisioningPreCondition(action, packageName);
} catch (RemoteException re) {
@@ -13101,4 +13248,70 @@
throw re.rethrowFromSystemServer();
}
}
+
+ /**
+ * Creates and provisions a managed profile and sets the
+ * {@link ManagedProfileProvisioningParams#getProfileAdminComponentName()} as the profile
+ * owner.
+ *
+ * <p>The method {@link #checkProvisioningPreCondition} must be returning {@link #CODE_OK}
+ * before calling this method.
+ *
+ * @param provisioningParams Params required to provision a managed profile,
+ * see {@link ManagedProfileProvisioningParams}.
+ * @return The {@link UserHandle} of the created profile or {@code null} if the service is
+ * not available.
+ * @throws SecurityException if the caller does not hold
+ * {@link android.Manifest.permission#MANAGE_PROFILE_AND_DEVICE_OWNERS}.
+ * @throws ProvisioningException if an error occurred during provisioning.
+ * @hide
+ */
+ @Nullable
+ @TestApi
+ public UserHandle createAndProvisionManagedProfile(
+ @NonNull ManagedProfileProvisioningParams provisioningParams)
+ throws ProvisioningException {
+ if (mService == null) {
+ return null;
+ }
+ try {
+ return mService.createAndProvisionManagedProfile(provisioningParams);
+ } catch (ServiceSpecificException e) {
+ throw new ProvisioningException(e, e.errorCode);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Provisions a managed device and sets the {@code deviceAdminComponentName} as the device
+ * owner.
+ *
+ * <p>The method {@link #checkProvisioningPreCondition} must be returning {@link #CODE_OK}
+ * before calling this method.
+ *
+ * @param provisioningParams Params required to provision a fully managed device,
+ * see {@link FullyManagedDeviceProvisioningParams}.
+ *
+ * @throws SecurityException if the caller does not hold
+ * {@link android.Manifest.permission#MANAGE_PROFILE_AND_DEVICE_OWNERS}.
+ * @throws ProvisioningException if an error occurred during provisioning.
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+ public void provisionFullyManagedDevice(
+ @NonNull FullyManagedDeviceProvisioningParams provisioningParams)
+ throws ProvisioningException {
+ if (mService != null) {
+ try {
+ mService.provisionFullyManagedDevice(provisioningParams);
+ } catch (ServiceSpecificException e) {
+ throw new ProvisioningException(e, e.errorCode);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+ }
}
diff --git a/core/java/android/app/admin/FullyManagedDeviceProvisioningParams.aidl b/core/java/android/app/admin/FullyManagedDeviceProvisioningParams.aidl
new file mode 100644
index 0000000..8a9cbba
--- /dev/null
+++ b/core/java/android/app/admin/FullyManagedDeviceProvisioningParams.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.admin;
+
+parcelable FullyManagedDeviceProvisioningParams;
diff --git a/core/java/android/app/admin/FullyManagedDeviceProvisioningParams.java b/core/java/android/app/admin/FullyManagedDeviceProvisioningParams.java
new file mode 100644
index 0000000..83af019
--- /dev/null
+++ b/core/java/android/app/admin/FullyManagedDeviceProvisioningParams.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.admin;
+
+import static java.util.Objects.requireNonNull;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.TestApi;
+import android.content.ComponentName;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Locale;
+
+/**
+ * Params required to provision a fully managed device, see
+ * {@link DevicePolicyManager#provisionFullyManagedDevice}.
+ * @hide
+ */
+@TestApi
+public final class FullyManagedDeviceProvisioningParams implements Parcelable {
+ @NonNull private final ComponentName mDeviceAdminComponentName;
+ @NonNull private final String mOwnerName;
+ private final boolean mLeaveAllSystemAppsEnabled;
+ @Nullable private final String mTimeZone;
+ private final long mLocalTime;
+ @SuppressLint("UseIcu")
+ @Nullable private final Locale mLocale;
+
+ private FullyManagedDeviceProvisioningParams(
+ @NonNull ComponentName deviceAdminComponentName,
+ @NonNull String ownerName,
+ boolean leaveAllSystemAppsEnabled,
+ @Nullable String timeZone,
+ long localTime,
+ @Nullable @SuppressLint("UseIcu") Locale locale) {
+ this.mDeviceAdminComponentName = requireNonNull(deviceAdminComponentName);
+ this.mOwnerName = requireNonNull(ownerName);
+ this.mLeaveAllSystemAppsEnabled = leaveAllSystemAppsEnabled;
+ this.mTimeZone = timeZone;
+ this.mLocalTime = localTime;
+ this.mLocale = locale;
+ }
+
+ private FullyManagedDeviceProvisioningParams(
+ @NonNull ComponentName deviceAdminComponentName,
+ @NonNull String ownerName,
+ boolean leaveAllSystemAppsEnabled,
+ @Nullable String timeZone,
+ long localTime,
+ @Nullable String localeStr) {
+ this(deviceAdminComponentName,
+ ownerName,
+ leaveAllSystemAppsEnabled,
+ timeZone,
+ localTime,
+ getLocale(localeStr));
+ }
+
+ @Nullable
+ private static Locale getLocale(String localeStr) {
+ return localeStr == null ? null : Locale.forLanguageTag(localeStr);
+ }
+
+ @NonNull
+ public ComponentName getDeviceAdminComponentName() {
+ return mDeviceAdminComponentName;
+ }
+
+ @NonNull
+ public String getOwnerName() {
+ return mOwnerName;
+ }
+
+ public boolean isLeaveAllSystemAppsEnabled() {
+ return mLeaveAllSystemAppsEnabled;
+ }
+
+ @Nullable
+ public String getTimeZone() {
+ return mTimeZone;
+ }
+
+ public long getLocalTime() {
+ return mLocalTime;
+ }
+
+ @Nullable
+ public @SuppressLint("UseIcu") Locale getLocale() {
+ return mLocale;
+ }
+
+ /**
+ * Builder class for {@link FullyManagedDeviceProvisioningParams} objects.
+ */
+ public static final class Builder {
+ @NonNull private final ComponentName mDeviceAdminComponentName;
+ @NonNull private final String mOwnerName;
+ private boolean mLeaveAllSystemAppsEnabled;
+ @Nullable private String mTimeZone;
+ private long mLocalTime;
+ @SuppressLint("UseIcu")
+ @Nullable private Locale mLocale;
+
+ /**
+ * Initialize a new {@link Builder} to construct a
+ * {@link FullyManagedDeviceProvisioningParams}.
+ * <p>
+ * See {@link DevicePolicyManager#provisionFullyManagedDevice}
+ *
+ * @param deviceAdminComponentName The admin {@link ComponentName} to be set as the device
+ * owner.
+ * @param ownerName The name of the device owner.
+ *
+ * @throws NullPointerException if {@code deviceAdminComponentName} or
+ * {@code ownerName} are null.
+ */
+ public Builder(
+ @NonNull ComponentName deviceAdminComponentName, @NonNull String ownerName) {
+ this.mDeviceAdminComponentName = requireNonNull(deviceAdminComponentName);
+ this.mOwnerName = requireNonNull(ownerName);
+ }
+
+ /**
+ * Sets whether non-required system apps should be installed on
+ * the created profile when
+ * {@link DevicePolicyManager#provisionFullyManagedDevice}
+ * is called. Defaults to {@code false} if not set.
+ */
+ @NonNull
+ public Builder setLeaveAllSystemAppsEnabled(boolean leaveAllSystemAppsEnabled) {
+ this.mLeaveAllSystemAppsEnabled = leaveAllSystemAppsEnabled;
+ return this;
+ }
+
+ /**
+ * Sets {@code timeZone} on the device. If not set or set to {@code null},
+ * {@link DevicePolicyManager#provisionFullyManagedDevice} will not set a timezone
+ */
+ @NonNull
+ public Builder setTimeZone(@Nullable String timeZone) {
+ this.mTimeZone = timeZone;
+ return this;
+ }
+
+ /**
+ * Sets {@code localTime} on the device, If not set or set to
+ * {@code 0}, {@link DevicePolicyManager#provisionFullyManagedDevice} will not set a
+ * local time.
+ */
+ @NonNull
+ public Builder setLocalTime(long localTime) {
+ this.mLocalTime = localTime;
+ return this;
+ }
+
+ /**
+ * Sets {@link Locale} on the device, If not set or set to {@code null},
+ * {@link DevicePolicyManager#provisionFullyManagedDevice} will not set a locale.
+ */
+ @NonNull
+ public Builder setLocale(@SuppressLint("UseIcu") @Nullable Locale locale) {
+ this.mLocale = locale;
+ return this;
+ }
+
+ /**
+ * Combines all of the attributes that have been set on this {@code Builder}
+ *
+ * @return a new {@link FullyManagedDeviceProvisioningParams} object.
+ */
+ @NonNull
+ public FullyManagedDeviceProvisioningParams build() {
+ return new FullyManagedDeviceProvisioningParams(
+ mDeviceAdminComponentName,
+ mOwnerName,
+ mLeaveAllSystemAppsEnabled,
+ mTimeZone,
+ mLocalTime,
+ mLocale);
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return "FullyManagedDeviceProvisioningParams{"
+ + "mDeviceAdminComponentName=" + mDeviceAdminComponentName
+ + ", mOwnerName=" + mOwnerName
+ + ", mLeaveAllSystemAppsEnabled=" + mLeaveAllSystemAppsEnabled
+ + ", mTimeZone=" + (mTimeZone == null ? "null" : mTimeZone)
+ + ", mLocalTime=" + mLocalTime
+ + ", mLocale=" + (mLocale == null ? "null" : mLocale)
+ + '}';
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, @Nullable int flags) {
+ dest.writeTypedObject(mDeviceAdminComponentName, flags);
+ dest.writeString(mOwnerName);
+ dest.writeBoolean(mLeaveAllSystemAppsEnabled);
+ dest.writeString(mTimeZone);
+ dest.writeLong(mLocalTime);
+ dest.writeString(mLocale == null ? null : mLocale.toLanguageTag());
+ }
+
+ @NonNull
+ public static final Creator<FullyManagedDeviceProvisioningParams> CREATOR =
+ new Creator<FullyManagedDeviceProvisioningParams>() {
+ @Override
+ public FullyManagedDeviceProvisioningParams createFromParcel(Parcel in) {
+ ComponentName componentName = in.readTypedObject(ComponentName.CREATOR);
+ String ownerName = in.readString();
+ boolean leaveAllSystemAppsEnabled = in.readBoolean();
+ String timeZone = in.readString();
+ long localtime = in.readLong();
+ String locale = in.readString();
+
+ return new FullyManagedDeviceProvisioningParams(
+ componentName,
+ ownerName,
+ leaveAllSystemAppsEnabled,
+ timeZone,
+ localtime,
+ locale);
+ }
+
+ @Override
+ public FullyManagedDeviceProvisioningParams[] newArray(int size) {
+ return new FullyManagedDeviceProvisioningParams[size];
+ }
+ };
+}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 8f84bfe..3765a67 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -25,6 +25,8 @@
import android.app.admin.SystemUpdatePolicy;
import android.app.admin.PasswordMetrics;
import android.app.admin.FactoryResetProtectionPolicy;
+import android.app.admin.ManagedProfileProvisioningParams;
+import android.app.admin.FullyManagedDeviceProvisioningParams;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
@@ -493,4 +495,7 @@
String getEnrollmentSpecificId(String callerPackage);
void setOrganizationIdForUser(in String callerPackage, in String enterpriseId, int userId);
+
+ UserHandle createAndProvisionManagedProfile(in ManagedProfileProvisioningParams provisioningParams);
+ void provisionFullyManagedDevice(in FullyManagedDeviceProvisioningParams provisioningParams);
}
diff --git a/core/java/android/app/admin/ManagedProfileProvisioningParams.aidl b/core/java/android/app/admin/ManagedProfileProvisioningParams.aidl
new file mode 100644
index 0000000..a6fae91
--- /dev/null
+++ b/core/java/android/app/admin/ManagedProfileProvisioningParams.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.admin;
+
+parcelable ManagedProfileProvisioningParams;
diff --git a/core/java/android/app/admin/ManagedProfileProvisioningParams.java b/core/java/android/app/admin/ManagedProfileProvisioningParams.java
new file mode 100644
index 0000000..5fe63d1
--- /dev/null
+++ b/core/java/android/app/admin/ManagedProfileProvisioningParams.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.admin;
+
+import static java.util.Objects.requireNonNull;
+
+import android.accounts.Account;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.TestApi;
+import android.content.ComponentName;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Params required to provision a managed profile, see
+ * {@link DevicePolicyManager#createAndProvisionManagedProfile}.
+ *
+ * @hide
+ */
+@TestApi
+public final class ManagedProfileProvisioningParams implements Parcelable {
+ @NonNull private final ComponentName mProfileAdminComponentName;
+ @NonNull private final String mOwnerName;
+ @Nullable private final String mProfileName;
+ @Nullable private final Account mAccountToMigrate;
+ private final boolean mLeaveAllSystemAppsEnabled;
+ private final boolean mOrganizationOwnedProvisioning;
+ private final boolean mKeepAccountMigrated;
+
+
+ private ManagedProfileProvisioningParams(
+ @NonNull ComponentName profileAdminComponentName,
+ @NonNull String ownerName,
+ @Nullable String profileName,
+ @Nullable Account accountToMigrate,
+ boolean leaveAllSystemAppsEnabled,
+ boolean organizationOwnedProvisioning,
+ boolean keepAccountMigrated) {
+ this.mProfileAdminComponentName = requireNonNull(profileAdminComponentName);
+ this.mOwnerName = requireNonNull(ownerName);
+ this.mProfileName = profileName;
+ this.mAccountToMigrate = accountToMigrate;
+ this.mLeaveAllSystemAppsEnabled = leaveAllSystemAppsEnabled;
+ this.mOrganizationOwnedProvisioning = organizationOwnedProvisioning;
+ this.mKeepAccountMigrated = keepAccountMigrated;
+ }
+
+ @NonNull
+ public ComponentName getProfileAdminComponentName() {
+ return mProfileAdminComponentName;
+ }
+
+ @NonNull
+ public String getOwnerName() {
+ return mOwnerName;
+ }
+
+ @Nullable
+ public String getProfileName() {
+ return mProfileName;
+ }
+
+ @Nullable
+ public Account getAccountToMigrate() {
+ return mAccountToMigrate;
+ }
+
+ public boolean isLeaveAllSystemAppsEnabled() {
+ return mLeaveAllSystemAppsEnabled;
+ }
+
+ public boolean isOrganizationOwnedProvisioning() {
+ return mOrganizationOwnedProvisioning;
+ }
+
+ public boolean isKeepAccountMigrated() {
+ return mKeepAccountMigrated;
+ }
+
+ /**
+ * Builder class for {@link ManagedProfileProvisioningParams} objects.
+ */
+ public static final class Builder {
+ @NonNull private final ComponentName mProfileAdminComponentName;
+ @NonNull private final String mOwnerName;
+ @Nullable private String mProfileName;
+ @Nullable private Account mAccountToMigrate;
+ private boolean mLeaveAllSystemAppsEnabled;
+ private boolean mOrganizationOwnedProvisioning;
+ private boolean mKeepAccountMigrated;
+
+ /**
+ * Initialize a new {@link Builder) to construct a {@link ManagedProfileProvisioningParams}.
+ * <p>
+ * See {@link DevicePolicyManager#createAndProvisionManagedProfile}
+ *
+ * @param profileAdminComponentName The admin {@link ComponentName} to be set as the profile
+ * owner.
+ * @param ownerName The name of the profile owner.
+ *
+ * @throws NullPointerException if {@code profileAdminComponentName} or
+ * {@code ownerName} are null.
+ */
+ public Builder(
+ @NonNull ComponentName profileAdminComponentName, @NonNull String ownerName) {
+ requireNonNull(profileAdminComponentName);
+ requireNonNull(ownerName);
+ this.mProfileAdminComponentName = profileAdminComponentName;
+ this.mOwnerName = ownerName;
+ }
+
+ /**
+ * Sets the profile name of the created profile when
+ * {@link DevicePolicyManager#createAndProvisionManagedProfile} is called. Defaults to
+ * {@code null} if not set.
+ */
+ @NonNull
+ public Builder setProfileName(@Nullable String profileName) {
+ this.mProfileName = profileName;
+ return this;
+ }
+
+ /**
+ * Sets the {@link Account} to migrate from the parent profile to the created profile when
+ * {@link DevicePolicyManager#createAndProvisionManagedProfile} is called. If not set, or
+ * set to {@code null}, no accounts will be migrated.
+ */
+ @NonNull
+ public Builder setAccountToMigrate(@Nullable Account accountToMigrate) {
+ this.mAccountToMigrate = accountToMigrate;
+ return this;
+ }
+
+ /**
+ * Sets whether non-required system apps should be installed on
+ * the created profile when {@link DevicePolicyManager#createAndProvisionManagedProfile}
+ * is called. Defaults to {@code false} if not set.
+ */
+ @NonNull
+ public Builder setLeaveAllSystemAppsEnabled(boolean leaveAllSystemAppsEnabled) {
+ this.mLeaveAllSystemAppsEnabled = leaveAllSystemAppsEnabled;
+ return this;
+ }
+
+ /**
+ * Sets if this device is owned by an organization. Defaults to {@code false}
+ * if not set.
+ */
+ @NonNull
+ public Builder setOrganizationOwnedProvisioning(boolean organizationOwnedProvisioning) {
+ this.mOrganizationOwnedProvisioning = organizationOwnedProvisioning;
+ return this;
+ }
+
+ /**
+ * Sets whether to keep the account on the parent profile during account migration.
+ * Defaults to {@code false}.
+ */
+ @NonNull
+ public Builder setKeepAccountMigrated(boolean keepAccountMigrated) {
+ this.mKeepAccountMigrated = keepAccountMigrated;
+ return this;
+ }
+
+ /**
+ * Combines all of the attributes that have been set on this {@code Builder}.
+ *
+ * @return a new {@link ManagedProfileProvisioningParams} object.
+ */
+ @NonNull
+ public ManagedProfileProvisioningParams build() {
+ return new ManagedProfileProvisioningParams(
+ mProfileAdminComponentName,
+ mOwnerName,
+ mProfileName,
+ mAccountToMigrate,
+ mLeaveAllSystemAppsEnabled,
+ mOrganizationOwnedProvisioning,
+ mKeepAccountMigrated);
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return "ManagedProfileProvisioningParams{"
+ + "mProfileAdminComponentName=" + mProfileAdminComponentName
+ + ", mOwnerName=" + mOwnerName
+ + ", mProfileName=" + (mProfileName == null ? "null" : mProfileName)
+ + ", mAccountToMigrate=" + (mAccountToMigrate == null ? "null" : mAccountToMigrate)
+ + ", mLeaveAllSystemAppsEnabled=" + mLeaveAllSystemAppsEnabled
+ + ", mOrganizationOwnedProvisioning=" + mOrganizationOwnedProvisioning
+ + ", mKeepAccountMigrated=" + mKeepAccountMigrated
+ + '}';
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, @Nullable int flags) {
+ dest.writeTypedObject(mProfileAdminComponentName, flags);
+ dest.writeString(mOwnerName);
+ dest.writeString(mProfileName);
+ dest.writeTypedObject(mAccountToMigrate, flags);
+ dest.writeBoolean(mLeaveAllSystemAppsEnabled);
+ dest.writeBoolean(mOrganizationOwnedProvisioning);
+ dest.writeBoolean(mKeepAccountMigrated);
+ }
+
+ public static final @NonNull Creator<ManagedProfileProvisioningParams> CREATOR =
+ new Creator<ManagedProfileProvisioningParams>() {
+ @Override
+ public ManagedProfileProvisioningParams createFromParcel(Parcel in) {
+ ComponentName componentName = in.readTypedObject(ComponentName.CREATOR);
+ String ownerName = in.readString();
+ String profileName = in.readString();
+ Account account = in.readTypedObject(Account.CREATOR);
+ boolean leaveAllSystemAppsEnabled = in.readBoolean();
+ boolean organizationOwnedProvisioning = in.readBoolean();
+ boolean keepAccountMigrated = in.readBoolean();
+
+ return new ManagedProfileProvisioningParams(
+ componentName,
+ ownerName,
+ profileName,
+ account,
+ leaveAllSystemAppsEnabled,
+ organizationOwnedProvisioning,
+ keepAccountMigrated);
+ }
+
+ @Override
+ public ManagedProfileProvisioningParams[] newArray(int size) {
+ return new ManagedProfileProvisioningParams[size];
+ }
+ };
+}
diff --git a/core/java/android/app/admin/ProvisioningException.java b/core/java/android/app/admin/ProvisioningException.java
new file mode 100644
index 0000000..639859b
--- /dev/null
+++ b/core/java/android/app/admin/ProvisioningException.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.admin;
+import android.annotation.NonNull;
+import android.annotation.TestApi;
+import android.util.AndroidException;
+
+/**
+ * Thrown to indicate a failure during {@link DevicePolicyManager#provisionFullyManagedDevice} and
+ * {@link DevicePolicyManager#createAndProvisionManagedProfile}.
+ *
+ * @hide
+ *
+ */
+@TestApi
+public class ProvisioningException extends AndroidException {
+ private final @DevicePolicyManager.ProvisioningResult int mProvisioningResult;
+
+ public ProvisioningException(@NonNull Exception cause,
+ @DevicePolicyManager.ProvisioningResult int provisioningResult) {
+ super(cause);
+ mProvisioningResult = provisioningResult;
+ }
+
+ public @DevicePolicyManager.ProvisioningResult int getProvisioningResult() {
+ return mProvisioningResult;
+ }
+}
diff --git a/core/java/android/appwidget/OWNERS b/core/java/android/appwidget/OWNERS
new file mode 100644
index 0000000..439df4b
--- /dev/null
+++ b/core/java/android/appwidget/OWNERS
@@ -0,0 +1,3 @@
+pinyaoting@google.com
+suprabh@google.com
+sunnygoyal@google.com
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 15daf1c..cd91aa9 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -225,6 +225,39 @@
@SystemApi
public static final int OPTIONAL_CODECS_PREF_ENABLED = 1;
+ /** @hide */
+ @IntDef(prefix = "DYNAMIC_BUFFER_SUPPORT_", value = {
+ DYNAMIC_BUFFER_SUPPORT_NONE,
+ DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD,
+ DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Type {}
+
+ /**
+ * Indicates the supported type of Dynamic Audio Buffer is not supported.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int DYNAMIC_BUFFER_SUPPORT_NONE = 0;
+
+ /**
+ * Indicates the supported type of Dynamic Audio Buffer is A2DP offload.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD = 1;
+
+ /**
+ * Indicates the supported type of Dynamic Audio Buffer is A2DP software encoding.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING = 2;
+
private BluetoothAdapter mAdapter;
private final BluetoothProfileConnector<IBluetoothA2dp> mProfileConnector =
new BluetoothProfileConnector(this, BluetoothProfile.A2DP, "BluetoothA2dp",
@@ -845,6 +878,87 @@
}
/**
+ * Get the supported type of the Dynamic Audio Buffer.
+ * <p>Possible return values are
+ * {@link #DYNAMIC_BUFFER_SUPPORT_NONE},
+ * {@link #DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD},
+ * {@link #DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING}.
+ *
+ * @return supported type of Dynamic Audio Buffer feature
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public @Type int getDynamicBufferSupport() {
+ if (VDBG) log("getDynamicBufferSupport()");
+ try {
+ final IBluetoothA2dp service = getService();
+ if (service != null && isEnabled()) {
+ return service.getDynamicBufferSupport();
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return DYNAMIC_BUFFER_SUPPORT_NONE;
+ } catch (RemoteException e) {
+ Log.e(TAG, "failed to get getDynamicBufferSupport, error: ", e);
+ return DYNAMIC_BUFFER_SUPPORT_NONE;
+ }
+ }
+
+ /**
+ * Return the record of {@link BufferConstraints} object that
+ * has the default/maximum/minimum audio buffer. This can be used to inform what the controller
+ * has support for the audio buffer.
+ *
+ * @return a record with {@link BufferConstraints} or null if report is unavailable
+ * or unsupported
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public @Nullable BufferConstraints getBufferConstraints() {
+ if (VDBG) log("getBufferConstraints()");
+ try {
+ final IBluetoothA2dp service = getService();
+ if (service != null && isEnabled()) {
+ return service.getBufferConstraints();
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return null;
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ return null;
+ }
+ }
+
+ /**
+ * Set Dynamic Audio Buffer Size.
+ *
+ * @param codec audio codec
+ * @param value buffer millis
+ * @return true to indicate success, or false on immediate error
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public boolean setBufferMillis(@BluetoothCodecConfig.SourceCodecType int codec, int value) {
+ if (VDBG) log("setBufferMillis(" + codec + ", " + value + ")");
+ try {
+ final IBluetoothA2dp service = getService();
+ if (service != null && isEnabled()) {
+ return service.setBufferMillis(codec, value);
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ return false;
+ }
+ }
+
+ /**
* Helper for converting a state to a string.
*
* For debug use only - strings are not internationalized.
diff --git a/core/java/android/bluetooth/BufferConstraint.java b/core/java/android/bluetooth/BufferConstraint.java
new file mode 100644
index 0000000..cbffc78
--- /dev/null
+++ b/core/java/android/bluetooth/BufferConstraint.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Stores a codec's constraints on buffering length in milliseconds.
+ *
+ * {@hide}
+ */
+@SystemApi
+public final class BufferConstraint implements Parcelable {
+
+ private static final String TAG = "BufferConstraint";
+ private int mDefaultMillis;
+ private int mMaxMillis;
+ private int mMinMillis;
+
+ public BufferConstraint(int defaultMillis, int maxMillis,
+ int minMillis) {
+ mDefaultMillis = defaultMillis;
+ mMaxMillis = maxMillis;
+ mMinMillis = minMillis;
+ }
+
+ BufferConstraint(Parcel in) {
+ mDefaultMillis = in.readInt();
+ mMaxMillis = in.readInt();
+ mMinMillis = in.readInt();
+ }
+
+ public static final @NonNull Parcelable.Creator<BufferConstraint> CREATOR =
+ new Parcelable.Creator<BufferConstraint>() {
+ public BufferConstraint createFromParcel(Parcel in) {
+ return new BufferConstraint(in);
+ }
+
+ public BufferConstraint[] newArray(int size) {
+ return new BufferConstraint[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeInt(mDefaultMillis);
+ out.writeInt(mMaxMillis);
+ out.writeInt(mMinMillis);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Get the default buffer millis
+ *
+ * @return default buffer millis
+ * @hide
+ */
+ @SystemApi
+ public int getDefaultMillis() {
+ return mDefaultMillis;
+ }
+
+ /**
+ * Get the maximum buffer millis
+ *
+ * @return maximum buffer millis
+ * @hide
+ */
+ @SystemApi
+ public int getMaxMillis() {
+ return mMaxMillis;
+ }
+
+ /**
+ * Get the minimum buffer millis
+ *
+ * @return minimum buffer millis
+ * @hide
+ */
+ @SystemApi
+ public int getMinMillis() {
+ return mMinMillis;
+ }
+}
diff --git a/core/java/android/bluetooth/BufferConstraints.java b/core/java/android/bluetooth/BufferConstraints.java
new file mode 100644
index 0000000..7e5ec1e
--- /dev/null
+++ b/core/java/android/bluetooth/BufferConstraints.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * A parcelable collection of buffer constraints by codec type.
+ *
+ * {@hide}
+ */
+@SystemApi
+public final class BufferConstraints implements Parcelable {
+ public static final int BUFFER_CODEC_MAX_NUM = 32;
+
+ private static final String TAG = "BufferConstraints";
+
+ private Map<Integer, BufferConstraint> mBufferConstraints;
+ private List<BufferConstraint> mBufferConstraintList;
+
+ public BufferConstraints(@NonNull List<BufferConstraint>
+ bufferConstraintList) {
+
+ mBufferConstraintList = new ArrayList<BufferConstraint>(bufferConstraintList);
+ mBufferConstraints = new HashMap<Integer, BufferConstraint>();
+ for (int i = 0; i < BUFFER_CODEC_MAX_NUM; i++) {
+ mBufferConstraints.put(i, bufferConstraintList.get(i));
+ }
+ }
+
+ BufferConstraints(Parcel in) {
+ mBufferConstraintList = new ArrayList<BufferConstraint>();
+ mBufferConstraints = new HashMap<Integer, BufferConstraint>();
+ in.readList(mBufferConstraintList, BufferConstraint.class.getClassLoader());
+ for (int i = 0; i < mBufferConstraintList.size(); i++) {
+ mBufferConstraints.put(i, mBufferConstraintList.get(i));
+ }
+ }
+
+ public static final @NonNull Parcelable.Creator<BufferConstraints> CREATOR =
+ new Parcelable.Creator<BufferConstraints>() {
+ public BufferConstraints createFromParcel(Parcel in) {
+ return new BufferConstraints(in);
+ }
+
+ public BufferConstraints[] newArray(int size) {
+ return new BufferConstraints[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeList(mBufferConstraintList);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Get the buffer constraints by codec type.
+ *
+ * @param codec Audio codec
+ * @return buffer constraints by codec type.
+ * @hide
+ */
+ @SystemApi
+ public @Nullable BufferConstraint getCodec(@BluetoothCodecConfig.SourceCodecType int codec) {
+ return mBufferConstraints.get(codec);
+ }
+}
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index c4d9867..0188637 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -1008,7 +1008,9 @@
for (int i = 0; i < size; i++) {
final Item item = mItems.get(i);
if (item.mIntent != null) {
- item.mIntent.prepareToEnterProcess();
+ // We can't recursively claim that this data is from a protected
+ // component, since it may have been filled in by a malicious app
+ item.mIntent.prepareToEnterProcess(false);
}
}
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 2190140..e4a81cf 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2625,6 +2625,36 @@
public abstract void sendStickyBroadcast(@RequiresPermission Intent intent);
/**
+ * <p>Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the
+ * Intent you are sending stays around after the broadcast is complete,
+ * so that others can quickly retrieve that data through the return
+ * value of {@link #registerReceiver(BroadcastReceiver, IntentFilter)}. In
+ * all other ways, this behaves the same as
+ * {@link #sendBroadcast(Intent)}.
+ *
+ * @deprecated Sticky broadcasts should not be used. They provide no security (anyone
+ * can access them), no protection (anyone can modify them), and many other problems.
+ * The recommended pattern is to use a non-sticky broadcast to report that <em>something</em>
+ * has changed, with another mechanism for apps to retrieve the current value whenever
+ * desired.
+ *
+ * @param intent The Intent to broadcast; all receivers matching this
+ * Intent will receive the broadcast, and the Intent will be held to
+ * be re-broadcast to future receivers.
+ * @param options (optional) Additional sending options, generated from a
+ * {@link android.app.BroadcastOptions}.
+ *
+ * @see #sendBroadcast(Intent)
+ * @see #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)
+ */
+ @Deprecated
+ @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY)
+ public void sendStickyBroadcast(@RequiresPermission @NonNull Intent intent,
+ @Nullable Bundle options) {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
+
+ /**
* <p>Version of {@link #sendStickyBroadcast} that allows you to
* receive data back from the broadcast. This is accomplished by
* supplying your own BroadcastReceiver when calling, which will be
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 078fa0d..c1c213e 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -624,6 +624,35 @@
mBase.sendStickyBroadcast(intent);
}
+ /**
+ * <p>Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the
+ * Intent you are sending stays around after the broadcast is complete,
+ * so that others can quickly retrieve that data through the return
+ * value of {@link #registerReceiver(BroadcastReceiver, IntentFilter)}. In
+ * all other ways, this behaves the same as
+ * {@link #sendBroadcast(Intent)}.
+ *
+ * @deprecated Sticky broadcasts should not be used. They provide no security (anyone
+ * can access them), no protection (anyone can modify them), and many other problems.
+ * The recommended pattern is to use a non-sticky broadcast to report that <em>something</em>
+ * has changed, with another mechanism for apps to retrieve the current value whenever
+ * desired.
+ *
+ * @param intent The Intent to broadcast; all receivers matching this
+ * Intent will receive the broadcast, and the Intent will be held to
+ * be re-broadcast to future receivers.
+ * @param options (optional) Additional sending options, generated from a
+ * {@link android.app.BroadcastOptions}.
+ *
+ * @see #sendBroadcast(Intent)
+ * @see #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)
+ */
+ @Override
+ @Deprecated
+ public void sendStickyBroadcast(@NonNull Intent intent, @Nullable Bundle options) {
+ mBase.sendStickyBroadcast(intent, options);
+ }
+
@Override
@Deprecated
public void sendStickyOrderedBroadcast(Intent intent,
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 7843d97..1752b48 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -6681,6 +6681,25 @@
| FLAG_GRANT_WRITE_URI_PERMISSION | FLAG_GRANT_PERSISTABLE_URI_PERMISSION
| FLAG_GRANT_PREFIX_URI_PERMISSION;
+ /**
+ * Local flag indicating this instance was created by copy constructor.
+ */
+ private static final int LOCAL_FLAG_FROM_COPY = 1 << 0;
+
+ /**
+ * Local flag indicating this instance was created from a {@link Parcel}.
+ */
+ private static final int LOCAL_FLAG_FROM_PARCEL = 1 << 1;
+
+ /**
+ * Local flag indicating this instance was delivered through a protected
+ * component, such as an activity that requires a signature permission, or a
+ * protected broadcast. Note that this flag <em>cannot</em> be recursively
+ * applied to any contained instances, since a malicious app may have
+ * controlled them via {@link #fillIn(Intent, int)}.
+ */
+ private static final int LOCAL_FLAG_FROM_PROTECTED_COMPONENT = 1 << 2;
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// toUri() and parseUri() options.
@@ -6798,6 +6817,8 @@
private String mPackage;
private ComponentName mComponent;
private int mFlags;
+ /** Set of in-process flags which are never parceled */
+ private int mLocalFlags;
private ArraySet<String> mCategories;
@UnsupportedAppUsage
private Bundle mExtras;
@@ -6848,6 +6869,11 @@
this.mCategories = new ArraySet<>(o.mCategories);
}
+ // Inherit flags from the original, plus mark that we were
+ // created by this copy constructor
+ this.mLocalFlags = o.mLocalFlags;
+ this.mLocalFlags |= LOCAL_FLAG_FROM_COPY;
+
if (copyMode != COPY_MODE_FILTER) {
this.mFlags = o.mFlags;
this.mContentUserHint = o.mContentUserHint;
@@ -10931,6 +10957,9 @@
/** @hide */
protected Intent(Parcel in) {
+ // Remember that we came from a remote process to help detect security
+ // issues caused by later unsafe launches
+ mLocalFlags = LOCAL_FLAG_FROM_PARCEL;
readFromParcel(in);
}
@@ -11242,18 +11271,27 @@
mData = Uri.fromFile(after);
}
}
+
+ // Detect cases where we're about to launch a potentially unsafe intent
+ if ((mLocalFlags & LOCAL_FLAG_FROM_PARCEL) != 0
+ && (mLocalFlags & LOCAL_FLAG_FROM_PROTECTED_COMPONENT) == 0
+ && StrictMode.vmUnsafeIntentLaunchEnabled()) {
+ StrictMode.onUnsafeIntentLaunch(this);
+ }
}
/**
* @hide
*/
- public void prepareToEnterProcess() {
+ public void prepareToEnterProcess(boolean fromProtectedComponent) {
// We just entered destination process, so we should be able to read all
// parcelables inside.
setDefusable(true);
if (mSelector != null) {
- mSelector.prepareToEnterProcess();
+ // We can't recursively claim that this data is from a protected
+ // component, since it may have been filled in by a malicious app
+ mSelector.prepareToEnterProcess(false);
}
if (mClipData != null) {
mClipData.prepareToEnterProcess();
@@ -11265,6 +11303,10 @@
mContentUserHint = UserHandle.USER_CURRENT;
}
}
+
+ if (fromProtectedComponent) {
+ mLocalFlags |= LOCAL_FLAG_FROM_PROTECTED_COMPONENT;
+ }
}
/** @hide */
diff --git a/core/java/android/content/om/IOverlayManager.aidl b/core/java/android/content/om/IOverlayManager.aidl
index 44b5c44..0b950b4 100644
--- a/core/java/android/content/om/IOverlayManager.aidl
+++ b/core/java/android/content/om/IOverlayManager.aidl
@@ -17,6 +17,7 @@
package android.content.om;
import android.content.om.OverlayInfo;
+import android.content.om.OverlayManagerTransaction;
/**
* Api for getting information about overlay packages.
@@ -163,4 +164,18 @@
* @param packageName The name of the overlay package whose idmap should be deleted.
*/
void invalidateCachesForOverlay(in String packageName, in int userIs);
+
+ /**
+ * Perform a series of requests related to overlay packages. This is an
+ * atomic operation: either all requests were performed successfully and
+ * the changes were propagated to the rest of the system, or at least one
+ * request could not be performed successfully and nothing is changed and
+ * nothing is propagated to the rest of the system.
+ *
+ * @see OverlayManagerTransaction
+ *
+ * @param transaction the series of overlay related requests to perform
+ * @throws SecurityException if the transaction failed
+ */
+ void commit(in OverlayManagerTransaction transaction);
}
diff --git a/core/java/android/content/om/OverlayManager.java b/core/java/android/content/om/OverlayManager.java
index 217f637c..7c14c28 100644
--- a/core/java/android/content/om/OverlayManager.java
+++ b/core/java/android/content/om/OverlayManager.java
@@ -254,6 +254,29 @@
}
/**
+ * Perform a series of requests related to overlay packages. This is an
+ * atomic operation: either all requests were performed successfully and
+ * the changes were propagated to the rest of the system, or at least one
+ * request could not be performed successfully and nothing is changed and
+ * nothing is propagated to the rest of the system.
+ *
+ * @see OverlayManagerTransaction
+ *
+ * @param transaction the series of overlay related requests to perform
+ * @throws Exception if not all the requests could be successfully and
+ * atomically executed
+ *
+ * @hide
+ */
+ public void commit(@NonNull final OverlayManagerTransaction transaction) {
+ try {
+ mService.commit(transaction);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Starting on R, actor enforcement and app visibility changes introduce additional failure
* cases, but the SecurityException thrown with these checks is unexpected for existing
* consumers of the API.
diff --git a/core/java/android/content/om/OverlayManagerTransaction.aidl b/core/java/android/content/om/OverlayManagerTransaction.aidl
new file mode 100644
index 0000000..6715c82
--- /dev/null
+++ b/core/java/android/content/om/OverlayManagerTransaction.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.om;
+
+parcelable OverlayManagerTransaction;
diff --git a/core/java/android/content/om/OverlayManagerTransaction.java b/core/java/android/content/om/OverlayManagerTransaction.java
new file mode 100644
index 0000000..1fa8973
--- /dev/null
+++ b/core/java/android/content/om/OverlayManagerTransaction.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.om;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.UserHandle;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Container for a batch of requests to the OverlayManagerService.
+ *
+ * Transactions are created using a builder interface. Example usage:
+ *
+ * final OverlayManager om = ctx.getSystemService(OverlayManager.class);
+ * final OverlayManagerTransaction t = new OverlayManagerTransaction.Builder()
+ * .setEnabled(...)
+ * .setEnabled(...)
+ * .build();
+ * om.commit(t);
+ *
+ * @hide
+ */
+public class OverlayManagerTransaction
+ implements Iterable<OverlayManagerTransaction.Request>, Parcelable {
+ // TODO: remove @hide from this class when OverlayManager is added to the
+ // SDK, but keep OverlayManagerTransaction.Request @hidden
+ private final List<Request> mRequests;
+
+ OverlayManagerTransaction(@NonNull final List<Request> requests) {
+ checkNotNull(requests);
+ if (requests.contains(null)) {
+ throw new IllegalArgumentException("null request");
+ }
+ mRequests = requests;
+ }
+
+ private OverlayManagerTransaction(@NonNull final Parcel source) {
+ final int size = source.readInt();
+ mRequests = new ArrayList<Request>(size);
+ for (int i = 0; i < size; i++) {
+ final int request = source.readInt();
+ final String packageName = source.readString();
+ final int userId = source.readInt();
+ mRequests.add(new Request(request, packageName, userId));
+ }
+ }
+
+ @Override
+ public Iterator<Request> iterator() {
+ return mRequests.iterator();
+ }
+
+ @Override
+ public String toString() {
+ return String.format("OverlayManagerTransaction { mRequests = %s }", mRequests);
+ }
+
+ /**
+ * A single unit of the transaction, such as a request to enable an
+ * overlay, or to disable an overlay.
+ *
+ * @hide
+ */
+ public static class Request {
+ @IntDef(prefix = "TYPE_", value = {
+ TYPE_SET_ENABLED,
+ TYPE_SET_DISABLED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface RequestType {}
+
+ public static final int TYPE_SET_ENABLED = 0;
+ public static final int TYPE_SET_DISABLED = 1;
+
+ @RequestType public final int type;
+ public final String packageName;
+ public final int userId;
+
+ public Request(@RequestType final int type, @NonNull final String packageName,
+ final int userId) {
+ this.type = type;
+ this.packageName = packageName;
+ this.userId = userId;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("Request{type=0x%02x (%s), packageName=%s, userId=%d}",
+ type, typeToString(), packageName, userId);
+ }
+
+ /**
+ * Translate the request type into a human readable string. Only
+ * intended for debugging.
+ *
+ * @hide
+ */
+ public String typeToString() {
+ switch (type) {
+ case TYPE_SET_ENABLED: return "TYPE_SET_ENABLED";
+ case TYPE_SET_DISABLED: return "TYPE_SET_DISABLED";
+ default: return String.format("TYPE_UNKNOWN (0x%02x)", type);
+ }
+ }
+ }
+
+ /**
+ * Builder class for OverlayManagerTransaction objects.
+ *
+ * @hide
+ */
+ public static class Builder {
+ private final List<Request> mRequests = new ArrayList<>();
+
+ /**
+ * Request that an overlay package be enabled and change its loading
+ * order to the last package to be loaded, or disabled
+ *
+ * If the caller has the correct permissions, it is always possible to
+ * disable an overlay. Due to technical and security reasons it may not
+ * always be possible to enable an overlay, for instance if the overlay
+ * does not successfully overlay any target resources due to
+ * overlayable policy restrictions.
+ *
+ * An enabled overlay is a part of target package's resources, i.e. it will
+ * be part of any lookups performed via {@link android.content.res.Resources}
+ * and {@link android.content.res.AssetManager}. A disabled overlay will no
+ * longer affect the resources of the target package. If the target is
+ * currently running, its outdated resources will be replaced by new ones.
+ *
+ * @param packageName The name of the overlay package.
+ * @param enable true to enable the overlay, false to disable it.
+ * @return this Builder object, so you can chain additional requests
+ */
+ public Builder setEnabled(@NonNull String packageName, boolean enable) {
+ return setEnabled(packageName, enable, UserHandle.myUserId());
+ }
+
+ /**
+ * @hide
+ */
+ public Builder setEnabled(@NonNull String packageName, boolean enable, int userId) {
+ checkNotNull(packageName);
+ @Request.RequestType final int type =
+ enable ? Request.TYPE_SET_ENABLED : Request.TYPE_SET_DISABLED;
+ mRequests.add(new Request(type, packageName, userId));
+ return this;
+ }
+
+ /**
+ * Create a new transaction out of the requests added so far. Execute
+ * the transaction by calling OverlayManager#commit.
+ *
+ * @see OverlayManager#commit
+ * @return a new transaction
+ */
+ public OverlayManagerTransaction build() {
+ return new OverlayManagerTransaction(mRequests);
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ final int size = mRequests.size();
+ dest.writeInt(size);
+ for (int i = 0; i < size; i++) {
+ final Request req = mRequests.get(i);
+ dest.writeInt(req.type);
+ dest.writeString(req.packageName);
+ dest.writeInt(req.userId);
+ }
+ }
+
+ public static final Parcelable.Creator<OverlayManagerTransaction> CREATOR =
+ new Parcelable.Creator<OverlayManagerTransaction>() {
+
+ @Override
+ public OverlayManagerTransaction createFromParcel(Parcel source) {
+ return new OverlayManagerTransaction(source);
+ }
+
+ @Override
+ public OverlayManagerTransaction[] newArray(int size) {
+ return new OverlayManagerTransaction[size];
+ }
+ };
+}
diff --git a/core/java/android/content/pm/AppSearchPerson.java b/core/java/android/content/pm/AppSearchPerson.java
index 045c55f..d70ac91 100644
--- a/core/java/android/content/pm/AppSearchPerson.java
+++ b/core/java/android/content/pm/AppSearchPerson.java
@@ -47,32 +47,24 @@
}
public static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_NAME)
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_NAME)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
.build()
- ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_KEY)
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_KEY)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
.build()
- ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_IS_BOT)
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
+ ).addProperty(new AppSearchSchema.BooleanPropertyConfig.Builder(KEY_IS_BOT)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build()
- ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_IS_IMPORTANT)
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
+ ).addProperty(new AppSearchSchema.BooleanPropertyConfig.Builder(KEY_IS_IMPORTANT)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build()
).build();
diff --git a/core/java/android/content/pm/AppSearchShortcutInfo.java b/core/java/android/content/pm/AppSearchShortcutInfo.java
index 14b8df8..85549d8 100644
--- a/core/java/android/content/pm/AppSearchShortcutInfo.java
+++ b/core/java/android/content/pm/AppSearchShortcutInfo.java
@@ -73,131 +73,100 @@
public static final String KEY_DISABLED_REASON = "disabledReason";
public static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
- .addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_PACKAGE_NAME)
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_PACKAGE_NAME)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
.build()
- ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_ACTIVITY)
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_ACTIVITY)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
.build()
- ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_TITLE)
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_TITLE)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
.build()
- ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_TEXT)
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_TEXT)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
.build()
- ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_DISABLED_MESSAGE)
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_DISABLED_MESSAGE)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
.build()
- ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_CATEGORIES)
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_CATEGORIES)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
.build()
- ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_INTENTS)
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_INTENTS)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
.build()
- ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_INTENT_PERSISTABLE_EXTRAS)
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
+ ).addProperty(new AppSearchSchema.BytesPropertyConfig.Builder(
+ KEY_INTENT_PERSISTABLE_EXTRAS)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build()
- ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_PERSON)
+ ).addProperty(new AppSearchSchema.DocumentPropertyConfig.Builder(KEY_PERSON)
.setSchemaType(AppSearchPerson.SCHEMA_TYPE)
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOCUMENT)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build()
- ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_LOCUS_ID)
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_LOCUS_ID)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
.build()
- ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_RANK)
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ ).addProperty(new AppSearchSchema.Int64PropertyConfig.Builder(KEY_RANK)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build()
- ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_EXTRAS)
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
+ ).addProperty(new AppSearchSchema.BytesPropertyConfig.Builder(KEY_EXTRAS)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build()
- ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_FLAGS)
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ ).addProperty(new AppSearchSchema.Int64PropertyConfig.Builder(KEY_FLAGS)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
.build()
- ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_ICON_RES_ID)
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ ).addProperty(new AppSearchSchema.Int64PropertyConfig.Builder(KEY_ICON_RES_ID)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
.build()
- ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_ICON_RES_NAME)
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_ICON_RES_NAME)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
.build()
- ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_ICON_URI)
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_ICON_URI)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
.build()
- ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_BITMAP_PATH)
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_BITMAP_PATH)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+ .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
.build()
- ).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_DISABLED_REASON)
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ ).addProperty(new AppSearchSchema.Int64PropertyConfig.Builder(KEY_DISABLED_REASON)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
- .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
.build()
).build();
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 747f8dc..0433db4 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2589,6 +2589,14 @@
/**
* Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device is compatible with Android’s security model.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_SECURITY_MODEL_COMPATIBLE =
+ "android.hardware.security.model.compatible";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device supports the OpenGL ES
* <a href="http://www.khronos.org/registry/gles/extensions/ANDROID/ANDROID_extension_pack_es31a.txt">
* Android Extension Pack</a>.
diff --git a/core/java/android/hardware/ISensorPrivacyManager.aidl b/core/java/android/hardware/ISensorPrivacyManager.aidl
index a54e88f..dbcd79d 100644
--- a/core/java/android/hardware/ISensorPrivacyManager.aidl
+++ b/core/java/android/hardware/ISensorPrivacyManager.aidl
@@ -41,4 +41,7 @@
void setIndividualSensorPrivacyForProfileGroup(int userId, int sensor, boolean enable);
// =============== End of transactions used on native side as well ============================
+
+ void suppressIndividualSensorPrivacyReminders(int userId, String packageName, IBinder token,
+ boolean suppress);
}
\ No newline at end of file
diff --git a/core/java/android/hardware/SensorPrivacyManager.java b/core/java/android/hardware/SensorPrivacyManager.java
index e165ad6..f4f9e17 100644
--- a/core/java/android/hardware/SensorPrivacyManager.java
+++ b/core/java/android/hardware/SensorPrivacyManager.java
@@ -22,6 +22,7 @@
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.content.Context;
+import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -44,6 +45,18 @@
@TestApi
@SystemService(Context.SENSOR_PRIVACY_SERVICE)
public final class SensorPrivacyManager {
+ /**
+ * Unique Id of this manager to identify to the service
+ * @hide
+ */
+ private IBinder token = new Binder();
+
+ /**
+ * An extra containing a sensor
+ * @hide
+ */
+ public static final String EXTRA_SENSOR = SensorPrivacyManager.class.getName()
+ + ".extra.sensor";
/** Microphone
* @hide */
@@ -299,4 +312,22 @@
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Don't show dialogs to turn off sensor privacy for this package.
+ *
+ * @param packageName Package name not to show dialogs for
+ * @param suppress Whether to suppress or re-enable.
+ *
+ * @hide
+ */
+ public void suppressIndividualSensorPrivacyReminders(@NonNull String packageName,
+ boolean suppress) {
+ try {
+ mService.suppressIndividualSensorPrivacyReminders(mContext.getUserId(), packageName,
+ token, suppress);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl
index fcdf61e..c854ac98 100644
--- a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl
@@ -38,7 +38,7 @@
SensorPropertiesInternal getSensorProperties(String opPackageName);
// Requests a proto dump of the sensor. See biometrics.proto
- byte[] dumpSensorServiceStateProto();
+ byte[] dumpSensorServiceStateProto(boolean clearSchedulerBuffer);
// This method prepares the service to start authenticating, but doesn't start authentication.
// This is protected by the MANAGE_BIOMETRIC signature permission. This method should only be
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 5a03ade..421a07b 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -47,28 +47,40 @@
* begins adjusting the power state to match what was requested.
* </p>
*
+ * @param groupId The identifier for the display group being requested to change power state
* @param request The requested power state.
- * @param waitForNegativeProximity If true, issues a request to wait for
+ * @param waitForNegativeProximity If {@code true}, issues a request to wait for
* negative proximity before turning the screen back on, assuming the screen
* was turned off by the proximity sensor.
- * @return True if display is ready, false if there are important changes that must
- * be made asynchronously (such as turning the screen on), in which case the caller
- * should grab a wake lock, watch for {@link DisplayPowerCallbacks#onStateChanged()}
- * then try the request again later until the state converges.
+ * @return {@code true} if display group is ready, {@code false} if there are important
+ * changes that must be made asynchronously (such as turning the screen on), in which case
+ * the caller should grab a wake lock, watch for {@link DisplayPowerCallbacks#onStateChanged}
+ * then try the request again later until the state converges. If the provided {@code groupId}
+ * cannot be found then {@code true} will be returned.
*/
- public abstract boolean requestPowerState(DisplayPowerRequest request,
+ public abstract boolean requestPowerState(int groupId, DisplayPowerRequest request,
boolean waitForNegativeProximity);
/**
- * Returns true if the proximity sensor screen-off function is available.
+ * Returns {@code true} if the proximity sensor screen-off function is available.
*/
public abstract boolean isProximitySensorAvailable();
/**
- * Returns the id of the {@link com.android.server.display.DisplayGroup} to which the provided
- * display belongs.
+ * Registers a display group listener which will be informed of the addition, removal, or change
+ * of display groups.
+ *
+ * @param listener The listener to register.
*/
- public abstract int getDisplayGroupId(int displayId);
+ public abstract void registerDisplayGroupListener(DisplayGroupListener listener);
+
+ /**
+ * Unregisters a display group listener which will be informed of the addition, removal, or
+ * change of display groups.
+ *
+ * @param listener The listener to unregister.
+ */
+ public abstract void unregisterDisplayGroupListener(DisplayGroupListener listener);
/**
* Screenshot for internal system-only use such as rotation, etc. This method includes
@@ -451,7 +463,7 @@
void onStateChanged();
void onProximityPositive();
void onProximityNegative();
- void onDisplayStateChange(int state); // one of the Display state constants
+ void onDisplayStateChange(boolean allInactive, boolean allOff);
void acquireSuspendBlocker();
void releaseSuspendBlocker();
@@ -465,4 +477,33 @@
public interface DisplayTransactionListener {
void onDisplayTransaction(Transaction t);
}
+
+ /**
+ * Called when there are changes to {@link com.android.server.display.DisplayGroup
+ * DisplayGroups}.
+ */
+ public interface DisplayGroupListener {
+ /**
+ * A new display group with the provided {@code groupId} was added.
+ * This is guaranteed to be called <i>before</i> any corresponding calls to
+ * {@link android.hardware.display.DisplayManager.DisplayListener} are made.
+ */
+ void onDisplayGroupAdded(int groupId);
+
+ /**
+ * The display group with the provided {@code groupId} was removed.
+ *
+ * This is guaranteed to be called <i>after</i> any corresponding calls to
+ * {@link android.hardware.display.DisplayManager.DisplayListener} are made.
+ */
+ void onDisplayGroupRemoved(int groupId);
+
+ /**
+ * The display group with the provided {@code groupId} has changed.
+ *
+ * This is guaranteed to be called <i>after</i> any corresponding calls to
+ * {@link android.hardware.display.DisplayManager.DisplayListener} are made.
+ */
+ void onDisplayGroupChanged(int groupId);
+ }
}
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index 3b19f12..1b188e8 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -35,7 +35,7 @@
ITestSession createTestSession(int sensorId, String opPackageName);
// Requests a proto dump of the specified sensor
- byte[] dumpSensorServiceStateProto(int sensorId);
+ byte[] dumpSensorServiceStateProto(int sensorId, boolean clearSchedulerBuffer);
// Retrieve static sensor properties for all face sensors
List<FaceSensorPropertiesInternal> getSensorPropertiesInternal(String opPackageName);
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 582570e..d932865 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -89,6 +89,8 @@
private static final int MSG_REMOVED = 105;
private static final int MSG_CHALLENGE_GENERATED = 106;
private static final int MSG_FINGERPRINT_DETECTED = 107;
+ private static final int MSG_UDFPS_POINTER_DOWN = 108;
+ private static final int MSG_UDFPS_POINTER_UP = 109;
/**
* Request authentication with any single sensor.
@@ -338,6 +340,20 @@
*/
@Override
public void onAuthenticationAcquired(int acquireInfo) {}
+
+ /**
+ * Invoked for under-display fingerprint sensors when a touch has been detected on the
+ * sensor area.
+ * @hide
+ */
+ public void onUdfpsPointerDown(int sensorId) {}
+
+ /**
+ * Invoked for under-display fingerprint sensors when a touch has been removed from the
+ * sensor area.
+ * @hide
+ */
+ public void onUdfpsPointerUp(int sensorId) {}
}
/**
@@ -1005,6 +1021,12 @@
sendFingerprintDetected(msg.arg1 /* sensorId */, msg.arg2 /* userId */,
(boolean) msg.obj /* isStrongBiometric */);
break;
+ case MSG_UDFPS_POINTER_DOWN:
+ sendUdfpsPointerDown(msg.arg1 /* sensorId */);
+ break;
+ case MSG_UDFPS_POINTER_UP:
+ sendUdfpsPointerUp(msg.arg1 /* sensorId */);
+ break;
default:
Slog.w(TAG, "Unknown message: " + msg.what);
@@ -1103,6 +1125,22 @@
mFingerprintDetectionCallback.onFingerprintDetected(sensorId, userId, isStrongBiometric);
}
+ private void sendUdfpsPointerDown(int sensorId) {
+ if (mAuthenticationCallback == null) {
+ Slog.e(TAG, "sendUdfpsPointerDown, callback null");
+ return;
+ }
+ mAuthenticationCallback.onUdfpsPointerDown(sensorId);
+ }
+
+ private void sendUdfpsPointerUp(int sensorId) {
+ if (mAuthenticationCallback == null) {
+ Slog.e(TAG, "sendUdfpsPointerUp, callback null");
+ return;
+ }
+ mAuthenticationCallback.onUdfpsPointerUp(sensorId);
+ }
+
/**
* @hide
*/
@@ -1280,6 +1318,17 @@
mHandler.obtainMessage(MSG_CHALLENGE_GENERATED, sensorId, 0, challenge)
.sendToTarget();
}
+
+ @Override // binder call
+ public void onUdfpsPointerDown(int sensorId) {
+ mHandler.obtainMessage(MSG_UDFPS_POINTER_DOWN, sensorId, 0).sendToTarget();
+ }
+
+ @Override // binder call
+ public void onUdfpsPointerUp(int sensorId) {
+ mHandler.obtainMessage(MSG_UDFPS_POINTER_UP, sensorId, 0).sendToTarget();
+
+ }
};
}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 74c5b58..3657a83 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -36,7 +36,7 @@
ITestSession createTestSession(int sensorId, String opPackageName);
// Requests a proto dump of the specified sensor
- byte[] dumpSensorServiceStateProto(int sensorId);
+ byte[] dumpSensorServiceStateProto(int sensorId, boolean clearSchedulerBuffer);
// Retrieve static sensor properties for all fingerprint sensors
List<FingerprintSensorPropertiesInternal> getSensorPropertiesInternal(String opPackageName);
diff --git a/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl b/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
index 095b8e9..1bd284d 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
@@ -30,4 +30,6 @@
void onError(int error, int vendorCode);
void onRemoved(in Fingerprint fp, int remaining);
void onChallengeGenerated(int sensorId, long challenge);
+ void onUdfpsPointerDown(int sensorId);
+ void onUdfpsPointerUp(int sensorId);
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 899af5a..2e45ed8 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -19,6 +19,7 @@
import static android.net.NetworkRequest.Type.LISTEN;
import static android.net.NetworkRequest.Type.REQUEST;
import static android.net.NetworkRequest.Type.TRACK_DEFAULT;
+import static android.net.QosCallback.QosCallbackRegistrationException;
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
@@ -29,7 +30,6 @@
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
import android.annotation.SystemService;
-import android.annotation.TestApi;
import android.app.PendingIntent;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -4823,6 +4823,8 @@
/**
* Simulates a Data Stall for the specified Network.
*
+ * <p>This method should only be used for tests.
+ *
* <p>The caller must be the owner of the specified Network.
*
* @param detectionMethod The detection method used to identify the Data Stall.
@@ -4832,7 +4834,7 @@
* @throws SecurityException if the caller is not the owner of the given network.
* @hide
*/
- @TestApi
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_TEST_NETWORKS,
android.Manifest.permission.NETWORK_STACK})
public void simulateDataStall(int detectionMethod, long timestampMillis,
@@ -4848,4 +4850,118 @@
Log.d(TAG, "setOemNetworkPreference called with preference: "
+ preference.toString());
}
+
+ @NonNull
+ private final List<QosCallbackConnection> mQosCallbackConnections = new ArrayList<>();
+
+ /**
+ * Registers a {@link QosSocketInfo} with an associated {@link QosCallback}. The callback will
+ * receive available QoS events related to the {@link Network} and local ip + port
+ * specified within socketInfo.
+ * <p/>
+ * The same {@link QosCallback} must be unregistered before being registered a second time,
+ * otherwise {@link QosCallbackRegistrationException} is thrown.
+ * <p/>
+ * This API does not, in itself, require any permission if called with a network that is not
+ * restricted. However, the underlying implementation currently only supports the IMS network,
+ * which is always restricted. That means non-preinstalled callers can't possibly find this API
+ * useful, because they'd never be called back on networks that they would have access to.
+ *
+ * @throws SecurityException if {@link QosSocketInfo#getNetwork()} is restricted and the app is
+ * missing CONNECTIVITY_USE_RESTRICTED_NETWORKS permission.
+ * @throws QosCallback.QosCallbackRegistrationException if qosCallback is already registered.
+ * @throws RuntimeException if the app already has too many callbacks registered.
+ *
+ * Exceptions after the time of registration is passed through
+ * {@link QosCallback#onError(QosCallbackException)}. see: {@link QosCallbackException}.
+ *
+ * @param socketInfo the socket information used to match QoS events
+ * @param callback receives qos events that satisfy socketInfo
+ * @param executor The executor on which the callback will be invoked. The provided
+ * {@link Executor} must run callback sequentially, otherwise the order of
+ * callbacks cannot be guaranteed.
+ *
+ * @hide
+ */
+ @SystemApi
+ public void registerQosCallback(@NonNull final QosSocketInfo socketInfo,
+ @NonNull final QosCallback callback,
+ @CallbackExecutor @NonNull final Executor executor) {
+ Objects.requireNonNull(socketInfo, "socketInfo must be non-null");
+ Objects.requireNonNull(callback, "callback must be non-null");
+ Objects.requireNonNull(executor, "executor must be non-null");
+
+ try {
+ synchronized (mQosCallbackConnections) {
+ if (getQosCallbackConnection(callback) == null) {
+ final QosCallbackConnection connection =
+ new QosCallbackConnection(this, callback, executor);
+ mQosCallbackConnections.add(connection);
+ mService.registerQosSocketCallback(socketInfo, connection);
+ } else {
+ Log.e(TAG, "registerQosCallback: Callback already registered");
+ throw new QosCallbackRegistrationException();
+ }
+ }
+ } catch (final RemoteException e) {
+ Log.e(TAG, "registerQosCallback: Error while registering ", e);
+
+ // The same unregister method method is called for consistency even though nothing
+ // will be sent to the ConnectivityService since the callback was never successfully
+ // registered.
+ unregisterQosCallback(callback);
+ e.rethrowFromSystemServer();
+ } catch (final ServiceSpecificException e) {
+ Log.e(TAG, "registerQosCallback: Error while registering ", e);
+ unregisterQosCallback(callback);
+ throw convertServiceException(e);
+ }
+ }
+
+ /**
+ * Unregisters the given {@link QosCallback}. The {@link QosCallback} will no longer receive
+ * events once unregistered and can be registered a second time.
+ * <p/>
+ * If the {@link QosCallback} does not have an active registration, it is a no-op.
+ *
+ * @param callback the callback being unregistered
+ *
+ * @hide
+ */
+ @SystemApi
+ public void unregisterQosCallback(@NonNull final QosCallback callback) {
+ Objects.requireNonNull(callback, "The callback must be non-null");
+ try {
+ synchronized (mQosCallbackConnections) {
+ final QosCallbackConnection connection = getQosCallbackConnection(callback);
+ if (connection != null) {
+ connection.stopReceivingMessages();
+ mService.unregisterQosCallback(connection);
+ mQosCallbackConnections.remove(connection);
+ } else {
+ Log.d(TAG, "unregisterQosCallback: Callback not registered");
+ }
+ }
+ } catch (final RemoteException e) {
+ Log.e(TAG, "unregisterQosCallback: Error while unregistering ", e);
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Gets the connection related to the callback.
+ *
+ * @param callback the callback to look up
+ * @return the related connection
+ */
+ @Nullable
+ private QosCallbackConnection getQosCallbackConnection(final QosCallback callback) {
+ for (final QosCallbackConnection connection : mQosCallbackConnections) {
+ // Checking by reference here is intentional
+ if (connection.getCallback() == callback) {
+ return connection;
+ }
+ }
+ return null;
+ }
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 5e925b6..6fecee6 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -20,6 +20,8 @@
import android.net.ConnectionInfo;
import android.net.ConnectivityDiagnosticsManager;
import android.net.IConnectivityDiagnosticsCallback;
+import android.net.IQosCallback;
+import android.net.ISocketKeepaliveCallback;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkAgentConfig;
@@ -27,9 +29,9 @@
import android.net.NetworkInfo;
import android.net.NetworkRequest;
import android.net.NetworkState;
-import android.net.ISocketKeepaliveCallback;
import android.net.ProxyInfo;
import android.net.UidRange;
+import android.net.QosSocketInfo;
import android.os.Bundle;
import android.os.IBinder;
import android.os.INetworkActivityListener;
@@ -206,11 +208,11 @@
void startNattKeepalive(in Network network, int intervalSeconds,
in ISocketKeepaliveCallback cb, String srcAddr, int srcPort, String dstAddr);
- void startNattKeepaliveWithFd(in Network network, in FileDescriptor fd, int resourceId,
+ void startNattKeepaliveWithFd(in Network network, in ParcelFileDescriptor pfd, int resourceId,
int intervalSeconds, in ISocketKeepaliveCallback cb, String srcAddr,
String dstAddr);
- void startTcpKeepalive(in Network network, in FileDescriptor fd, int intervalSeconds,
+ void startTcpKeepalive(in Network network, in ParcelFileDescriptor pfd, int intervalSeconds,
in ISocketKeepaliveCallback cb);
void stopKeepalive(in Network network, int slot);
@@ -239,4 +241,7 @@
void unregisterNetworkActivityListener(in INetworkActivityListener l);
boolean isDefaultNetworkActive();
+
+ void registerQosSocketCallback(in QosSocketInfo socketInfo, in IQosCallback callback);
+ void unregisterQosCallback(in IQosCallback callback);
}
diff --git a/core/java/android/net/INetworkPolicyListener.aidl b/core/java/android/net/INetworkPolicyListener.aidl
index fe9141c..dfb1e99 100644
--- a/core/java/android/net/INetworkPolicyListener.aidl
+++ b/core/java/android/net/INetworkPolicyListener.aidl
@@ -23,6 +23,6 @@
void onMeteredIfacesChanged(in String[] meteredIfaces);
void onRestrictBackgroundChanged(boolean restrictBackground);
void onUidPoliciesChanged(int uid, int uidPolicies);
- void onSubscriptionOverride(int subId, int overrideMask, int overrideValue);
+ void onSubscriptionOverride(int subId, int overrideMask, int overrideValue, in int[] networkTypes);
void onSubscriptionPlansChanged(int subId, in SubscriptionPlan[] plans);
}
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 792e5b4..84a2acc 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -76,9 +76,10 @@
SubscriptionPlan[] getSubscriptionPlans(int subId, String callingPackage);
void setSubscriptionPlans(int subId, in SubscriptionPlan[] plans, String callingPackage);
String getSubscriptionPlansOwner(int subId);
- void setSubscriptionOverride(int subId, int overrideMask, int overrideValue, long timeoutMillis, String callingPackage);
+ void setSubscriptionOverride(int subId, int overrideMask, int overrideValue, in int[] networkTypes, long timeoutMillis, String callingPackage);
void factoryReset(String subscriber);
boolean isUidNetworkingBlocked(int uid, boolean meteredNetwork);
+ boolean isUidRestrictedOnMeteredNetworks(int uid);
}
diff --git a/core/java/android/net/IQosCallback.aidl b/core/java/android/net/IQosCallback.aidl
new file mode 100644
index 0000000..91c7575
--- /dev/null
+++ b/core/java/android/net/IQosCallback.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.os.Bundle;
+import android.net.QosSession;
+import android.telephony.data.EpsBearerQosSessionAttributes;
+
+/**
+ * AIDL interface for QosCallback
+ *
+ * @hide
+ */
+oneway interface IQosCallback
+{
+ void onQosEpsBearerSessionAvailable(in QosSession session,
+ in EpsBearerQosSessionAttributes attributes);
+ void onQosSessionLost(in QosSession session);
+ void onError(in int type);
+}
diff --git a/core/java/android/net/NattSocketKeepalive.java b/core/java/android/net/NattSocketKeepalive.java
index b0ce0c7..a15d165 100644
--- a/core/java/android/net/NattSocketKeepalive.java
+++ b/core/java/android/net/NattSocketKeepalive.java
@@ -51,7 +51,7 @@
void startImpl(int intervalSec) {
mExecutor.execute(() -> {
try {
- mService.startNattKeepaliveWithFd(mNetwork, mPfd.getFileDescriptor(), mResourceId,
+ mService.startNattKeepaliveWithFd(mNetwork, mPfd, mResourceId,
intervalSec, mCallback,
mSource.getHostAddress(), mDestination.getHostAddress());
} catch (RemoteException e) {
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 4f46736..d22d82d 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -30,6 +30,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.telephony.data.EpsBearerQosSessionAttributes;
import android.util.Log;
import com.android.connectivity.aidl.INetworkAgent;
@@ -228,12 +229,6 @@
public static final String REDIRECT_URL_KEY = "redirect URL";
/**
- * Bundle key for the underlying networks in {@code EVENT_UNDERLYING_NETWORKS_CHANGED}.
- * @hide
- */
- public static final String UNDERLYING_NETWORKS_KEY = "underlyingNetworks";
-
- /**
* Sent by the NetworkAgent to ConnectivityService to indicate this network was
* explicitly selected. This should be sent before the NetworkInfo is marked
* CONNECTED so it can be given special treatment at that time.
@@ -347,6 +342,24 @@
*/
private static final int EVENT_AGENT_DISCONNECTED = BASE + 19;
+ /**
+ * Sent by QosCallbackTracker to {@link NetworkAgent} to register a new filter with
+ * callback.
+ *
+ * arg1 = QoS agent callback ID
+ * obj = {@link QosFilter}
+ * @hide
+ */
+ public static final int CMD_REGISTER_QOS_CALLBACK = BASE + 20;
+
+ /**
+ * Sent by QosCallbackTracker to {@link NetworkAgent} to unregister a callback.
+ *
+ * arg1 = QoS agent callback ID
+ * @hide
+ */
+ public static final int CMD_UNREGISTER_QOS_CALLBACK = BASE + 21;
+
private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) {
// The subtype can be changed with (TODO) setLegacySubtype, but it starts
// with 0 (TelephonyManager.NETWORK_TYPE_UNKNOWN) and an empty description.
@@ -526,6 +539,17 @@
onRemoveKeepalivePacketFilter(msg.arg1 /* slot */);
break;
}
+ case CMD_REGISTER_QOS_CALLBACK: {
+ onQosCallbackRegistered(
+ msg.arg1 /* QoS callback id */,
+ (QosFilter) msg.obj /* QoS filter */);
+ break;
+ }
+ case CMD_UNREGISTER_QOS_CALLBACK: {
+ onQosCallbackUnregistered(
+ msg.arg1 /* QoS callback id */);
+ break;
+ }
}
}
}
@@ -559,6 +583,8 @@
}
private static class NetworkAgentBinder extends INetworkAgent.Stub {
+ private static final String LOG_TAG = NetworkAgentBinder.class.getSimpleName();
+
private final Handler mHandler;
private NetworkAgentBinder(Handler handler) {
@@ -645,6 +671,25 @@
mHandler.sendMessage(mHandler.obtainMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER,
slot, 0));
}
+
+ @Override
+ public void onQosFilterCallbackRegistered(final int qosCallbackId,
+ final QosFilterParcelable qosFilterParcelable) {
+ if (qosFilterParcelable.getQosFilter() != null) {
+ mHandler.sendMessage(
+ mHandler.obtainMessage(CMD_REGISTER_QOS_CALLBACK, qosCallbackId, 0,
+ qosFilterParcelable.getQosFilter()));
+ return;
+ }
+
+ Log.wtf(LOG_TAG, "onQosFilterCallbackRegistered: qos filter is null.");
+ }
+
+ @Override
+ public void onQosCallbackUnregistered(final int qosCallbackId) {
+ mHandler.sendMessage(mHandler.obtainMessage(
+ CMD_UNREGISTER_QOS_CALLBACK, qosCallbackId, 0, null));
+ }
}
/**
@@ -1073,8 +1118,68 @@
protected void preventAutomaticReconnect() {
}
+ /**
+ * Called when a qos callback is registered with a filter.
+ * @param qosCallbackId the id for the callback registered
+ * @param filter the filter being registered
+ */
+ public void onQosCallbackRegistered(final int qosCallbackId, final @NonNull QosFilter filter) {
+ }
+
+ /**
+ * Called when a qos callback is registered with a filter.
+ * <p/>
+ * Any QoS events that are sent with the same callback id after this method is called
+ * are a no-op.
+ *
+ * @param qosCallbackId the id for the callback being unregistered
+ */
+ public void onQosCallbackUnregistered(final int qosCallbackId) {
+ }
+
+
+ /**
+ * Sends the attributes of Eps Bearer Qos Session back to the Application
+ *
+ * @param qosCallbackId the callback id that the session belongs to
+ * @param sessionId the unique session id across all Eps Bearer Qos Sessions
+ * @param attributes the attributes of the Eps Qos Session
+ */
+ public final void sendQosSessionAvailable(final int qosCallbackId, final int sessionId,
+ @NonNull final EpsBearerQosSessionAttributes attributes) {
+ Objects.requireNonNull(attributes, "The attributes must be non-null");
+ queueOrSendMessage(ra -> ra.sendEpsQosSessionAvailable(qosCallbackId,
+ new QosSession(sessionId, QosSession.TYPE_EPS_BEARER),
+ attributes));
+ }
+
+ /**
+ * Sends event that the Eps Qos Session was lost.
+ *
+ * @param qosCallbackId the callback id that the session belongs to
+ * @param sessionId the unique session id across all Eps Bearer Qos Sessions
+ */
+ public final void sendQosSessionLost(final int qosCallbackId, final int sessionId) {
+ queueOrSendMessage(ra -> ra.sendQosSessionLost(qosCallbackId,
+ new QosSession(sessionId, QosSession.TYPE_EPS_BEARER)));
+ }
+
+ /**
+ * Sends the exception type back to the application.
+ *
+ * The NetworkAgent should not send anymore messages with this id.
+ *
+ * @param qosCallbackId the callback id this exception belongs to
+ * @param exceptionType the type of exception
+ */
+ public final void sendQosCallbackError(final int qosCallbackId,
+ @QosCallbackException.ExceptionType final int exceptionType) {
+ queueOrSendMessage(ra -> ra.sendQosCallbackError(qosCallbackId, exceptionType));
+ }
+
+
/** @hide */
- protected void log(String s) {
+ protected void log(final String s) {
Log.d(LOG_TAG, "NetworkAgent: " + s);
}
}
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 2d9f6d8..0a895b9 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -23,7 +23,6 @@
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
-import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.net.ConnectivityManager.NetworkCallback;
import android.os.Build;
@@ -576,7 +575,6 @@
* @hide
*/
@UnsupportedAppUsage
- @TestApi
public @NetCapability int[] getCapabilities() {
return BitUtils.unpackBits(mNetworkCapabilities);
}
@@ -821,7 +819,7 @@
*
* @hide
*/
- @TestApi
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int TRANSPORT_TEST = 7;
/** @hide */
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index cad0db2..ed169e7 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -34,6 +34,7 @@
import android.os.Build;
import android.os.Process;
import android.os.RemoteException;
+import android.telephony.Annotation;
import android.telephony.SubscriptionPlan;
import android.util.DebugUtils;
import android.util.Pair;
@@ -377,6 +378,8 @@
* @param overrideMask the bitmask that specifies which of the overrides is being
* set or cleared.
* @param overrideValue the override values to set or clear.
+ * @param networkTypes the network types this override applies to.
+ * {@see TelephonyManager#getAllNetworkTypes()}
* @param timeoutMillis the timeout after which the requested override will
* be automatically cleared, or {@code 0} to leave in the
* requested state until explicitly cleared, or the next reboot,
@@ -385,11 +388,12 @@
* @hide
*/
public void setSubscriptionOverride(int subId, @SubscriptionOverrideMask int overrideMask,
- @SubscriptionOverrideMask int overrideValue, long timeoutMillis,
- @NonNull String callingPackage) {
+ @SubscriptionOverrideMask int overrideValue,
+ @NonNull @Annotation.NetworkType int[] networkTypes, long timeoutMillis,
+ @NonNull String callingPackage) {
try {
- mService.setSubscriptionOverride(subId, overrideMask, overrideValue, timeoutMillis,
- callingPackage);
+ mService.setSubscriptionOverride(subId, overrideMask, overrideValue, networkTypes,
+ timeoutMillis, callingPackage);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -460,6 +464,22 @@
}
/**
+ * Check that the given uid is restricted from doing networking on metered networks.
+ *
+ * @param uid The target uid.
+ * @return true if the given uid is restricted from doing networking on metered networks.
+ *
+ * @hide
+ */
+ public boolean isUidRestrictedOnMeteredNetworks(int uid) {
+ try {
+ return mService.isUidRestrictedOnMeteredNetworks(uid);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Get multipath preference for the given network.
*/
public int getMultipathPreference(Network network) {
@@ -597,9 +617,10 @@
* @param subId the subscriber this override applies to.
* @param overrideMask a bitmask that specifies which of the overrides is set.
* @param overrideValue a bitmask that specifies the override values.
+ * @param networkTypes the network types this override applies to.
*/
public void onSubscriptionOverride(int subId, @SubscriptionOverrideMask int overrideMask,
- @SubscriptionOverrideMask int overrideValue) {}
+ @SubscriptionOverrideMask int overrideValue, int[] networkTypes) {}
/**
* Notify of subscription plans change about a given subscription.
@@ -623,8 +644,8 @@
@Override
public void onSubscriptionOverride(int subId, @SubscriptionOverrideMask int overrideMask,
- @SubscriptionOverrideMask int overrideValue) {
- mCallback.onSubscriptionOverride(subId, overrideMask, overrideValue);
+ @SubscriptionOverrideMask int overrideValue, int[] networkTypes) {
+ mCallback.onSubscriptionOverride(subId, overrideMask, overrideValue, networkTypes);
}
@Override
@@ -640,7 +661,7 @@
@Override public void onRestrictBackgroundChanged(boolean restrictBackground) { }
@Override public void onUidPoliciesChanged(int uid, int uidPolicies) { }
@Override public void onSubscriptionOverride(int subId, int overrideMask,
- int overrideValue) { }
+ int overrideValue, int[] networkTypes) { }
@Override public void onSubscriptionPlansChanged(int subId, SubscriptionPlan[] plans) { }
}
}
diff --git a/core/java/android/net/NetworkReleasedException.java b/core/java/android/net/NetworkReleasedException.java
new file mode 100644
index 0000000..0629b75
--- /dev/null
+++ b/core/java/android/net/NetworkReleasedException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.SystemApi;
+
+/**
+ * Indicates that the {@link Network} was released and is no longer available.
+ *
+ * @hide
+ */
+@SystemApi
+public class NetworkReleasedException extends Exception {
+ /** @hide */
+ public NetworkReleasedException() {
+ super("The network was released and is no longer available");
+ }
+}
diff --git a/core/java/android/net/QosCallback.java b/core/java/android/net/QosCallback.java
new file mode 100644
index 0000000..22f06bc
--- /dev/null
+++ b/core/java/android/net/QosCallback.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Receives Qos information given a {@link Network}. The callback is registered with
+ * {@link ConnectivityManager#registerQosCallback}.
+ *
+ * <p>
+ * <br/>
+ * The callback will no longer receive calls if any of the following takes place:
+ * <ol>
+ * <li>{@link ConnectivityManager#unregisterQosCallback(QosCallback)} is called with the same
+ * callback instance.</li>
+ * <li>{@link QosCallback#onError(QosCallbackException)} is called.</li>
+ * <li>A network specific issue occurs. eg. Congestion on a carrier network.</li>
+ * <li>The network registered with the callback has no associated QoS providers</li>
+ * </ul>
+ * {@hide}
+ */
+@SystemApi
+public abstract class QosCallback {
+ /**
+ * Invoked after an error occurs on a registered callback. Once called, the callback is
+ * automatically unregistered and the callback will no longer receive calls.
+ *
+ * <p>The underlying exception can either be a runtime exception or a custom exception made for
+ * {@link QosCallback}. see: {@link QosCallbackException}.
+ *
+ * @param exception wraps the underlying cause
+ */
+ public void onError(@NonNull final QosCallbackException exception) {
+ }
+
+ /**
+ * Called when a Qos Session first becomes available to the callback or if its attributes have
+ * changed.
+ * <p>
+ * Note: The callback may be called multiple times with the same attributes.
+ *
+ * @param session the available session
+ * @param sessionAttributes the attributes of the session
+ */
+ public void onQosSessionAvailable(@NonNull final QosSession session,
+ @NonNull final QosSessionAttributes sessionAttributes) {
+ }
+
+ /**
+ * Called after a Qos Session is lost.
+ * <p>
+ * At least one call to
+ * {@link QosCallback#onQosSessionAvailable(QosSession, QosSessionAttributes)}
+ * with the same {@link QosSession} will precede a call to lost.
+ *
+ * @param session the lost session
+ */
+ public void onQosSessionLost(@NonNull final QosSession session) {
+ }
+
+ /**
+ * Thrown when there is a problem registering {@link QosCallback} with
+ * {@link ConnectivityManager#registerQosCallback(QosSocketInfo, QosCallback, Executor)}.
+ */
+ public static class QosCallbackRegistrationException extends RuntimeException {
+ /**
+ * @hide
+ */
+ public QosCallbackRegistrationException() {
+ super();
+ }
+ }
+}
diff --git a/core/java/android/net/QosCallbackConnection.java b/core/java/android/net/QosCallbackConnection.java
new file mode 100644
index 0000000..bdb4ad6
--- /dev/null
+++ b/core/java/android/net/QosCallbackConnection.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.telephony.data.EpsBearerQosSessionAttributes;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * Sends messages from {@link com.android.server.ConnectivityService} to the registered
+ * {@link QosCallback}.
+ * <p/>
+ * This is a satellite class of {@link ConnectivityManager} and not meant
+ * to be used in other contexts.
+ *
+ * @hide
+ */
+class QosCallbackConnection extends android.net.IQosCallback.Stub {
+
+ @NonNull private final ConnectivityManager mConnectivityManager;
+ @Nullable private volatile QosCallback mCallback;
+ @NonNull private final Executor mExecutor;
+
+ @VisibleForTesting
+ @Nullable
+ public QosCallback getCallback() {
+ return mCallback;
+ }
+
+ /**
+ * The constructor for the connection
+ *
+ * @param connectivityManager the mgr that created this connection
+ * @param callback the callback to send messages back to
+ * @param executor The executor on which the callback will be invoked. The provided
+ * {@link Executor} must run callback sequentially, otherwise the order of
+ * callbacks cannot be guaranteed.
+ */
+ QosCallbackConnection(@NonNull final ConnectivityManager connectivityManager,
+ @NonNull final QosCallback callback,
+ @NonNull final Executor executor) {
+ mConnectivityManager = Objects.requireNonNull(connectivityManager,
+ "connectivityManager must be non-null");
+ mCallback = Objects.requireNonNull(callback, "callback must be non-null");
+ mExecutor = Objects.requireNonNull(executor, "executor must be non-null");
+ }
+
+ /**
+ * Called when either the {@link EpsBearerQosSessionAttributes} has changed or on the first time
+ * the attributes have become available.
+ *
+ * @param session the session that is now available
+ * @param attributes the corresponding attributes of session
+ */
+ @Override
+ public void onQosEpsBearerSessionAvailable(@NonNull final QosSession session,
+ @NonNull final EpsBearerQosSessionAttributes attributes) {
+
+ mExecutor.execute(() -> {
+ final QosCallback callback = mCallback;
+ if (callback != null) {
+ callback.onQosSessionAvailable(session, attributes);
+ }
+ });
+ }
+
+ /**
+ * Called when the session is lost.
+ *
+ * @param session the session that was lost
+ */
+ @Override
+ public void onQosSessionLost(@NonNull final QosSession session) {
+ mExecutor.execute(() -> {
+ final QosCallback callback = mCallback;
+ if (callback != null) {
+ callback.onQosSessionLost(session);
+ }
+ });
+ }
+
+ /**
+ * Called when there is an error on the registered callback.
+ *
+ * @param errorType the type of error
+ */
+ @Override
+ public void onError(@QosCallbackException.ExceptionType final int errorType) {
+ mExecutor.execute(() -> {
+ final QosCallback callback = mCallback;
+ if (callback != null) {
+ // Messages no longer need to be received since there was an error.
+ stopReceivingMessages();
+ mConnectivityManager.unregisterQosCallback(callback);
+ callback.onError(QosCallbackException.createException(errorType));
+ }
+ });
+ }
+
+ /**
+ * The callback will stop receiving messages.
+ * <p/>
+ * There are no synchronization guarantees on exactly when the callback will stop receiving
+ * messages.
+ */
+ void stopReceivingMessages() {
+ mCallback = null;
+ }
+}
diff --git a/core/java/android/net/QosCallbackException.java b/core/java/android/net/QosCallbackException.java
new file mode 100644
index 0000000..7fd9a527e
--- /dev/null
+++ b/core/java/android/net/QosCallbackException.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This is the exception type passed back through the onError method on {@link QosCallback}.
+ * {@link QosCallbackException#getCause()} contains the actual error that caused this exception.
+ *
+ * The possible exception types as causes are:
+ * 1. {@link NetworkReleasedException}
+ * 2. {@link SocketNotBoundException}
+ * 3. {@link UnsupportedOperationException}
+ * 4. {@link SocketLocalAddressChangedException}
+ *
+ * @hide
+ */
+@SystemApi
+public final class QosCallbackException extends Exception {
+
+ /** @hide */
+ @IntDef(prefix = {"EX_TYPE_"}, value = {
+ EX_TYPE_FILTER_NONE,
+ EX_TYPE_FILTER_NETWORK_RELEASED,
+ EX_TYPE_FILTER_SOCKET_NOT_BOUND,
+ EX_TYPE_FILTER_NOT_SUPPORTED,
+ EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ExceptionType {}
+
+ private static final String TAG = "QosCallbackException";
+
+ // Types of exceptions supported //
+ /** {@hide} */
+ public static final int EX_TYPE_FILTER_NONE = 0;
+
+ /** {@hide} */
+ public static final int EX_TYPE_FILTER_NETWORK_RELEASED = 1;
+
+ /** {@hide} */
+ public static final int EX_TYPE_FILTER_SOCKET_NOT_BOUND = 2;
+
+ /** {@hide} */
+ public static final int EX_TYPE_FILTER_NOT_SUPPORTED = 3;
+
+ /** {@hide} */
+ public static final int EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED = 4;
+
+ /**
+ * Creates exception based off of a type and message. Not all types of exceptions accept a
+ * custom message.
+ *
+ * {@hide}
+ */
+ @NonNull
+ static QosCallbackException createException(@ExceptionType final int type) {
+ switch (type) {
+ case EX_TYPE_FILTER_NETWORK_RELEASED:
+ return new QosCallbackException(new NetworkReleasedException());
+ case EX_TYPE_FILTER_SOCKET_NOT_BOUND:
+ return new QosCallbackException(new SocketNotBoundException());
+ case EX_TYPE_FILTER_NOT_SUPPORTED:
+ return new QosCallbackException(new UnsupportedOperationException(
+ "This device does not support the specified filter"));
+ case EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED:
+ return new QosCallbackException(
+ new SocketLocalAddressChangedException());
+ default:
+ Log.wtf(TAG, "create: No case setup for exception type: '" + type + "'");
+ return new QosCallbackException(
+ new RuntimeException("Unknown exception code: " + type));
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public QosCallbackException(@NonNull final String message) {
+ super(message);
+ }
+
+ /**
+ * @hide
+ */
+ public QosCallbackException(@NonNull final Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/core/java/android/net/QosFilter.java b/core/java/android/net/QosFilter.java
new file mode 100644
index 0000000..0705468
--- /dev/null
+++ b/core/java/android/net/QosFilter.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+
+/**
+ * Provides the related filtering logic to the {@link NetworkAgent} to match {@link QosSession}s
+ * to their related {@link QosCallback}.
+ *
+ * Used by the {@link com.android.server.ConnectivityService} to validate a {@link QosCallback}
+ * is still able to receive a {@link QosSession}.
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class QosFilter {
+
+ /**
+ * The constructor is kept hidden from outside this package to ensure that all derived types
+ * are known and properly handled when being passed to and from {@link NetworkAgent}.
+ *
+ * @hide
+ */
+ QosFilter() {
+ }
+
+ /**
+ * The network used with this filter.
+ *
+ * @return the registered {@link Network}
+ */
+ @NonNull
+ public abstract Network getNetwork();
+
+ /**
+ * Validates that conditions have not changed such that no further {@link QosSession}s should
+ * be passed back to the {@link QosCallback} associated to this filter.
+ *
+ * @return the error code when present, otherwise the filter is valid
+ *
+ * @hide
+ */
+ @QosCallbackException.ExceptionType
+ public abstract int validate();
+}
+
diff --git a/core/java/android/net/QosFilterParcelable.aidl b/core/java/android/net/QosFilterParcelable.aidl
new file mode 100644
index 0000000..312d635
--- /dev/null
+++ b/core/java/android/net/QosFilterParcelable.aidl
@@ -0,0 +1,21 @@
+/*
+**
+** Copyright (C) 2020 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.net;
+
+parcelable QosFilterParcelable;
+
diff --git a/core/java/android/net/QosFilterParcelable.java b/core/java/android/net/QosFilterParcelable.java
new file mode 100644
index 0000000..da3b2cf
--- /dev/null
+++ b/core/java/android/net/QosFilterParcelable.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.util.Objects;
+
+/**
+ * Aware of how to parcel different types of {@link QosFilter}s. Any new type of qos filter must
+ * have a specialized case written here.
+ * <p/>
+ * Specifically leveraged when transferring {@link QosFilter} from
+ * {@link com.android.server.ConnectivityService} to {@link NetworkAgent} when the filter is first
+ * registered.
+ * <p/>
+ * This is not meant to be used in other contexts.
+ *
+ * @hide
+ */
+public final class QosFilterParcelable implements Parcelable {
+
+ private static final String LOG_TAG = QosFilterParcelable.class.getSimpleName();
+
+ // Indicates that the filter was not successfully written to the parcel.
+ private static final int NO_FILTER_PRESENT = 0;
+
+ // The parcel is of type qos socket filter.
+ private static final int QOS_SOCKET_FILTER = 1;
+
+ private final QosFilter mQosFilter;
+
+ /**
+ * The underlying qos filter.
+ * <p/>
+ * Null only in the case parceling failed.
+ */
+ @Nullable
+ public QosFilter getQosFilter() {
+ return mQosFilter;
+ }
+
+ public QosFilterParcelable(@NonNull final QosFilter qosFilter) {
+ Objects.requireNonNull(qosFilter, "qosFilter must be non-null");
+
+ // NOTE: Normally a type check would belong here, but doing so breaks unit tests that rely
+ // on mocking qos filter.
+ mQosFilter = qosFilter;
+ }
+
+ private QosFilterParcelable(final Parcel in) {
+ final int filterParcelType = in.readInt();
+
+ switch (filterParcelType) {
+ case QOS_SOCKET_FILTER: {
+ mQosFilter = new QosSocketFilter(QosSocketInfo.CREATOR.createFromParcel(in));
+ break;
+ }
+
+ case NO_FILTER_PRESENT:
+ default: {
+ mQosFilter = null;
+ }
+ }
+ }
+
+ public static final Creator<QosFilterParcelable> CREATOR = new Creator<QosFilterParcelable>() {
+ @Override
+ public QosFilterParcelable createFromParcel(final Parcel in) {
+ return new QosFilterParcelable(in);
+ }
+
+ @Override
+ public QosFilterParcelable[] newArray(final int size) {
+ return new QosFilterParcelable[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(final Parcel dest, final int flags) {
+ if (mQosFilter instanceof QosSocketFilter) {
+ dest.writeInt(QOS_SOCKET_FILTER);
+ final QosSocketFilter qosSocketFilter = (QosSocketFilter) mQosFilter;
+ qosSocketFilter.getQosSocketInfo().writeToParcel(dest, 0);
+ return;
+ }
+ dest.writeInt(NO_FILTER_PRESENT);
+ Log.e(LOG_TAG, "Parceling failed, unknown type of filter present: " + mQosFilter);
+ }
+}
diff --git a/core/java/android/net/QosSession.aidl b/core/java/android/net/QosSession.aidl
new file mode 100644
index 0000000..c2cf366
--- /dev/null
+++ b/core/java/android/net/QosSession.aidl
@@ -0,0 +1,21 @@
+/*
+**
+** Copyright (C) 2020 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.net;
+
+parcelable QosSession;
+
diff --git a/core/java/android/net/QosSession.java b/core/java/android/net/QosSession.java
new file mode 100644
index 0000000..4f3bb77
--- /dev/null
+++ b/core/java/android/net/QosSession.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Provides identifying information of a QoS session. Sent to an application through
+ * {@link QosCallback}.
+ *
+ * @hide
+ */
+@SystemApi
+public final class QosSession implements Parcelable {
+
+ /**
+ * The {@link QosSession} is a LTE EPS Session.
+ */
+ public static final int TYPE_EPS_BEARER = 1;
+
+ private final int mSessionId;
+
+ private final int mSessionType;
+
+ /**
+ * Gets the unique id of the session that is used to differentiate sessions across different
+ * types.
+ * <p/>
+ * Note: Different qos sessions can be provided by different actors.
+ *
+ * @return the unique id
+ */
+ public long getUniqueId() {
+ return (long) mSessionType << 32 | mSessionId;
+ }
+
+ /**
+ * Gets the session id that is unique within that type.
+ * <p/>
+ * Note: The session id is set by the actor providing the qos. It can be either manufactured by
+ * the actor, but also may have a particular meaning within that type. For example, using the
+ * bearer id as the session id for {@link android.telephony.data.EpsBearerQosSessionAttributes}
+ * is a straight forward way to keep the sessions unique from one another within that type.
+ *
+ * @return the id of the session
+ */
+ public int getSessionId() {
+ return mSessionId;
+ }
+
+ /**
+ * Gets the type of session.
+ */
+ @QosSessionType
+ public int getSessionType() {
+ return mSessionType;
+ }
+
+ /**
+ * Creates a {@link QosSession}.
+ *
+ * @param sessionId uniquely identifies the session across all sessions of the same type
+ * @param sessionType the type of session
+ */
+ public QosSession(final int sessionId, @QosSessionType final int sessionType) {
+ //Ensures the session id is unique across types of sessions
+ mSessionId = sessionId;
+ mSessionType = sessionType;
+ }
+
+
+ @Override
+ public String toString() {
+ return "QosSession{"
+ + "mSessionId=" + mSessionId
+ + ", mSessionType=" + mSessionType
+ + '}';
+ }
+
+ /**
+ * Annotations for types of qos sessions.
+ */
+ @IntDef(value = {
+ TYPE_EPS_BEARER,
+ })
+ @interface QosSessionType {}
+
+ private QosSession(final Parcel in) {
+ mSessionId = in.readInt();
+ mSessionType = in.readInt();
+ }
+
+ @NonNull
+ public static final Creator<QosSession> CREATOR = new Creator<QosSession>() {
+ @NonNull
+ @Override
+ public QosSession createFromParcel(@NonNull final Parcel in) {
+ return new QosSession(in);
+ }
+
+ @NonNull
+ @Override
+ public QosSession[] newArray(final int size) {
+ return new QosSession[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull final Parcel dest, final int flags) {
+ dest.writeInt(mSessionId);
+ dest.writeInt(mSessionType);
+ }
+}
diff --git a/core/java/android/net/QosSessionAttributes.java b/core/java/android/net/QosSessionAttributes.java
new file mode 100644
index 0000000..7a88594
--- /dev/null
+++ b/core/java/android/net/QosSessionAttributes.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.SystemApi;
+
+/**
+ * Implemented by classes that encapsulate Qos related attributes that describe a Qos Session.
+ *
+ * Use the instanceof keyword to determine the underlying type.
+ *
+ * @hide
+ */
+@SystemApi
+public interface QosSessionAttributes {
+}
diff --git a/core/java/android/net/QosSocketFilter.java b/core/java/android/net/QosSocketFilter.java
new file mode 100644
index 0000000..f51a088
--- /dev/null
+++ b/core/java/android/net/QosSocketFilter.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import static android.net.QosCallbackException.EX_TYPE_FILTER_NONE;
+import static android.net.QosCallbackException.EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.util.Objects;
+
+/**
+ * Filters a {@link QosSession} according to the binding on the provided {@link Socket}.
+ *
+ * @hide
+ */
+public class QosSocketFilter extends QosFilter {
+
+ private static final String TAG = QosSocketFilter.class.getSimpleName();
+
+ @NonNull
+ private final QosSocketInfo mQosSocketInfo;
+
+ /**
+ * Creates a {@link QosSocketFilter} based off of {@link QosSocketInfo}.
+ *
+ * @param qosSocketInfo the information required to filter and validate
+ */
+ public QosSocketFilter(@NonNull final QosSocketInfo qosSocketInfo) {
+ Objects.requireNonNull(qosSocketInfo, "qosSocketInfo must be non-null");
+ mQosSocketInfo = qosSocketInfo;
+ }
+
+ /**
+ * Gets the parcelable qos socket info that was used to create the filter.
+ */
+ @NonNull
+ public QosSocketInfo getQosSocketInfo() {
+ return mQosSocketInfo;
+ }
+
+ /**
+ * Performs two validations:
+ * 1. If the socket is not bound, then return
+ * {@link QosCallbackException.EX_TYPE_FILTER_SOCKET_NOT_BOUND}. This is detected
+ * by checking the local address on the filter which becomes null when the socket is no
+ * longer bound.
+ * 2. In the scenario that the socket is now bound to a different local address, which can
+ * happen in the case of UDP, then
+ * {@link QosCallbackException.EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED} is returned.
+ * @return validation error code
+ */
+ @Override
+ public int validate() {
+ final InetSocketAddress sa = getAddressFromFileDescriptor();
+ if (sa == null) {
+ return QosCallbackException.EX_TYPE_FILTER_SOCKET_NOT_BOUND;
+ }
+
+ if (!sa.equals(mQosSocketInfo.getLocalSocketAddress())) {
+ return EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED;
+ }
+
+ return EX_TYPE_FILTER_NONE;
+ }
+
+ /**
+ * The local address of the socket's binding.
+ *
+ * Note: If the socket is no longer bound, null is returned.
+ *
+ * @return the local address
+ */
+ @Nullable
+ private InetSocketAddress getAddressFromFileDescriptor() {
+ final ParcelFileDescriptor parcelFileDescriptor = mQosSocketInfo.getParcelFileDescriptor();
+ if (parcelFileDescriptor == null) return null;
+
+ final FileDescriptor fd = parcelFileDescriptor.getFileDescriptor();
+ if (fd == null) return null;
+
+ final SocketAddress address;
+ try {
+ address = Os.getsockname(fd);
+ } catch (final ErrnoException e) {
+ Log.e(TAG, "getAddressFromFileDescriptor: getLocalAddress exception", e);
+ return null;
+ }
+ if (address instanceof InetSocketAddress) {
+ return (InetSocketAddress) address;
+ }
+ return null;
+ }
+
+ /**
+ * The network used with this filter.
+ *
+ * @return the registered {@link Network}
+ */
+ @NonNull
+ @Override
+ public Network getNetwork() {
+ return mQosSocketInfo.getNetwork();
+ }
+}
diff --git a/core/java/android/net/QosSocketInfo.aidl b/core/java/android/net/QosSocketInfo.aidl
new file mode 100644
index 0000000..476c090
--- /dev/null
+++ b/core/java/android/net/QosSocketInfo.aidl
@@ -0,0 +1,21 @@
+/*
+**
+** Copyright (C) 2020 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.net;
+
+parcelable QosSocketInfo;
+
diff --git a/core/java/android/net/QosSocketInfo.java b/core/java/android/net/QosSocketInfo.java
new file mode 100644
index 0000000..d37c469
--- /dev/null
+++ b/core/java/android/net/QosSocketInfo.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.util.Objects;
+
+/**
+ * Used in conjunction with
+ * {@link ConnectivityManager#registerQosCallback}
+ * in order to receive Qos Sessions related to the local address and port of a bound {@link Socket}.
+ *
+ * @hide
+ */
+@SystemApi
+public final class QosSocketInfo implements Parcelable {
+
+ @NonNull
+ private final Network mNetwork;
+
+ @NonNull
+ private final ParcelFileDescriptor mParcelFileDescriptor;
+
+ @NonNull
+ private final InetSocketAddress mLocalSocketAddress;
+
+ /**
+ * The {@link Network} the socket is on.
+ *
+ * @return the registered {@link Network}
+ */
+ @NonNull
+ public Network getNetwork() {
+ return mNetwork;
+ }
+
+ /**
+ * The parcel file descriptor wrapped around the socket's file descriptor.
+ *
+ * @return the parcel file descriptor of the socket
+ */
+ @NonNull
+ ParcelFileDescriptor getParcelFileDescriptor() {
+ return mParcelFileDescriptor;
+ }
+
+ /**
+ * The local address of the socket passed into {@link QosSocketInfo(Network, Socket)}.
+ * The value does not reflect any changes that occur to the socket after it is first set
+ * in the constructor.
+ *
+ * @return the local address of the socket
+ */
+ @NonNull
+ public InetSocketAddress getLocalSocketAddress() {
+ return mLocalSocketAddress;
+ }
+
+ /**
+ * Creates a {@link QosSocketInfo} given a {@link Network} and bound {@link Socket}. The
+ * {@link Socket} must remain bound in order to receive {@link QosSession}s.
+ *
+ * @param network the network
+ * @param socket the bound {@link Socket}
+ */
+ public QosSocketInfo(@NonNull final Network network, @NonNull final Socket socket)
+ throws IOException {
+ Objects.requireNonNull(socket, "socket cannot be null");
+
+ mNetwork = Objects.requireNonNull(network, "network cannot be null");
+ mParcelFileDescriptor = ParcelFileDescriptor.dup(socket.getFileDescriptor$());
+ mLocalSocketAddress =
+ new InetSocketAddress(socket.getLocalAddress(), socket.getLocalPort());
+ }
+
+ /* Parcelable methods */
+ private QosSocketInfo(final Parcel in) {
+ mNetwork = Objects.requireNonNull(Network.CREATOR.createFromParcel(in));
+ mParcelFileDescriptor = ParcelFileDescriptor.CREATOR.createFromParcel(in);
+
+ final int addressLength = in.readInt();
+ mLocalSocketAddress = readSocketAddress(in, addressLength);
+ }
+
+ private InetSocketAddress readSocketAddress(final Parcel in, final int addressLength) {
+ final byte[] address = new byte[addressLength];
+ in.readByteArray(address);
+ final int port = in.readInt();
+
+ try {
+ return new InetSocketAddress(InetAddress.getByAddress(address), port);
+ } catch (final UnknownHostException e) {
+ /* The catch block was purposely left empty. UnknownHostException will never be thrown
+ since the address provided is numeric and non-null. */
+ }
+ return new InetSocketAddress();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull final Parcel dest, final int flags) {
+ mNetwork.writeToParcel(dest, 0);
+ mParcelFileDescriptor.writeToParcel(dest, 0);
+
+ final byte[] address = mLocalSocketAddress.getAddress().getAddress();
+ dest.writeInt(address.length);
+ dest.writeByteArray(address);
+ dest.writeInt(mLocalSocketAddress.getPort());
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<QosSocketInfo> CREATOR =
+ new Parcelable.Creator<QosSocketInfo>() {
+ @NonNull
+ @Override
+ public QosSocketInfo createFromParcel(final Parcel in) {
+ return new QosSocketInfo(in);
+ }
+
+ @NonNull
+ @Override
+ public QosSocketInfo[] newArray(final int size) {
+ return new QosSocketInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/net/SocketLocalAddressChangedException.java b/core/java/android/net/SocketLocalAddressChangedException.java
new file mode 100644
index 0000000..9daad83
--- /dev/null
+++ b/core/java/android/net/SocketLocalAddressChangedException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.SystemApi;
+
+/**
+ * Thrown when the local address of the socket has changed.
+ *
+ * @hide
+ */
+@SystemApi
+public class SocketLocalAddressChangedException extends Exception {
+ /** @hide */
+ public SocketLocalAddressChangedException() {
+ super("The local address of the socket changed");
+ }
+}
diff --git a/core/java/android/net/SocketNotBoundException.java b/core/java/android/net/SocketNotBoundException.java
new file mode 100644
index 0000000..b1d7026
--- /dev/null
+++ b/core/java/android/net/SocketNotBoundException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.SystemApi;
+
+/**
+ * Thrown when a previously bound socket becomes unbound.
+ *
+ * @hide
+ */
+@SystemApi
+public class SocketNotBoundException extends Exception {
+ /** @hide */
+ public SocketNotBoundException() {
+ super("The socket is unbound");
+ }
+}
diff --git a/core/java/android/net/TcpSocketKeepalive.java b/core/java/android/net/TcpSocketKeepalive.java
index 436397e..d89814d 100644
--- a/core/java/android/net/TcpSocketKeepalive.java
+++ b/core/java/android/net/TcpSocketKeepalive.java
@@ -21,7 +21,6 @@
import android.os.RemoteException;
import android.util.Log;
-import java.io.FileDescriptor;
import java.util.concurrent.Executor;
/** @hide */
@@ -54,8 +53,7 @@
void startImpl(int intervalSec) {
mExecutor.execute(() -> {
try {
- final FileDescriptor fd = mPfd.getFileDescriptor();
- mService.startTcpKeepalive(mNetwork, fd, intervalSec, mCallback);
+ mService.startTcpKeepalive(mNetwork, mPfd, intervalSec, mCallback);
} catch (RemoteException e) {
Log.e(TAG, "Error starting packet keepalive: ", e);
throw e.rethrowFromSystemServer();
diff --git a/core/java/android/net/TestNetworkInterface.java b/core/java/android/net/TestNetworkInterface.java
index 8455083..4449ff8 100644
--- a/core/java/android/net/TestNetworkInterface.java
+++ b/core/java/android/net/TestNetworkInterface.java
@@ -15,7 +15,8 @@
*/
package android.net;
-import android.annotation.TestApi;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
@@ -25,9 +26,11 @@
*
* @hide
*/
-@TestApi
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public final class TestNetworkInterface implements Parcelable {
+ @NonNull
private final ParcelFileDescriptor mFileDescriptor;
+ @NonNull
private final String mInterfaceName;
@Override
@@ -36,29 +39,32 @@
}
@Override
- public void writeToParcel(Parcel out, int flags) {
+ public void writeToParcel(@NonNull Parcel out, int flags) {
out.writeParcelable(mFileDescriptor, PARCELABLE_WRITE_RETURN_VALUE);
out.writeString(mInterfaceName);
}
- public TestNetworkInterface(ParcelFileDescriptor pfd, String intf) {
+ public TestNetworkInterface(@NonNull ParcelFileDescriptor pfd, @NonNull String intf) {
mFileDescriptor = pfd;
mInterfaceName = intf;
}
- private TestNetworkInterface(Parcel in) {
+ private TestNetworkInterface(@NonNull Parcel in) {
mFileDescriptor = in.readParcelable(ParcelFileDescriptor.class.getClassLoader());
mInterfaceName = in.readString();
}
+ @NonNull
public ParcelFileDescriptor getFileDescriptor() {
return mFileDescriptor;
}
+ @NonNull
public String getInterfaceName() {
return mInterfaceName;
}
+ @NonNull
public static final Parcelable.Creator<TestNetworkInterface> CREATOR =
new Parcelable.Creator<TestNetworkInterface>() {
public TestNetworkInterface createFromParcel(Parcel in) {
diff --git a/core/java/android/net/TestNetworkManager.java b/core/java/android/net/TestNetworkManager.java
index a0a563b..4e89414 100644
--- a/core/java/android/net/TestNetworkManager.java
+++ b/core/java/android/net/TestNetworkManager.java
@@ -17,18 +17,21 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.TestApi;
+import android.annotation.SystemApi;
import android.os.IBinder;
import android.os.RemoteException;
import com.android.internal.util.Preconditions;
+import java.util.Arrays;
+import java.util.Collection;
+
/**
* Class that allows creation and management of per-app, test-only networks
*
* @hide
*/
-@TestApi
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public class TestNetworkManager {
/**
* Prefix for tun interfaces created by this class.
@@ -57,7 +60,7 @@
* @param network The test network that should be torn down
* @hide
*/
- @TestApi
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public void teardownTestNetwork(@NonNull Network network) {
try {
mService.teardownTestNetwork(network.netId);
@@ -102,7 +105,7 @@
* @param binder A binder object guarding the lifecycle of this test network.
* @hide
*/
- @TestApi
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public void setupTestNetwork(@NonNull String iface, @NonNull IBinder binder) {
setupTestNetwork(iface, null, true, new int[0], binder);
}
@@ -127,12 +130,29 @@
* @param linkAddrs an array of LinkAddresses to assign to the TUN interface
* @return A ParcelFileDescriptor of the underlying TUN interface. Close this to tear down the
* TUN interface.
+ * @deprecated Use {@link #createTunInterface(Collection)} instead.
* @hide
*/
- @TestApi
+ @Deprecated
+ @NonNull
public TestNetworkInterface createTunInterface(@NonNull LinkAddress[] linkAddrs) {
+ return createTunInterface(Arrays.asList(linkAddrs));
+ }
+
+ /**
+ * Create a tun interface for testing purposes
+ *
+ * @param linkAddrs an array of LinkAddresses to assign to the TUN interface
+ * @return A ParcelFileDescriptor of the underlying TUN interface. Close this to tear down the
+ * TUN interface.
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @NonNull
+ public TestNetworkInterface createTunInterface(@NonNull Collection<LinkAddress> linkAddrs) {
try {
- return mService.createTunInterface(linkAddrs);
+ final LinkAddress[] arr = new LinkAddress[linkAddrs.size()];
+ return mService.createTunInterface(linkAddrs.toArray(arr));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -145,7 +165,8 @@
* TAP interface.
* @hide
*/
- @TestApi
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @NonNull
public TestNetworkInterface createTapInterface() {
try {
return mService.createTapInterface();
diff --git a/core/java/android/net/util/MultinetworkPolicyTracker.java b/core/java/android/net/util/MultinetworkPolicyTracker.java
index 8dfd4e1..85e3fa3 100644
--- a/core/java/android/net/util/MultinetworkPolicyTracker.java
+++ b/core/java/android/net/util/MultinetworkPolicyTracker.java
@@ -29,7 +29,6 @@
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
-import android.os.UserHandle;
import android.provider.Settings;
import android.telephony.PhoneStateListener;
import android.telephony.SubscriptionManager;
@@ -114,8 +113,8 @@
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
- mContext.registerReceiverAsUser(
- mBroadcastReceiver, UserHandle.ALL, intentFilter, null, mHandler);
+ mContext.registerReceiverForAllUsers(mBroadcastReceiver, intentFilter,
+ null /* broadcastPermission */, mHandler);
reevaluate();
}
diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java
index ba29a15a..71d2177 100644
--- a/core/java/android/os/BatteryConsumer.java
+++ b/core/java/android/os/BatteryConsumer.java
@@ -43,7 +43,10 @@
POWER_COMPONENT_AUDIO,
POWER_COMPONENT_VIDEO,
POWER_COMPONENT_FLASHLIGHT,
+ POWER_COMPONENT_MOBILE_RADIO,
POWER_COMPONENT_SYSTEM_SERVICES,
+ POWER_COMPONENT_SENSORS,
+ POWER_COMPONENT_GNSS,
})
@Retention(RetentionPolicy.SOURCE)
public static @interface PowerComponent {
@@ -57,8 +60,11 @@
public static final int POWER_COMPONENT_VIDEO = 5;
public static final int POWER_COMPONENT_FLASHLIGHT = 6;
public static final int POWER_COMPONENT_SYSTEM_SERVICES = 7;
+ public static final int POWER_COMPONENT_MOBILE_RADIO = 8;
+ public static final int POWER_COMPONENT_SENSORS = 9;
+ public static final int POWER_COMPONENT_GNSS = 10;
- public static final int POWER_COMPONENT_COUNT = 8;
+ public static final int POWER_COMPONENT_COUNT = 11;
public static final int FIRST_CUSTOM_POWER_COMPONENT_ID = 1000;
public static final int LAST_CUSTOM_POWER_COMPONENT_ID = 9999;
@@ -87,6 +93,9 @@
TIME_COMPONENT_BLUETOOTH,
TIME_COMPONENT_CAMERA,
TIME_COMPONENT_FLASHLIGHT,
+ TIME_COMPONENT_MOBILE_RADIO,
+ TIME_COMPONENT_SENSORS,
+ TIME_COMPONENT_GNSS,
})
@Retention(RetentionPolicy.SOURCE)
public static @interface TimeComponent {
@@ -100,8 +109,11 @@
public static final int TIME_COMPONENT_AUDIO = 5;
public static final int TIME_COMPONENT_VIDEO = 6;
public static final int TIME_COMPONENT_FLASHLIGHT = 7;
+ public static final int TIME_COMPONENT_MOBILE_RADIO = 8;
+ public static final int TIME_COMPONENT_SENSORS = 9;
+ public static final int TIME_COMPONENT_GNSS = 10;
- public static final int TIME_COMPONENT_COUNT = 8;
+ public static final int TIME_COMPONENT_COUNT = 11;
public static final int FIRST_CUSTOM_TIME_COMPONENT_ID = 1000;
public static final int LAST_CUSTOM_TIME_COMPONENT_ID = 9999;
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 8148c45..e504946 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -318,6 +318,7 @@
* @see #SDK_INT
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@TestApi
public static final int FIRST_SDK_INT = SystemProperties
.getInt("ro.product.first_api_level", 0);
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 6fe5777..b39c182 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -86,7 +86,7 @@
Bundle getApplicationRestrictionsForUser(in String packageName, int userId);
void setDefaultGuestRestrictions(in Bundle restrictions);
Bundle getDefaultGuestRestrictions();
- int removeUserOrSetEphemeral(int userId);
+ int removeUserOrSetEphemeral(int userId, boolean evenWhenDisallowed);
boolean markGuestForDeletion(int userId);
UserInfo findCurrentGuestUser();
boolean isQuietModeEnabled(int userId);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 814a248..cbb3ba9 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -416,9 +416,21 @@
public static final int GO_TO_SLEEP_REASON_QUIESCENT = 10;
/**
+ * Go to sleep reason code: The last powered on display group has been removed.
* @hide
*/
- public static final int GO_TO_SLEEP_REASON_MAX = GO_TO_SLEEP_REASON_QUIESCENT;
+ public static final int GO_TO_SLEEP_REASON_DISPLAY_GROUP_REMOVED = 11;
+
+ /**
+ * Go to sleep reason code: Every display group has been turned off.
+ * @hide
+ */
+ public static final int GO_TO_SLEEP_REASON_DISPLAY_GROUPS_TURNED_OFF = 12;
+
+ /**
+ * @hide
+ */
+ public static final int GO_TO_SLEEP_REASON_MAX = GO_TO_SLEEP_REASON_DISPLAY_GROUPS_TURNED_OFF;
/**
* @hide
@@ -435,6 +447,8 @@
case GO_TO_SLEEP_REASON_ACCESSIBILITY: return "accessibility";
case GO_TO_SLEEP_REASON_FORCE_SUSPEND: return "force_suspend";
case GO_TO_SLEEP_REASON_INATTENTIVE: return "inattentive";
+ case GO_TO_SLEEP_REASON_DISPLAY_GROUP_REMOVED: return "display_group_removed";
+ case GO_TO_SLEEP_REASON_DISPLAY_GROUPS_TURNED_OFF: return "display_groups_turned_off";
default: return Integer.toString(sleepReason);
}
}
@@ -521,11 +535,32 @@
WAKE_REASON_WAKE_KEY,
WAKE_REASON_WAKE_MOTION,
WAKE_REASON_HDMI,
+ WAKE_REASON_DISPLAY_GROUP_ADDED,
+ WAKE_REASON_DISPLAY_GROUP_TURNED_ON,
})
@Retention(RetentionPolicy.SOURCE)
public @interface WakeReason{}
/**
+ * @hide
+ */
+ @IntDef(prefix = { "GO_TO_SLEEP_REASON_" }, value = {
+ GO_TO_SLEEP_REASON_APPLICATION,
+ GO_TO_SLEEP_REASON_DEVICE_ADMIN,
+ GO_TO_SLEEP_REASON_TIMEOUT,
+ GO_TO_SLEEP_REASON_LID_SWITCH,
+ GO_TO_SLEEP_REASON_POWER_BUTTON,
+ GO_TO_SLEEP_REASON_HDMI,
+ GO_TO_SLEEP_REASON_SLEEP_BUTTON,
+ GO_TO_SLEEP_REASON_ACCESSIBILITY,
+ GO_TO_SLEEP_REASON_FORCE_SUSPEND,
+ GO_TO_SLEEP_REASON_INATTENTIVE,
+ GO_TO_SLEEP_REASON_QUIESCENT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface GoToSleepReason{}
+
+ /**
* Wake up reason code: Waking for an unknown reason.
* @hide
*/
@@ -589,6 +624,18 @@
public static final int WAKE_REASON_LID = 9;
/**
+ * Wake up reason code: Waking due to display group being added.
+ * @hide
+ */
+ public static final int WAKE_REASON_DISPLAY_GROUP_ADDED = 10;
+
+ /**
+ * Wake up reason code: Waking due to display group being powered on.
+ * @hide
+ */
+ public static final int WAKE_REASON_DISPLAY_GROUP_TURNED_ON = 11;
+
+ /**
* Convert the wake reason to a string for debugging purposes.
* @hide
*/
@@ -604,6 +651,8 @@
case WAKE_REASON_WAKE_MOTION: return "WAKE_REASON_WAKE_MOTION";
case WAKE_REASON_HDMI: return "WAKE_REASON_HDMI";
case WAKE_REASON_LID: return "WAKE_REASON_LID";
+ case WAKE_REASON_DISPLAY_GROUP_ADDED: return "WAKE_REASON_DISPLAY_GROUP_ADDED";
+ case WAKE_REASON_DISPLAY_GROUP_TURNED_ON: return "WAKE_REASON_DISPLAY_GROUP_TURNED_ON";
default: return Integer.toString(wakeReason);
}
}
@@ -1195,8 +1244,15 @@
}
}
- /**
- * Forces the device to go to sleep.
+ /**
+ * Forces the {@link com.android.server.display.DisplayGroup#DEFAULT default display group}
+ * to turn off.
+ *
+ * <p>If the {@link com.android.server.display.DisplayGroup#DEFAULT default display group} is
+ * turned on it will be turned off. If all displays are off as a result of this action the
+ * device will be put to sleep. If the {@link com.android.server.display.DisplayGroup#DEFAULT
+ * default display group} is already off then nothing will happen.
+ *
* <p>
* Overrides all the wake locks that are held.
* This is what happens when the power key is pressed to turn off the screen.
@@ -1219,7 +1275,14 @@
}
/**
- * Forces the device to go to sleep.
+ * Forces the {@link com.android.server.display.DisplayGroup#DEFAULT default display group}
+ * to turn off.
+ *
+ * <p>If the {@link com.android.server.display.DisplayGroup#DEFAULT default display group} is
+ * turned on it will be turned off. If all displays are off as a result of this action the
+ * device will be put to sleep. If the {@link com.android.server.display.DisplayGroup#DEFAULT
+ * default display group} is already off then nothing will happen.
+ *
* <p>
* Overrides all the wake locks that are held.
* This is what happens when the power key is pressed to turn off the screen.
@@ -1249,9 +1312,15 @@
}
/**
- * Forces the device to wake up from sleep.
+ * Forces the {@link com.android.server.display.DisplayGroup#DEFAULT default display group}
+ * to turn on.
+ *
+ * <p>If the {@link com.android.server.display.DisplayGroup#DEFAULT default display group} is
+ * turned off it will be turned on. Additionally, if the device is asleep it will be awoken. If
+ * the {@link com.android.server.display.DisplayGroup#DEFAULT default display group} is already
+ * on then nothing will happen.
+ *
* <p>
- * If the device is currently asleep, wakes it up, otherwise does nothing.
* This is what happens when the power key is pressed to turn on the screen.
* </p><p>
* Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
@@ -1274,9 +1343,15 @@
}
/**
- * Forces the device to wake up from sleep.
+ * Forces the {@link com.android.server.display.DisplayGroup#DEFAULT default display group}
+ * to turn on.
+ *
+ * <p>If the {@link com.android.server.display.DisplayGroup#DEFAULT default display group} is
+ * turned off it will be turned on. Additionally, if the device is asleep it will be awoken. If
+ * the {@link com.android.server.display.DisplayGroup#DEFAULT default display group} is already
+ * on then nothing will happen.
+ *
* <p>
- * If the device is currently asleep, wakes it up, otherwise does nothing.
* This is what happens when the power key is pressed to turn on the screen.
* </p><p>
* Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
@@ -1303,9 +1378,13 @@
}
/**
- * Forces the device to wake up from sleep.
+ * Forces the {@link android.view.Display#DEFAULT_DISPLAY default display} to turn on.
+ *
+ * <p>If the {@link android.view.Display#DEFAULT_DISPLAY default display} is turned off it will
+ * be turned on. Additionally, if the device is asleep it will be awoken. If the {@link
+ * android.view.Display#DEFAULT_DISPLAY default display} is already on then nothing will happen.
+ *
* <p>
- * If the device is currently asleep, wakes it up, otherwise does nothing.
* This is what happens when the power key is pressed to turn on the screen.
* </p><p>
* Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index b13be9f..1189fdb 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -52,6 +52,7 @@
import android.os.strictmode.ServiceConnectionLeakedViolation;
import android.os.strictmode.SqliteObjectLeakedViolation;
import android.os.strictmode.UnbufferedIoViolation;
+import android.os.strictmode.UnsafeIntentLaunchViolation;
import android.os.strictmode.UntaggedSocketViolation;
import android.os.strictmode.Violation;
import android.os.strictmode.WebViewMethodCalledOnWrongThreadViolation;
@@ -256,6 +257,7 @@
DETECT_VM_NON_SDK_API_USAGE,
DETECT_VM_IMPLICIT_DIRECT_BOOT,
DETECT_VM_INCORRECT_CONTEXT_USE,
+ DETECT_VM_UNSAFE_INTENT_LAUNCH,
PENALTY_GATHER,
PENALTY_LOG,
PENALTY_DIALOG,
@@ -297,6 +299,8 @@
private static final int DETECT_VM_CREDENTIAL_PROTECTED_WHILE_LOCKED = 1 << 11;
/** @hide */
private static final int DETECT_VM_INCORRECT_CONTEXT_USE = 1 << 12;
+ /** @hide */
+ private static final int DETECT_VM_UNSAFE_INTENT_LAUNCH = 1 << 13;
/** @hide */
private static final int DETECT_VM_ALL = 0x0000ffff;
@@ -854,6 +858,7 @@
* <p>In the Honeycomb release this includes leaks of SQLite cursors, Activities, and
* other closable objects but will likely expand in future releases.
*/
+ @SuppressWarnings("AndroidFrameworkCompatChange")
public @NonNull Builder detectAll() {
detectLeakedSqlLiteObjects();
@@ -885,6 +890,9 @@
if (targetSdk >= Build.VERSION_CODES.R) {
detectIncorrectContextUse();
}
+ if (targetSdk >= Build.VERSION_CODES.S) {
+ detectUnsafeIntentLaunch();
+ }
// TODO: Decide whether to detect non SDK API usage beyond a certain API level.
// TODO: enable detectImplicitDirectBoot() once system is less noisy
@@ -1067,6 +1075,59 @@
}
/**
+ * Detect when your app launches an {@link Intent} which originated
+ * from outside your app.
+ * <p>
+ * Violations may indicate security vulnerabilities in the design of
+ * your app, where a malicious app could trick you into granting
+ * {@link Uri} permissions or launching unexported components. Here
+ * are some typical design patterns that can be used to safely
+ * resolve these violations:
+ * <ul>
+ * <li>The ideal approach is to migrate to using a
+ * {@link android.app.PendingIntent}, which ensures that your launch is
+ * performed using the identity of the original creator, completely
+ * avoiding the security issues described above.
+ * <li>If using a {@link android.app.PendingIntent} isn't feasible, an
+ * alternative approach is to create a brand new {@link Intent} and
+ * carefully copy only specific values from the original
+ * {@link Intent} after careful validation.
+ * </ul>
+ * <p>
+ * Note that this <em>may</em> detect false-positives if your app
+ * sends itself an {@link Intent} which is first routed through the
+ * OS, such as using {@link Intent#createChooser}. In these cases,
+ * careful inspection is required to determine if the return point
+ * into your app is appropriately protected with a signature
+ * permission or marked as unexported. If the return point is not
+ * protected, your app is likely vulnerable to malicious apps.
+ *
+ * @see Context#startActivity(Intent)
+ * @see Context#startService(Intent)
+ * @see Context#bindService(Intent, ServiceConnection, int)
+ * @see Context#sendBroadcast(Intent)
+ * @see android.app.Activity#setResult(int, Intent)
+ */
+ public @NonNull Builder detectUnsafeIntentLaunch() {
+ return enable(DETECT_VM_UNSAFE_INTENT_LAUNCH);
+ }
+
+ /**
+ * Permit your app to launch any {@link Intent} which originated
+ * from outside your app.
+ * <p>
+ * Disabling this check is <em>strongly discouraged</em>, as
+ * violations may indicate security vulnerabilities in the design of
+ * your app, where a malicious app could trick you into granting
+ * {@link Uri} permissions or launching unexported components.
+ *
+ * @see #detectUnsafeIntentLaunch()
+ */
+ public @NonNull Builder permitUnsafeIntentLaunch() {
+ return disable(DETECT_VM_UNSAFE_INTENT_LAUNCH);
+ }
+
+ /**
* Crashes the whole process on violation. This penalty runs at the end of all enabled
* penalties so you'll still get your logging or other violations before the process
* dies.
@@ -2115,6 +2176,11 @@
}
/** @hide */
+ public static boolean vmUnsafeIntentLaunchEnabled() {
+ return (sVmPolicy.mask & DETECT_VM_UNSAFE_INTENT_LAUNCH) != 0;
+ }
+
+ /** @hide */
public static void onSqliteObjectLeaked(String message, Throwable originStack) {
onVmPolicyViolation(new SqliteObjectLeakedViolation(message, originStack));
}
@@ -2221,6 +2287,11 @@
}
}
+ /** @hide */
+ public static void onUnsafeIntentLaunch(Intent intent) {
+ onVmPolicyViolation(new UnsafeIntentLaunchViolation(intent));
+ }
+
/** Assume locked until we hear otherwise */
private static volatile boolean sUserKeyUnlocked = false;
diff --git a/core/java/android/os/SystemBatteryConsumer.java b/core/java/android/os/SystemBatteryConsumer.java
index 08e358f..49bf084 100644
--- a/core/java/android/os/SystemBatteryConsumer.java
+++ b/core/java/android/os/SystemBatteryConsumer.java
@@ -41,7 +41,7 @@
// Reserved: APP
DRAIN_TYPE_BLUETOOTH,
DRAIN_TYPE_CAMERA,
- DRAIN_TYPE_CELL,
+ DRAIN_TYPE_MOBILE_RADIO,
DRAIN_TYPE_FLASHLIGHT,
DRAIN_TYPE_IDLE,
DRAIN_TYPE_MEMORY,
@@ -59,7 +59,7 @@
public static final int DRAIN_TYPE_AMBIENT_DISPLAY = 0;
public static final int DRAIN_TYPE_BLUETOOTH = 2;
public static final int DRAIN_TYPE_CAMERA = 3;
- public static final int DRAIN_TYPE_CELL = 4;
+ public static final int DRAIN_TYPE_MOBILE_RADIO = 4;
public static final int DRAIN_TYPE_FLASHLIGHT = 5;
public static final int DRAIN_TYPE_IDLE = 6;
public static final int DRAIN_TYPE_MEMORY = 7;
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index ed60baf..77183ac 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -4058,14 +4058,18 @@
* the current user, then set the user as ephemeral so that it will be removed when it is
* stopped.
*
+ * @param evenWhenDisallowed when {@code true}, user is removed even if the caller user has the
+ * {@link #DISALLOW_REMOVE_USER} or {@link #DISALLOW_REMOVE_MANAGED_PROFILE} restriction
+ *
* @return the {@link RemoveResult} code
* @hide
*/
@RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
Manifest.permission.CREATE_USERS})
- public @RemoveResult int removeUserOrSetEphemeral(@UserIdInt int userId) {
+ public @RemoveResult int removeUserOrSetEphemeral(@UserIdInt int userId,
+ boolean evenWhenDisallowed) {
try {
- return mService.removeUserOrSetEphemeral(userId);
+ return mService.removeUserOrSetEphemeral(userId, evenWhenDisallowed);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
diff --git a/core/java/android/os/storage/OWNERS b/core/java/android/os/storage/OWNERS
index 8af7de5..7e17a08 100644
--- a/core/java/android/os/storage/OWNERS
+++ b/core/java/android/os/storage/OWNERS
@@ -5,3 +5,6 @@
corinac@google.com
zezeozue@google.com
maco@google.com
+sahanas@google.com
+abkaur@google.com
+chiangi@google.com
diff --git a/core/java/android/os/strictmode/UnsafeIntentLaunchViolation.java b/core/java/android/os/strictmode/UnsafeIntentLaunchViolation.java
new file mode 100644
index 0000000..891fb59
--- /dev/null
+++ b/core/java/android/os/strictmode/UnsafeIntentLaunchViolation.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.strictmode;
+
+import android.annotation.NonNull;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.net.Uri;
+
+/**
+ * Violation raised when your app launches an {@link Intent} which originated
+ * from outside your app.
+ * <p>
+ * Violations may indicate security vulnerabilities in the design of your app,
+ * where a malicious app could trick you into granting {@link Uri} permissions
+ * or launching unexported components. Here are some typical design patterns
+ * that can be used to safely resolve these violations:
+ * <ul>
+ * <li>The ideal approach is to migrate to using a {@link PendingIntent}, which
+ * ensures that your launch is performed using the identity of the original
+ * creator, completely avoiding the security issues described above.
+ * <li>If using a {@link PendingIntent} isn't feasible, an alternative approach
+ * is to create a brand new {@link Intent} and carefully copy only specific
+ * values from the original {@link Intent} after careful validation.
+ * </ul>
+ * <p>
+ * Note that this <em>may</em> detect false-positives if your app sends itself
+ * an {@link Intent} which is first routed through the OS, such as using
+ * {@link Intent#createChooser}. In these cases, careful inspection is required
+ * to determine if the return point into your app is appropriately protected
+ * with a signature permission or marked as unexported. If the return point is
+ * not protected, your app is likely vulnerable to malicious apps.
+ */
+public final class UnsafeIntentLaunchViolation extends Violation {
+ /** @hide */
+ public UnsafeIntentLaunchViolation(@NonNull Intent intent) {
+ super("Launch of unsafe intent: " + intent);
+ }
+}
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index c28b59b..db55e1c 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -662,6 +662,11 @@
// usage for that uid, keep it. Otherwise, remove it
boolean isMostRecentForUid = true;
for (int otherUsageNum = 0; otherUsageNum < rawUsages.size(); otherUsageNum++) {
+ // Do not compare this usage to itself
+ if (otherUsageNum == usageNum) {
+ continue;
+ }
+
OpUsage otherUsage = rawUsages.get(otherUsageNum);
if (otherUsage.uid == usage.uid) {
if (otherUsage.isRunning && !usage.isRunning) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 27ba72b..0bb5365 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -89,8 +89,11 @@
import com.android.internal.widget.ILockSettings;
import java.io.IOException;
+import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Field;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
@@ -99,7 +102,6 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
-
/**
* The Settings provider contains global system-level device preferences.
*/
@@ -2659,22 +2661,30 @@
private final String mCallListCommand;
private final String mCallSetAllCommand;
+ private final ArraySet<String> mReadableFields;
+ private final ArraySet<String> mAllFields;
+
@GuardedBy("this")
private GenerationTracker mGenerationTracker;
- public NameValueCache(Uri uri, String getCommand, String setCommand,
- ContentProviderHolder providerHolder) {
- this(uri, getCommand, setCommand, null, null, providerHolder);
+ <T extends NameValueTable> NameValueCache(Uri uri, String getCommand,
+ String setCommand, ContentProviderHolder providerHolder, Class<T> callerClass) {
+ this(uri, getCommand, setCommand, null, null, providerHolder,
+ callerClass);
}
- NameValueCache(Uri uri, String getCommand, String setCommand, String listCommand,
- String setAllCommand, ContentProviderHolder providerHolder) {
+ private <T extends NameValueTable> NameValueCache(Uri uri, String getCommand,
+ String setCommand, String listCommand, String setAllCommand,
+ ContentProviderHolder providerHolder, Class<T> callerClass) {
mUri = uri;
mCallGetCommand = getCommand;
mCallSetCommand = setCommand;
mCallListCommand = listCommand;
mCallSetAllCommand = setAllCommand;
mProviderHolder = providerHolder;
+ mReadableFields = new ArraySet<>();
+ mAllFields = new ArraySet<>();
+ getPublicSettingsForClass(callerClass, mAllFields, mReadableFields);
}
public boolean putStringForUser(ContentResolver cr, String name, String value,
@@ -2726,6 +2736,18 @@
@UnsupportedAppUsage
public String getStringForUser(ContentResolver cr, String name, final int userHandle) {
+ // Check if the target settings key is readable. Reject if the caller is not system and
+ // is trying to access a settings key defined in the Settings.Secure, Settings.System or
+ // Settings.Global and is not annotated as @Readable.
+ // Notice that a key string that is not defined in any of the Settings.* classes will
+ // still be regarded as readable.
+ if (!Settings.isInSystemServer() && mAllFields.contains(name)
+ && !mReadableFields.contains(name)) {
+ throw new SecurityException(
+ "Settings key: <" + name + "> is not readable. From S+, new public "
+ + "settings keys need to be annotated with @Readable unless they are "
+ + "annotated with @hide.");
+ }
final boolean isSelf = (userHandle == UserHandle.myUserId());
int currentGeneration = -1;
if (isSelf) {
@@ -3061,7 +3083,42 @@
*/
public static boolean canDrawOverlays(Context context) {
return Settings.isCallingPackageAllowedToDrawOverlays(context, Process.myUid(),
- context.getOpPackageName(), false);
+ context.getOpPackageName(), false) || context.checkSelfPermission(
+ Manifest.permission.SYSTEM_APPLICATION_OVERLAY)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
+ /**
+ * This annotation indicates that the value of a setting is allowed to be read
+ * with the get* methods. The following settings should be readable:
+ * 1) all the public settings
+ * 2) all the hidden settings added before S
+ */
+ @Target({ ElementType.FIELD })
+ @Retention(RetentionPolicy.RUNTIME)
+ private @interface Readable {
+ }
+
+ private static <T extends NameValueTable> void getPublicSettingsForClass(
+ Class<T> callerClass, Set<String> allKeys, Set<String> readableKeys) {
+ final Field[] allFields = callerClass.getDeclaredFields();
+ try {
+ for (int i = 0; i < allFields.length; i++) {
+ final Field field = allFields[i];
+ if (!field.getType().equals(String.class)) {
+ continue;
+ }
+ final Object value = field.get(callerClass);
+ if (!value.getClass().equals(String.class)) {
+ continue;
+ }
+ allKeys.add((String) value);
+ if (field.getAnnotation(Readable.class) != null) {
+ readableKeys.add((String) value);
+ }
+ }
+ } catch (IllegalAccessException ignored) {
+ }
}
/**
@@ -3091,7 +3148,8 @@
CONTENT_URI,
CALL_METHOD_GET_SYSTEM,
CALL_METHOD_PUT_SYSTEM,
- sProviderHolder);
+ sProviderHolder,
+ System.class);
@UnsupportedAppUsage
private static final HashSet<String> MOVED_TO_SECURE;
@@ -3145,8 +3203,11 @@
MOVED_TO_SECURE_THEN_GLOBAL.add(Global.BLUETOOTH_ON);
MOVED_TO_SECURE_THEN_GLOBAL.add(Global.DATA_ROAMING);
MOVED_TO_SECURE_THEN_GLOBAL.add(Global.DEVICE_PROVISIONED);
- MOVED_TO_SECURE_THEN_GLOBAL.add(Global.USB_MASS_STORAGE_ENABLED);
MOVED_TO_SECURE_THEN_GLOBAL.add(Global.HTTP_PROXY);
+ MOVED_TO_SECURE_THEN_GLOBAL.add(Global.NETWORK_PREFERENCE);
+ MOVED_TO_SECURE_THEN_GLOBAL.add(Global.USB_MASS_STORAGE_ENABLED);
+ MOVED_TO_SECURE_THEN_GLOBAL.add(Global.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS);
+ MOVED_TO_SECURE_THEN_GLOBAL.add(Global.WIFI_MAX_DHCP_RETRY_COUNT);
// these are moving directly from system to global
MOVED_TO_GLOBAL.add(Settings.Global.AIRPLANE_MODE_ON);
@@ -3184,6 +3245,12 @@
MOVED_TO_GLOBAL.add(Settings.Global.SMS_SHORT_CODES_UPDATE_METADATA_URL);
MOVED_TO_GLOBAL.add(Settings.Global.CERT_PIN_UPDATE_CONTENT_URL);
MOVED_TO_GLOBAL.add(Settings.Global.CERT_PIN_UPDATE_METADATA_URL);
+ MOVED_TO_GLOBAL.add(Settings.Global.RADIO_NFC);
+ MOVED_TO_GLOBAL.add(Settings.Global.RADIO_CELL);
+ MOVED_TO_GLOBAL.add(Settings.Global.RADIO_WIFI);
+ MOVED_TO_GLOBAL.add(Settings.Global.RADIO_BLUETOOTH);
+ MOVED_TO_GLOBAL.add(Settings.Global.RADIO_WIMAX);
+ MOVED_TO_GLOBAL.add(Settings.Global.SHOW_PROCESSES);
}
/** @hide */
@@ -3208,6 +3275,11 @@
sNameValueCache.clearGenerationTrackerForTest();
}
+ /** @hide */
+ public static void getPublicSettings(Set<String> allKeys, Set<String> readableKeys) {
+ getPublicSettingsForClass(System.class, allKeys, readableKeys);
+ }
+
/**
* Look up a name in the database.
* @param resolver to access the database with
@@ -3232,6 +3304,7 @@
+ " to android.provider.Settings.Global, returning read-only value.");
return Global.getStringForUser(resolver, name, userHandle);
}
+
return sNameValueCache.getStringForUser(resolver, name, userHandle);
}
@@ -3709,6 +3782,7 @@
* 3 - The end button goes to the home screen. If the user is already on the
* home screen, it puts the device to sleep.
*/
+ @Readable
public static final String END_BUTTON_BEHAVIOR = "end_button_behavior";
/**
@@ -3733,6 +3807,7 @@
* Is advanced settings mode turned on. 0 == no, 1 == yes
* @hide
*/
+ @Readable
public static final String ADVANCED_SETTINGS = "advanced_settings";
/**
@@ -3833,6 +3908,7 @@
* @deprecated Use {@link WifiManager} instead
*/
@Deprecated
+ @Readable
public static final String WIFI_USE_STATIC_IP = "wifi_use_static_ip";
/**
@@ -3843,6 +3919,7 @@
* @deprecated Use {@link WifiManager} instead
*/
@Deprecated
+ @Readable
public static final String WIFI_STATIC_IP = "wifi_static_ip";
/**
@@ -3853,6 +3930,7 @@
* @deprecated Use {@link WifiManager} instead
*/
@Deprecated
+ @Readable
public static final String WIFI_STATIC_GATEWAY = "wifi_static_gateway";
/**
@@ -3863,6 +3941,7 @@
* @deprecated Use {@link WifiManager} instead
*/
@Deprecated
+ @Readable
public static final String WIFI_STATIC_NETMASK = "wifi_static_netmask";
/**
@@ -3873,6 +3952,7 @@
* @deprecated Use {@link WifiManager} instead
*/
@Deprecated
+ @Readable
public static final String WIFI_STATIC_DNS1 = "wifi_static_dns1";
/**
@@ -3883,6 +3963,7 @@
* @deprecated Use {@link WifiManager} instead
*/
@Deprecated
+ @Readable
public static final String WIFI_STATIC_DNS2 = "wifi_static_dns2";
/**
@@ -3893,6 +3974,7 @@
* 1 -- connectable but not discoverable
* 0 -- neither connectable nor discoverable
*/
+ @Readable
public static final String BLUETOOTH_DISCOVERABILITY =
"bluetooth_discoverability";
@@ -3901,6 +3983,7 @@
* Bluetooth becomes discoverable for a certain number of seconds,
* after which is becomes simply connectable. The value is in seconds.
*/
+ @Readable
public static final String BLUETOOTH_DISCOVERABILITY_TIMEOUT =
"bluetooth_discoverability_timeout";
@@ -3934,11 +4017,13 @@
* @deprecated Use {@link android.app.AlarmManager#getNextAlarmClock()}.
*/
@Deprecated
+ @Readable
public static final String NEXT_ALARM_FORMATTED = "next_alarm_formatted";
/**
* Scaling factor for fonts, float.
*/
+ @Readable
public static final String FONT_SCALE = "font_scale";
/**
@@ -3950,6 +4035,7 @@
* instead.
* @hide
*/
+ @Readable
public static final String SYSTEM_LOCALES = "system_locales";
@@ -3975,12 +4061,14 @@
* @deprecated This setting is no longer used.
*/
@Deprecated
+ @Readable
public static final String DIM_SCREEN = "dim_screen";
/**
* The display color mode.
* @hide
*/
+ @Readable
public static final String DISPLAY_COLOR_MODE = "display_color_mode";
/**
@@ -3989,6 +4077,7 @@
* If this isn't set, 0 will be used.
* @hide
*/
+ @Readable
public static final String MIN_REFRESH_RATE = "min_refresh_rate";
/**
@@ -3997,6 +4086,7 @@
* If this isn't set, the system falls back to a device specific default.
* @hide
*/
+ @Readable
public static final String PEAK_REFRESH_RATE = "peak_refresh_rate";
/**
@@ -4009,23 +4099,27 @@
* This value is bounded by maximum timeout set by
* {@link android.app.admin.DevicePolicyManager#setMaximumTimeToLock(ComponentName, long)}.
*/
+ @Readable
public static final String SCREEN_OFF_TIMEOUT = "screen_off_timeout";
/**
* The screen backlight brightness between 0 and 255.
*/
+ @Readable
public static final String SCREEN_BRIGHTNESS = "screen_brightness";
/**
* The screen backlight brightness between 0 and 255.
* @hide
*/
+ @Readable
public static final String SCREEN_BRIGHTNESS_FOR_VR = "screen_brightness_for_vr";
/**
* The screen backlight brightness between 0.0f and 1.0f.
* @hide
*/
+ @Readable
public static final String SCREEN_BRIGHTNESS_FOR_VR_FLOAT =
"screen_brightness_for_vr_float";
@@ -4033,11 +4127,13 @@
* The screen backlight brightness between 0.0f and 1.0f.
* @hide
*/
+ @Readable
public static final String SCREEN_BRIGHTNESS_FLOAT = "screen_brightness_float";
/**
* Control whether to enable automatic brightness mode.
*/
+ @Readable
public static final String SCREEN_BRIGHTNESS_MODE = "screen_brightness_mode";
/**
@@ -4046,6 +4142,7 @@
* @hide
*/
@UnsupportedAppUsage
+ @Readable
public static final String SCREEN_AUTO_BRIGHTNESS_ADJ = "screen_auto_brightness_adj";
/**
@@ -4089,6 +4186,7 @@
* stream type's bit should be set to 1 if it should be muted when going
* into an inaudible ringer mode.
*/
+ @Readable
public static final String MODE_RINGER_STREAMS_AFFECTED = "mode_ringer_streams_affected";
/**
@@ -4096,12 +4194,14 @@
* stream type's bit should be set to 1 if it should be muted when a mute request
* is received.
*/
+ @Readable
public static final String MUTE_STREAMS_AFFECTED = "mute_streams_affected";
/**
* Whether vibrate is on for different events. This is used internally,
* changing this value will not change the vibrate. See AudioManager.
*/
+ @Readable
public static final String VIBRATE_ON = "vibrate_on";
/**
@@ -4116,6 +4216,7 @@
*
* @hide
*/
+ @Readable
public static final String VIBRATE_INPUT_DEVICES = "vibrate_input_devices";
/**
@@ -4132,6 +4233,7 @@
* 3 - Strong vibrations
* @hide
*/
+ @Readable
public static final String NOTIFICATION_VIBRATION_INTENSITY =
"notification_vibration_intensity";
/**
@@ -4148,6 +4250,7 @@
* 3 - Strong vibrations
* @hide
*/
+ @Readable
public static final String RING_VIBRATION_INTENSITY =
"ring_vibration_intensity";
@@ -4165,6 +4268,7 @@
* 3 - Strong vibrations
* @hide
*/
+ @Readable
public static final String HAPTIC_FEEDBACK_INTENSITY =
"haptic_feedback_intensity";
@@ -4174,6 +4278,7 @@
*
* @removed Not used by anything since API 2.
*/
+ @Readable
public static final String VOLUME_RING = "volume_ring";
/**
@@ -4182,6 +4287,7 @@
*
* @removed Not used by anything since API 2.
*/
+ @Readable
public static final String VOLUME_SYSTEM = "volume_system";
/**
@@ -4190,6 +4296,7 @@
*
* @removed Not used by anything since API 2.
*/
+ @Readable
public static final String VOLUME_VOICE = "volume_voice";
/**
@@ -4198,6 +4305,7 @@
*
* @removed Not used by anything since API 2.
*/
+ @Readable
public static final String VOLUME_MUSIC = "volume_music";
/**
@@ -4206,6 +4314,7 @@
*
* @removed Not used by anything since API 2.
*/
+ @Readable
public static final String VOLUME_ALARM = "volume_alarm";
/**
@@ -4214,6 +4323,7 @@
*
* @removed Not used by anything since API 2.
*/
+ @Readable
public static final String VOLUME_NOTIFICATION = "volume_notification";
/**
@@ -4222,6 +4332,7 @@
*
* @removed Not used by anything since API 2.
*/
+ @Readable
public static final String VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco";
/**
@@ -4229,12 +4340,14 @@
* Acessibility volume. This is used internally, changing this
* value will not change the volume.
*/
+ @Readable
public static final String VOLUME_ACCESSIBILITY = "volume_a11y";
/**
* @hide
* Volume index for virtual assistant.
*/
+ @Readable
public static final String VOLUME_ASSISTANT = "volume_assistant";
/**
@@ -4242,6 +4355,7 @@
*
* @hide
*/
+ @Readable
public static final String VOLUME_MASTER = "volume_master";
/**
@@ -4250,6 +4364,7 @@
* @hide
*/
@UnsupportedAppUsage
+ @Readable
public static final String MASTER_MONO = "master_mono";
/**
@@ -4257,6 +4372,7 @@
*
* @hide
*/
+ @Readable
public static final String MASTER_BALANCE = "master_balance";
/**
@@ -4274,6 +4390,7 @@
* @deprecated
*/
@Deprecated
+ @Readable
public static final String NOTIFICATIONS_USE_RING_VOLUME =
"notifications_use_ring_volume";
@@ -4290,6 +4407,7 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @Readable
public static final String VIBRATE_IN_SILENT = "vibrate_in_silent";
/**
@@ -4325,6 +4443,7 @@
*
* @removed Not used by anything since API 2.
*/
+ @Readable
public static final String APPEND_FOR_LAST_AUDIBLE = "_last_audible";
/**
@@ -4336,6 +4455,7 @@
*
* @see #DEFAULT_RINGTONE_URI
*/
+ @Readable
public static final String RINGTONE = "ringtone";
/**
@@ -4359,6 +4479,7 @@
* @see #RINGTONE
* @see #DEFAULT_NOTIFICATION_URI
*/
+ @Readable
public static final String NOTIFICATION_SOUND = "notification_sound";
/**
@@ -4380,6 +4501,7 @@
* @see #RINGTONE
* @see #DEFAULT_ALARM_ALERT_URI
*/
+ @Readable
public static final String ALARM_ALERT = "alarm_alert";
/**
@@ -4400,29 +4522,35 @@
*
* @hide
*/
+ @Readable
public static final String MEDIA_BUTTON_RECEIVER = "media_button_receiver";
/**
* Setting to enable Auto Replace (AutoText) in text editors. 1 = On, 0 = Off
*/
+ @Readable
public static final String TEXT_AUTO_REPLACE = "auto_replace";
/**
* Setting to enable Auto Caps in text editors. 1 = On, 0 = Off
*/
+ @Readable
public static final String TEXT_AUTO_CAPS = "auto_caps";
/**
* Setting to enable Auto Punctuate in text editors. 1 = On, 0 = Off. This
* feature converts two spaces to a "." and space.
*/
+ @Readable
public static final String TEXT_AUTO_PUNCTUATE = "auto_punctuate";
/**
* Setting to showing password characters in text editors. 1 = On, 0 = Off
*/
+ @Readable
public static final String TEXT_SHOW_PASSWORD = "show_password";
+ @Readable
public static final String SHOW_GTALK_SERVICE_STATUS =
"SHOW_GTALK_SERVICE_STATUS";
@@ -4432,6 +4560,7 @@
* @deprecated Use {@link WallpaperManager} instead.
*/
@Deprecated
+ @Readable
public static final String WALLPAPER_ACTIVITY = "wallpaper_activity";
/**
@@ -4453,6 +4582,7 @@
* 12
* 24
*/
+ @Readable
public static final String TIME_12_24 = "time_12_24";
/**
@@ -4461,6 +4591,7 @@
* dd/mm/yyyy
* yyyy/mm/dd
*/
+ @Readable
public static final String DATE_FORMAT = "date_format";
/**
@@ -4470,6 +4601,7 @@
* nonzero = it has been run in the past
* 0 = it has not been run in the past
*/
+ @Readable
public static final String SETUP_WIZARD_HAS_RUN = "setup_wizard_has_run";
/**
@@ -4506,6 +4638,7 @@
* by the application; if 1, it will be used by default unless explicitly
* disabled by the application.
*/
+ @Readable
public static final String ACCELEROMETER_ROTATION = "accelerometer_rotation";
/**
@@ -4516,6 +4649,7 @@
*
* @see Display#getRotation
*/
+ @Readable
public static final String USER_ROTATION = "user_rotation";
/**
@@ -4530,6 +4664,7 @@
* @hide
*/
@UnsupportedAppUsage
+ @Readable
public static final String HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY =
"hide_rotation_lock_toggle_for_accessibility";
@@ -4543,6 +4678,7 @@
* relied on the setting, while this is purely about the vibration setting for incoming
* calls.
*/
+ @Readable
public static final String VIBRATE_WHEN_RINGING = "vibrate_when_ringing";
/**
@@ -4550,6 +4686,7 @@
* {@code 0}, enhanced call blocking functionality is disabled.
* @hide
*/
+ @Readable
public static final String DEBUG_ENABLE_ENHANCED_CALL_BLOCKING =
"debug.enable_enhanced_calling";
@@ -4557,6 +4694,7 @@
* Whether the audible DTMF tones are played by the dialer when dialing. The value is
* boolean (1 or 0).
*/
+ @Readable
public static final String DTMF_TONE_WHEN_DIALING = "dtmf_tone";
/**
@@ -4565,6 +4703,7 @@
* 0 = Normal
* 1 = Long
*/
+ @Readable
public static final String DTMF_TONE_TYPE_WHEN_DIALING = "dtmf_tone_type";
/**
@@ -4573,6 +4712,7 @@
* @hide
*/
@UnsupportedAppUsage
+ @Readable
public static final String HEARING_AID = "hearing_aid";
/**
@@ -4585,18 +4725,21 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @Readable
public static final String TTY_MODE = "tty_mode";
/**
* Whether the sounds effects (key clicks, lid open ...) are enabled. The value is
* boolean (1 or 0).
*/
+ @Readable
public static final String SOUND_EFFECTS_ENABLED = "sound_effects_enabled";
/**
* Whether haptic feedback (Vibrate on tap) is enabled. The value is
* boolean (1 or 0).
*/
+ @Readable
public static final String HAPTIC_FEEDBACK_ENABLED = "haptic_feedback_enabled";
/**
@@ -4604,6 +4747,7 @@
* setting for this.
*/
@Deprecated
+ @Readable
public static final String SHOW_WEB_SUGGESTIONS = "show_web_suggestions";
/**
@@ -4612,6 +4756,7 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @Readable
public static final String NOTIFICATION_LIGHT_PULSE = "notification_light_pulse";
/**
@@ -4621,6 +4766,7 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @Readable
public static final String POINTER_LOCATION = "pointer_location";
/**
@@ -4630,6 +4776,7 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @Readable
public static final String SHOW_TOUCHES = "show_touches";
/**
@@ -4640,6 +4787,7 @@
* 1 = yes
* @hide
*/
+ @Readable
public static final String WINDOW_ORIENTATION_LISTENER_LOG =
"window_orientation_listener_log";
@@ -4665,12 +4813,14 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @Readable
public static final String LOCKSCREEN_SOUNDS_ENABLED = "lockscreen_sounds_enabled";
/**
* Whether the lockscreen should be completely disabled.
* @hide
*/
+ @Readable
public static final String LOCKSCREEN_DISABLED = "lockscreen.disabled";
/**
@@ -4741,6 +4891,7 @@
* 1 = yes
* @hide
*/
+ @Readable
public static final String SIP_RECEIVE_CALLS = "sip_receive_calls";
/**
@@ -4749,18 +4900,21 @@
* "SIP_ADDRESS_ONLY" : Only if destination is a SIP address
* @hide
*/
+ @Readable
public static final String SIP_CALL_OPTIONS = "sip_call_options";
/**
* One of the sip call options: Always use SIP with network access.
* @hide
*/
+ @Readable
public static final String SIP_ALWAYS = "SIP_ALWAYS";
/**
* One of the sip call options: Only if destination is a SIP address.
* @hide
*/
+ @Readable
public static final String SIP_ADDRESS_ONLY = "SIP_ADDRESS_ONLY";
/**
@@ -4771,6 +4925,7 @@
* @hide
*/
@Deprecated
+ @Readable
public static final String SIP_ASK_ME_EACH_TIME = "SIP_ASK_ME_EACH_TIME";
/**
@@ -4782,12 +4937,14 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @Readable
public static final String POINTER_SPEED = "pointer_speed";
/**
* Whether lock-to-app will be triggered by long-press on recents.
* @hide
*/
+ @Readable
public static final String LOCK_TO_APP_ENABLED = "lock_to_app_enabled";
/**
@@ -4797,6 +4954,7 @@
* Backward-compatible with <code>PrefGetPreference(prefAllowEasterEggs)</code>.
* @hide
*/
+ @Readable
public static final String EGG_MODE = "egg_mode";
/**
@@ -4805,6 +4963,7 @@
* 1 - Show percentage
* @hide
*/
+ @Readable
public static final String SHOW_BATTERY_PERCENT = "status_bar_show_battery_percent";
/**
@@ -4813,6 +4972,7 @@
* for instance pausing media apps when another starts.
* @hide
*/
+ @Readable
public static final String MULTI_AUDIO_FOCUS_ENABLED = "multi_audio_focus_enabled";
/**
@@ -5006,6 +5166,7 @@
* @see android.telephony.TelephonyManager.WifiCallingChoices
* @hide
*/
+ @Readable
public static final String WHEN_TO_MAKE_WIFI_CALLS = "when_to_make_wifi_calls";
// Settings moved to Settings.Secure
@@ -5162,6 +5323,7 @@
* instead
*/
@Deprecated
+ @Readable
public static final String WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE =
Secure.WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE;
@@ -5176,6 +5338,7 @@
* {@link android.provider.Settings.Secure#WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS} instead
*/
@Deprecated
+ @Readable
public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS =
Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS;
@@ -5184,6 +5347,7 @@
* {@link android.provider.Settings.Secure#WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED} instead
*/
@Deprecated
+ @Readable
public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED =
Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED;
@@ -5193,6 +5357,7 @@
* instead
*/
@Deprecated
+ @Readable
public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS =
Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS;
@@ -5201,6 +5366,7 @@
* {@link android.provider.Settings.Secure#WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT} instead
*/
@Deprecated
+ @Readable
public static final String WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT =
Secure.WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT;
@@ -5235,6 +5401,7 @@
* instead
*/
@Deprecated
+ @Readable
public static final String WIFI_WATCHDOG_PING_TIMEOUT_MS =
Secure.WIFI_WATCHDOG_PING_TIMEOUT_MS;
@@ -5284,7 +5451,8 @@
CONTENT_URI,
CALL_METHOD_GET_SECURE,
CALL_METHOD_PUT_SECURE,
- sProviderHolder);
+ sProviderHolder,
+ Secure.class);
private static ILockSettings sLockSettings = null;
@@ -5422,6 +5590,11 @@
sNameValueCache.clearGenerationTrackerForTest();
}
+ /** @hide */
+ public static void getPublicSettings(Set<String> allKeys, Set<String> readableKeys) {
+ getPublicSettingsForClass(Secure.class, allKeys, readableKeys);
+ }
+
/**
* Look up a name in the database.
* @param resolver to access the database with
@@ -5917,6 +6090,7 @@
* Control whether to enable adaptive sleep mode.
* @hide
*/
+ @Readable
public static final String ADAPTIVE_SLEEP = "adaptive_sleep";
/**
@@ -5934,6 +6108,7 @@
* @hide
*/
@Deprecated
+ @Readable
public static final String BUGREPORT_IN_POWER_MENU = "bugreport_in_power_menu";
/**
@@ -5951,6 +6126,7 @@
* @deprecated This settings is not used anymore.
*/
@Deprecated
+ @Readable
public static final String ALLOW_MOCK_LOCATION = "mock_location";
/**
@@ -5959,6 +6135,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String ODI_CAPTIONS_ENABLED = "odi_captions_enabled";
/**
@@ -5998,6 +6175,7 @@
* to the Instant App, it is generated when the Instant App is first installed and reset if
* the user clears the Instant App.
*/
+ @Readable
public static final String ANDROID_ID = "android_id";
/**
@@ -6016,12 +6194,14 @@
* Setting to record the input method used by default, holding the ID
* of the desired method.
*/
+ @Readable
public static final String DEFAULT_INPUT_METHOD = "default_input_method";
/**
* Setting to record the input method subtype used by default, holding the ID
* of the desired method.
*/
+ @Readable
public static final String SELECTED_INPUT_METHOD_SUBTYPE =
"selected_input_method_subtype";
@@ -6030,12 +6210,14 @@
* and its last used subtype.
* @hide
*/
+ @Readable
public static final String INPUT_METHODS_SUBTYPE_HISTORY =
"input_methods_subtype_history";
/**
* Setting to record the visibility of input method selector
*/
+ @Readable
public static final String INPUT_METHOD_SELECTOR_VISIBILITY =
"input_method_selector_visibility";
@@ -6044,6 +6226,7 @@
* @hide
*/
@TestApi
+ @Readable
public static final String VOICE_INTERACTION_SERVICE = "voice_interaction_service";
/**
@@ -6051,6 +6234,7 @@
* @hide
*/
@TestApi
+ @Readable
public static final String AUTOFILL_SERVICE = "autofill_service";
/**
@@ -6061,6 +6245,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String AUTOFILL_FEATURE_FIELD_CLASSIFICATION =
"autofill_field_classification";
@@ -6069,6 +6254,7 @@
*
* @hide
*/
+ @Readable
public static final String DARK_MODE_DIALOG_SEEN =
"dark_mode_dialog_seen";
@@ -6077,6 +6263,7 @@
* Represented as milliseconds from midnight (e.g. 79200000 == 10pm).
* @hide
*/
+ @Readable
public static final String DARK_THEME_CUSTOM_START_TIME =
"dark_theme_custom_start_time";
@@ -6085,6 +6272,7 @@
* Represented as milliseconds from midnight (e.g. 79200000 == 10pm).
* @hide
*/
+ @Readable
public static final String DARK_THEME_CUSTOM_END_TIME =
"dark_theme_custom_end_time";
@@ -6094,6 +6282,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE =
"autofill_user_data_max_user_data_size";
@@ -6104,6 +6293,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE =
"autofill_user_data_max_field_classification_size";
@@ -6114,6 +6304,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT =
"autofill_user_data_max_category_count";
@@ -6123,6 +6314,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String AUTOFILL_USER_DATA_MAX_VALUE_LENGTH =
"autofill_user_data_max_value_length";
@@ -6132,6 +6324,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String AUTOFILL_USER_DATA_MIN_VALUE_LENGTH =
"autofill_user_data_min_value_length";
@@ -6144,6 +6337,7 @@
* @hide
*/
@TestApi
+ @Readable
public static final String CONTENT_CAPTURE_ENABLED = "content_capture_enabled";
/**
@@ -6161,6 +6355,7 @@
*
* @hide
*/
+ @Readable
public static final String MANAGED_PROVISIONING_DPC_DOWNLOADED =
"managed_provisioning_dpc_downloaded";
@@ -6171,6 +6366,7 @@
* <p>
* Type: int (0 for false, 1 for true)
*/
+ @Readable
public static final String SECURE_FRP_MODE = "secure_frp_mode";
/**
@@ -6181,6 +6377,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String USER_SETUP_COMPLETE = "user_setup_complete";
/**
@@ -6236,6 +6433,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String USER_SETUP_PERSONALIZATION_STATE =
"user_setup_personalization_state";
@@ -6246,6 +6444,7 @@
*
* @hide
*/
+ @Readable
public static final String TV_USER_SETUP_COMPLETE = "tv_user_setup_complete";
/**
@@ -6257,6 +6456,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String COMPLETED_CATEGORY_PREFIX = "suggested.completed_category.";
/**
@@ -6267,6 +6467,7 @@
* Format like "ime0;subtype0;subtype1;subtype2:ime1:ime2;subtype0"
* where imeId is ComponentName and subtype is int32.
*/
+ @Readable
public static final String ENABLED_INPUT_METHODS = "enabled_input_methods";
/**
@@ -6275,6 +6476,7 @@
* by ':'.
* @hide
*/
+ @Readable
public static final String DISABLED_SYSTEM_INPUT_METHODS = "disabled_system_input_methods";
/**
@@ -6283,6 +6485,7 @@
* @hide
*/
@TestApi
+ @Readable
@SuppressLint("NoSettingsProvider")
public static final String SHOW_IME_WITH_HARD_KEYBOARD = "show_ime_with_hard_keyboard";
@@ -6300,6 +6503,7 @@
*
* @hide
*/
+ @Readable
public static final String ALWAYS_ON_VPN_APP = "always_on_vpn_app";
/**
@@ -6308,6 +6512,7 @@
*
* @hide
*/
+ @Readable
public static final String ALWAYS_ON_VPN_LOCKDOWN = "always_on_vpn_lockdown";
/**
@@ -6317,6 +6522,7 @@
*
* @hide
*/
+ @Readable
public static final String ALWAYS_ON_VPN_LOCKDOWN_WHITELIST =
"always_on_vpn_lockdown_whitelist";
@@ -6330,6 +6536,8 @@
* {@link PackageManager#canRequestPackageInstalls()}
* @see PackageManager#canRequestPackageInstalls()
*/
+ @Deprecated
+ @Readable
public static final String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
/**
@@ -6341,6 +6549,7 @@
*
* @hide
*/
+ @Readable
public static final String UNKNOWN_SOURCES_DEFAULT_REVERSED =
"unknown_sources_default_reversed";
@@ -6354,6 +6563,7 @@
* instead.
*/
@Deprecated
+ @Readable
public static final String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed";
/**
@@ -6365,12 +6575,14 @@
* {@link LocationManager#MODE_CHANGED_ACTION}.
*/
@Deprecated
+ @Readable
public static final String LOCATION_MODE = "location_mode";
/**
* The App or module that changes the location mode.
* @hide
*/
+ @Readable
public static final String LOCATION_CHANGER = "location_changer";
/**
@@ -6439,6 +6651,7 @@
* android.app.timezonedetector.TimeZoneDetector#updateConfiguration} to update.
* @hide
*/
+ @Readable
public static final String LOCATION_TIME_ZONE_DETECTION_ENABLED =
"location_time_zone_detection_enabled";
@@ -6448,6 +6661,7 @@
*
* @hide
*/
+ @Readable
public static final String LOCATION_COARSE_ACCURACY_M = "locationCoarseAccuracy";
/**
@@ -6455,6 +6669,7 @@
* @hide
*/
@Deprecated
+ @Readable
public static final String LOCK_BIOMETRIC_WEAK_FLAGS =
"lock_biometric_weak_flags";
@@ -6462,6 +6677,7 @@
* Whether lock-to-app will lock the keyguard when exiting.
* @hide
*/
+ @Readable
public static final String LOCK_TO_APP_EXIT_LOCKED = "lock_to_app_exit_locked";
/**
@@ -6472,6 +6688,7 @@
* {@link VERSION_CODES#M} or later throws a {@code SecurityException}.
*/
@Deprecated
+ @Readable
public static final String LOCK_PATTERN_ENABLED = "lock_pattern_autolock";
/**
@@ -6481,6 +6698,7 @@
* {@link VERSION_CODES#M} or later throws a {@code SecurityException}.
*/
@Deprecated
+ @Readable
public static final String LOCK_PATTERN_VISIBLE = "lock_pattern_visible_pattern";
/**
@@ -6494,6 +6712,7 @@
* {@link VERSION_CODES#M} or later throws a {@code SecurityException}.
*/
@Deprecated
+ @Readable
public static final String
LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED = "lock_pattern_tactile_feedback_enabled";
@@ -6503,6 +6722,7 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @Readable
public static final String LOCK_SCREEN_LOCK_AFTER_TIMEOUT = "lock_screen_lock_after_timeout";
@@ -6512,6 +6732,7 @@
* @deprecated
*/
@Deprecated
+ @Readable
public static final String LOCK_SCREEN_OWNER_INFO = "lock_screen_owner_info";
/**
@@ -6519,6 +6740,7 @@
* @hide
*/
@Deprecated
+ @Readable
public static final String LOCK_SCREEN_APPWIDGET_IDS =
"lock_screen_appwidget_ids";
@@ -6527,6 +6749,7 @@
* @hide
*/
@Deprecated
+ @Readable
public static final String LOCK_SCREEN_FALLBACK_APPWIDGET_ID =
"lock_screen_fallback_appwidget_id";
@@ -6535,6 +6758,7 @@
* @hide
*/
@Deprecated
+ @Readable
public static final String LOCK_SCREEN_STICKY_APPWIDGET =
"lock_screen_sticky_appwidget";
@@ -6545,6 +6769,7 @@
*/
@Deprecated
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @Readable
public static final String LOCK_SCREEN_OWNER_INFO_ENABLED =
"lock_screen_owner_info_enabled";
@@ -6557,6 +6782,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS =
"lock_screen_allow_private_notifications";
@@ -6565,6 +6791,7 @@
* without having to unlock
* @hide
*/
+ @Readable
public static final String LOCK_SCREEN_ALLOW_REMOTE_INPUT =
"lock_screen_allow_remote_input";
@@ -6574,12 +6801,14 @@
* {"clock": id, "_applied_timestamp": timestamp}
* @hide
*/
+ @Readable
public static final String LOCK_SCREEN_CUSTOM_CLOCK_FACE = "lock_screen_custom_clock_face";
/**
* Indicates which clock face to show on lock screen and AOD while docked.
* @hide
*/
+ @Readable
public static final String DOCKED_CLOCK_FACE = "docked_clock_face";
/**
@@ -6587,6 +6816,7 @@
* the lockscreen notification policy.
* @hide
*/
+ @Readable
public static final String SHOW_NOTE_ABOUT_NOTIFICATION_HIDING =
"show_note_about_notification_hiding";
@@ -6594,6 +6824,7 @@
* Set to 1 by the system after trust agents have been initialized.
* @hide
*/
+ @Readable
public static final String TRUST_AGENTS_INITIALIZED =
"trust_agents_initialized";
@@ -6604,6 +6835,7 @@
* many collisions. It should not be used.
*/
@Deprecated
+ @Readable
public static final String LOGGING_ID = "logging_id";
/**
@@ -6615,16 +6847,19 @@
/**
* No longer supported.
*/
+ @Readable
public static final String PARENTAL_CONTROL_ENABLED = "parental_control_enabled";
/**
* No longer supported.
*/
+ @Readable
public static final String PARENTAL_CONTROL_LAST_UPDATE = "parental_control_last_update";
/**
* No longer supported.
*/
+ @Readable
public static final String PARENTAL_CONTROL_REDIRECT_URL = "parental_control_redirect_url";
/**
@@ -6633,6 +6868,7 @@
* and new Settings apps.
*/
// TODO: 881807
+ @Readable
public static final String SETTINGS_CLASSNAME = "settings_classname";
/**
@@ -6650,12 +6886,14 @@
/**
* If accessibility is enabled.
*/
+ @Readable
public static final String ACCESSIBILITY_ENABLED = "accessibility_enabled";
/**
* Setting specifying if the accessibility shortcut is enabled.
* @hide
*/
+ @Readable
public static final String ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN =
"accessibility_shortcut_on_lock_screen";
@@ -6663,6 +6901,7 @@
* Setting specifying if the accessibility shortcut dialog has been shown to this user.
* @hide
*/
+ @Readable
public static final String ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN =
"accessibility_shortcut_dialog_shown";
@@ -6677,6 +6916,7 @@
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@TestApi
+ @Readable
public static final String ACCESSIBILITY_SHORTCUT_TARGET_SERVICE =
"accessibility_shortcut_target_service";
@@ -6687,6 +6927,7 @@
* accessibility feature.
* @hide
*/
+ @Readable
public static final String ACCESSIBILITY_BUTTON_TARGET_COMPONENT =
"accessibility_button_target_component";
@@ -6699,6 +6940,7 @@
* accessibility feature.
* @hide
*/
+ @Readable
public static final String ACCESSIBILITY_BUTTON_TARGETS = "accessibility_button_targets";
/**
@@ -6707,17 +6949,20 @@
*
* @hide
*/
+ @Readable
public static final String ACCESSIBILITY_SHORTCUT_TARGET_MAGNIFICATION_CONTROLLER =
"com.android.server.accessibility.MagnificationController";
/**
* If touch exploration is enabled.
*/
+ @Readable
public static final String TOUCH_EXPLORATION_ENABLED = "touch_exploration_enabled";
/**
* List of the enabled accessibility providers.
*/
+ @Readable
public static final String ENABLED_ACCESSIBILITY_SERVICES =
"enabled_accessibility_services";
@@ -6727,6 +6972,7 @@
*
* @hide
*/
+ @Readable
public static final String TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES =
"touch_exploration_granted_accessibility_services";
@@ -6734,12 +6980,14 @@
* Whether the Global Actions Panel is enabled.
* @hide
*/
+ @Readable
public static final String GLOBAL_ACTIONS_PANEL_ENABLED = "global_actions_panel_enabled";
/**
* Whether the Global Actions Panel can be toggled on or off in Settings.
* @hide
*/
+ @Readable
public static final String GLOBAL_ACTIONS_PANEL_AVAILABLE =
"global_actions_panel_available";
@@ -6747,6 +6995,7 @@
* Enables debug mode for the Global Actions Panel.
* @hide
*/
+ @Readable
public static final String GLOBAL_ACTIONS_PANEL_DEBUG_ENABLED =
"global_actions_panel_debug_enabled";
@@ -6755,24 +7004,28 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String HUSH_GESTURE_USED = "hush_gesture_used";
/**
* Number of times the user has manually clicked the ringer toggle
* @hide
*/
+ @Readable
public static final String MANUAL_RINGER_TOGGLE_COUNT = "manual_ringer_toggle_count";
/**
* Whether to play a sound for charging events.
* @hide
*/
+ @Readable
public static final String CHARGING_SOUNDS_ENABLED = "charging_sounds_enabled";
/**
* Whether to vibrate for charging events.
* @hide
*/
+ @Readable
public static final String CHARGING_VIBRATION_ENABLED = "charging_vibration_enabled";
/**
@@ -6782,6 +7035,7 @@
* user to specify a duration.
* @hide
*/
+ @Readable
public static final String ZEN_DURATION = "zen_duration";
/** @hide */ public static final int ZEN_DURATION_PROMPT = -1;
@@ -6791,24 +7045,28 @@
* If nonzero, will show the zen upgrade notification when the user toggles DND on/off.
* @hide
*/
+ @Readable
public static final String SHOW_ZEN_UPGRADE_NOTIFICATION = "show_zen_upgrade_notification";
/**
* If nonzero, will show the zen update settings suggestion.
* @hide
*/
+ @Readable
public static final String SHOW_ZEN_SETTINGS_SUGGESTION = "show_zen_settings_suggestion";
/**
* If nonzero, zen has not been updated to reflect new changes.
* @hide
*/
+ @Readable
public static final String ZEN_SETTINGS_UPDATED = "zen_settings_updated";
/**
* If nonzero, zen setting suggestion has been viewed by user
* @hide
*/
+ @Readable
public static final String ZEN_SETTINGS_SUGGESTION_VIEWED =
"zen_settings_suggestion_viewed";
@@ -6817,6 +7075,7 @@
* boolean (1 or 0).
* @hide
*/
+ @Readable
public static final String IN_CALL_NOTIFICATION_ENABLED = "in_call_notification_enabled";
/**
@@ -6825,6 +7084,7 @@
*
* @hide
*/
+ @Readable
public static final String KEYGUARD_SLICE_URI = "keyguard_slice_uri";
/**
@@ -6837,6 +7097,7 @@
*
* @hide
*/
+ @Readable
public static final String FONT_WEIGHT_ADJUSTMENT = "font_weight_adjustment";
/**
@@ -6847,6 +7108,7 @@
* at all times, which was the behavior when this value was {@code true}.
*/
@Deprecated
+ @Readable
public static final String ACCESSIBILITY_SPEAK_PASSWORD = "speak_password";
/**
@@ -6854,6 +7116,7 @@
*
* @hide
*/
+ @Readable
public static final String ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED =
"high_text_contrast_enabled";
@@ -6867,6 +7130,7 @@
*/
@UnsupportedAppUsage
@TestApi
+ @Readable
public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED =
"accessibility_display_magnification_enabled";
@@ -6882,6 +7146,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED =
"accessibility_display_magnification_navbar_enabled";
@@ -6895,6 +7160,7 @@
*
* @hide
*/
+ @Readable
public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE =
"accessibility_display_magnification_scale";
@@ -6905,6 +7171,7 @@
* @deprecated
*/
@Deprecated
+ @Readable
public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_AUTO_UPDATE =
"accessibility_display_magnification_auto_update";
@@ -6914,6 +7181,7 @@
*
* @hide
*/
+ @Readable
public static final String ACCESSIBILITY_SOFT_KEYBOARD_MODE =
"accessibility_soft_keyboard_mode";
@@ -6947,6 +7215,7 @@
*
* @hide
*/
+ @Readable
public static final String ACCESSIBILITY_CAPTIONING_ENABLED =
"accessibility_captioning_enabled";
@@ -6957,6 +7226,7 @@
* @see java.util.Locale#toString
* @hide
*/
+ @Readable
public static final String ACCESSIBILITY_CAPTIONING_LOCALE =
"accessibility_captioning_locale";
@@ -6971,6 +7241,7 @@
* @see java.util.Locale#toString
* @hide
*/
+ @Readable
public static final String ACCESSIBILITY_CAPTIONING_PRESET =
"accessibility_captioning_preset";
@@ -6981,6 +7252,7 @@
* @see android.graphics.Color#argb
* @hide
*/
+ @Readable
public static final String ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR =
"accessibility_captioning_background_color";
@@ -6991,6 +7263,7 @@
* @see android.graphics.Color#argb
* @hide
*/
+ @Readable
public static final String ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR =
"accessibility_captioning_foreground_color";
@@ -7005,6 +7278,7 @@
* @see #ACCESSIBILITY_CAPTIONING_EDGE_COLOR
* @hide
*/
+ @Readable
public static final String ACCESSIBILITY_CAPTIONING_EDGE_TYPE =
"accessibility_captioning_edge_type";
@@ -7016,6 +7290,7 @@
* @see android.graphics.Color#argb
* @hide
*/
+ @Readable
public static final String ACCESSIBILITY_CAPTIONING_EDGE_COLOR =
"accessibility_captioning_edge_color";
@@ -7026,6 +7301,7 @@
* @see android.graphics.Color#argb
* @hide
*/
+ @Readable
public static final String ACCESSIBILITY_CAPTIONING_WINDOW_COLOR =
"accessibility_captioning_window_color";
@@ -7042,6 +7318,7 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @Readable
public static final String ACCESSIBILITY_CAPTIONING_TYPEFACE =
"accessibility_captioning_typeface";
@@ -7050,12 +7327,14 @@
*
* @hide
*/
+ @Readable
public static final String ACCESSIBILITY_CAPTIONING_FONT_SCALE =
"accessibility_captioning_font_scale";
/**
* Setting that specifies whether display color inversion is enabled.
*/
+ @Readable
public static final String ACCESSIBILITY_DISPLAY_INVERSION_ENABLED =
"accessibility_display_inversion_enabled";
@@ -7066,6 +7345,7 @@
* @hide
*/
@UnsupportedAppUsage
+ @Readable
public static final String ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED =
"accessibility_display_daltonizer_enabled";
@@ -7082,6 +7362,7 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @Readable
public static final String ACCESSIBILITY_DISPLAY_DALTONIZER =
"accessibility_display_daltonizer";
@@ -7092,6 +7373,7 @@
* @hide
*/
@UnsupportedAppUsage
+ @Readable
public static final String ACCESSIBILITY_AUTOCLICK_ENABLED =
"accessibility_autoclick_enabled";
@@ -7102,6 +7384,7 @@
* @see #ACCESSIBILITY_AUTOCLICK_ENABLED
* @hide
*/
+ @Readable
public static final String ACCESSIBILITY_AUTOCLICK_DELAY =
"accessibility_autoclick_delay";
@@ -7112,6 +7395,7 @@
* @hide
*/
@UnsupportedAppUsage
+ @Readable
public static final String ACCESSIBILITY_LARGE_POINTER_ICON =
"accessibility_large_pointer_icon";
@@ -7120,6 +7404,7 @@
* @hide
*/
@UnsupportedAppUsage
+ @Readable
public static final String LONG_PRESS_TIMEOUT = "long_press_timeout";
/**
@@ -7127,6 +7412,7 @@
* down event for an interaction to be considered part of the same multi-press.
* @hide
*/
+ @Readable
public static final String MULTI_PRESS_TIMEOUT = "multi_press_timeout";
/**
@@ -7135,6 +7421,7 @@
*
* @hide
*/
+ @Readable
public static final String ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS =
"accessibility_non_interactive_ui_timeout_ms";
@@ -7144,6 +7431,7 @@
*
* @hide
*/
+ @Readable
public static final String ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS =
"accessibility_interactive_ui_timeout_ms";
@@ -7154,6 +7442,7 @@
*
* @hide
*/
+ @Readable
public static final String REDUCE_BRIGHT_COLORS_ACTIVATED =
"reduce_bright_colors_activated";
@@ -7163,6 +7452,7 @@
*
* @hide
*/
+ @Readable
public static final String REDUCE_BRIGHT_COLORS_LEVEL =
"reduce_bright_colors_level";
@@ -7171,6 +7461,7 @@
*
* @hide
*/
+ @Readable
public static final String REDUCE_BRIGHT_COLORS_PERSIST_ACROSS_REBOOTS =
"reduce_bright_colors_persist_across_reboots";
@@ -7183,6 +7474,7 @@
* @hide
*/
@UnsupportedAppUsage
+ @Readable
public static final String ENABLED_PRINT_SERVICES =
"enabled_print_services";
@@ -7192,6 +7484,7 @@
* @hide
*/
@TestApi
+ @Readable
public static final String DISABLED_PRINT_SERVICES =
"disabled_print_services";
@@ -7202,6 +7495,7 @@
*
* @hide
*/
+ @Readable
public static final String DISPLAY_DENSITY_FORCED = "display_density_forced";
/**
@@ -7214,21 +7508,25 @@
* the framework text to speech APIs as of the Ice Cream Sandwich release.
*/
@Deprecated
+ @Readable
public static final String TTS_USE_DEFAULTS = "tts_use_defaults";
/**
* Default text-to-speech engine speech rate. 100 = 1x
*/
+ @Readable
public static final String TTS_DEFAULT_RATE = "tts_default_rate";
/**
* Default text-to-speech engine pitch. 100 = 1x
*/
+ @Readable
public static final String TTS_DEFAULT_PITCH = "tts_default_pitch";
/**
* Default text-to-speech engine.
*/
+ @Readable
public static final String TTS_DEFAULT_SYNTH = "tts_default_synth";
/**
@@ -7240,6 +7538,7 @@
* locale. {@link TextToSpeech#getLanguage()}.
*/
@Deprecated
+ @Readable
public static final String TTS_DEFAULT_LANG = "tts_default_lang";
/**
@@ -7251,6 +7550,7 @@
* locale. {@link TextToSpeech#getLanguage()}.
*/
@Deprecated
+ @Readable
public static final String TTS_DEFAULT_COUNTRY = "tts_default_country";
/**
@@ -7262,6 +7562,7 @@
* locale that is in use {@link TextToSpeech#getLanguage()}.
*/
@Deprecated
+ @Readable
public static final String TTS_DEFAULT_VARIANT = "tts_default_variant";
/**
@@ -7276,11 +7577,13 @@
*
* @hide
*/
+ @Readable
public static final String TTS_DEFAULT_LOCALE = "tts_default_locale";
/**
* Space delimited list of plugin packages that are enabled.
*/
+ @Readable
public static final String TTS_ENABLED_PLUGINS = "tts_enabled_plugins";
/**
@@ -7320,6 +7623,7 @@
* @deprecated This setting is not used.
*/
@Deprecated
+ @Readable
public static final String WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE =
"wifi_watchdog_acceptable_packet_loss_percentage";
@@ -7329,6 +7633,7 @@
* @deprecated This setting is not used.
*/
@Deprecated
+ @Readable
public static final String WIFI_WATCHDOG_AP_COUNT = "wifi_watchdog_ap_count";
/**
@@ -7336,6 +7641,7 @@
* @deprecated This setting is not used.
*/
@Deprecated
+ @Readable
public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS =
"wifi_watchdog_background_check_delay_ms";
@@ -7345,6 +7651,7 @@
* @deprecated This setting is not used.
*/
@Deprecated
+ @Readable
public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED =
"wifi_watchdog_background_check_enabled";
@@ -7353,6 +7660,7 @@
* @deprecated This setting is not used.
*/
@Deprecated
+ @Readable
public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS =
"wifi_watchdog_background_check_timeout_ms";
@@ -7364,6 +7672,7 @@
* @deprecated This setting is not used.
*/
@Deprecated
+ @Readable
public static final String WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT =
"wifi_watchdog_initial_ignored_ping_count";
@@ -7375,12 +7684,14 @@
* @deprecated This setting is not used.
*/
@Deprecated
+ @Readable
public static final String WIFI_WATCHDOG_MAX_AP_CHECKS = "wifi_watchdog_max_ap_checks";
/**
* @deprecated Use {@link android.provider.Settings.Global#WIFI_WATCHDOG_ON} instead
*/
@Deprecated
+ @Readable
public static final String WIFI_WATCHDOG_ON = "wifi_watchdog_on";
/**
@@ -7388,6 +7699,7 @@
* @deprecated This setting is not used.
*/
@Deprecated
+ @Readable
public static final String WIFI_WATCHDOG_WATCH_LIST = "wifi_watchdog_watch_list";
/**
@@ -7395,6 +7707,7 @@
* @deprecated This setting is not used.
*/
@Deprecated
+ @Readable
public static final String WIFI_WATCHDOG_PING_COUNT = "wifi_watchdog_ping_count";
/**
@@ -7402,6 +7715,7 @@
* @deprecated This setting is not used.
*/
@Deprecated
+ @Readable
public static final String WIFI_WATCHDOG_PING_DELAY_MS = "wifi_watchdog_ping_delay_ms";
/**
@@ -7409,6 +7723,7 @@
* @deprecated This setting is not used.
*/
@Deprecated
+ @Readable
public static final String WIFI_WATCHDOG_PING_TIMEOUT_MS = "wifi_watchdog_ping_timeout_ms";
/**
@@ -7433,6 +7748,7 @@
*
* @hide
*/
+ @Readable
public static final String CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS =
"connectivity_release_pending_intent_delay_ms";
@@ -7446,12 +7762,14 @@
* now appear disconnected.
*/
@Deprecated
+ @Readable
public static final String BACKGROUND_DATA = "background_data";
/**
* Origins for which browsers should allow geolocation by default.
* The value is a space-separated list of origins.
*/
+ @Readable
public static final String ALLOWED_GEOLOCATION_ORIGINS
= "allowed_geolocation_origins";
@@ -7462,6 +7780,7 @@
* 3 = TTY VCO
* @hide
*/
+ @Readable
public static final String PREFERRED_TTY_MODE =
"preferred_tty_mode";
@@ -7471,6 +7790,7 @@
* 1 = enhanced voice privacy
* @hide
*/
+ @Readable
public static final String ENHANCED_VOICE_PRIVACY_ENABLED = "enhanced_voice_privacy_enabled";
/**
@@ -7479,6 +7799,7 @@
* 1 = enabled
* @hide
*/
+ @Readable
public static final String TTY_MODE_ENABLED = "tty_mode_enabled";
/**
@@ -7487,6 +7808,7 @@
* 0 = OFF
* 1 = ON
*/
+ @Readable
public static final String RTT_CALLING_MODE = "rtt_calling_mode";
/**
@@ -7496,6 +7818,7 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @Readable
public static final String BACKUP_ENABLED = "backup_enabled";
/**
@@ -7505,6 +7828,7 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @Readable
public static final String BACKUP_AUTO_RESTORE = "backup_auto_restore";
/**
@@ -7513,6 +7837,7 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @Readable
public static final String BACKUP_PROVISIONED = "backup_provisioned";
/**
@@ -7520,6 +7845,7 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @Readable
public static final String BACKUP_TRANSPORT = "backup_transport";
/**
@@ -7529,6 +7855,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String LAST_SETUP_SHOWN = "last_setup_shown";
/**
@@ -7551,6 +7878,7 @@
*
* @hide
*/
+ @Readable
public static final String SEARCH_GLOBAL_SEARCH_ACTIVITY =
"search_global_search_activity";
@@ -7558,21 +7886,25 @@
* The number of promoted sources in GlobalSearch.
* @hide
*/
+ @Readable
public static final String SEARCH_NUM_PROMOTED_SOURCES = "search_num_promoted_sources";
/**
* The maximum number of suggestions returned by GlobalSearch.
* @hide
*/
+ @Readable
public static final String SEARCH_MAX_RESULTS_TO_DISPLAY = "search_max_results_to_display";
/**
* The number of suggestions GlobalSearch will ask each non-web search source for.
* @hide
*/
+ @Readable
public static final String SEARCH_MAX_RESULTS_PER_SOURCE = "search_max_results_per_source";
/**
* The number of suggestions the GlobalSearch will ask the web search source for.
* @hide
*/
+ @Readable
public static final String SEARCH_WEB_RESULTS_OVERRIDE_LIMIT =
"search_web_results_override_limit";
/**
@@ -7580,69 +7912,81 @@
* promoted sources before continuing with all other sources.
* @hide
*/
+ @Readable
public static final String SEARCH_PROMOTED_SOURCE_DEADLINE_MILLIS =
"search_promoted_source_deadline_millis";
/**
* The number of milliseconds before GlobalSearch aborts search suggesiton queries.
* @hide
*/
+ @Readable
public static final String SEARCH_SOURCE_TIMEOUT_MILLIS = "search_source_timeout_millis";
/**
* The maximum number of milliseconds that GlobalSearch shows the previous results
* after receiving a new query.
* @hide
*/
+ @Readable
public static final String SEARCH_PREFILL_MILLIS = "search_prefill_millis";
/**
* The maximum age of log data used for shortcuts in GlobalSearch.
* @hide
*/
+ @Readable
public static final String SEARCH_MAX_STAT_AGE_MILLIS = "search_max_stat_age_millis";
/**
* The maximum age of log data used for source ranking in GlobalSearch.
* @hide
*/
+ @Readable
public static final String SEARCH_MAX_SOURCE_EVENT_AGE_MILLIS =
"search_max_source_event_age_millis";
/**
* The minimum number of impressions needed to rank a source in GlobalSearch.
* @hide
*/
+ @Readable
public static final String SEARCH_MIN_IMPRESSIONS_FOR_SOURCE_RANKING =
"search_min_impressions_for_source_ranking";
/**
* The minimum number of clicks needed to rank a source in GlobalSearch.
* @hide
*/
+ @Readable
public static final String SEARCH_MIN_CLICKS_FOR_SOURCE_RANKING =
"search_min_clicks_for_source_ranking";
/**
* The maximum number of shortcuts shown by GlobalSearch.
* @hide
*/
+ @Readable
public static final String SEARCH_MAX_SHORTCUTS_RETURNED = "search_max_shortcuts_returned";
/**
* The size of the core thread pool for suggestion queries in GlobalSearch.
* @hide
*/
+ @Readable
public static final String SEARCH_QUERY_THREAD_CORE_POOL_SIZE =
"search_query_thread_core_pool_size";
/**
* The maximum size of the thread pool for suggestion queries in GlobalSearch.
* @hide
*/
+ @Readable
public static final String SEARCH_QUERY_THREAD_MAX_POOL_SIZE =
"search_query_thread_max_pool_size";
/**
* The size of the core thread pool for shortcut refreshing in GlobalSearch.
* @hide
*/
+ @Readable
public static final String SEARCH_SHORTCUT_REFRESH_CORE_POOL_SIZE =
"search_shortcut_refresh_core_pool_size";
/**
* The maximum size of the thread pool for shortcut refreshing in GlobalSearch.
* @hide
*/
+ @Readable
public static final String SEARCH_SHORTCUT_REFRESH_MAX_POOL_SIZE =
"search_shortcut_refresh_max_pool_size";
/**
@@ -7650,12 +7994,14 @@
* wait before terminating.
* @hide
*/
+ @Readable
public static final String SEARCH_THREAD_KEEPALIVE_SECONDS =
"search_thread_keepalive_seconds";
/**
* The maximum number of concurrent suggestion queries to each source.
* @hide
*/
+ @Readable
public static final String SEARCH_PER_SOURCE_CONCURRENT_QUERY_LIMIT =
"search_per_source_concurrent_query_limit";
@@ -7664,24 +8010,28 @@
* (0 = false, 1 = true)
* @hide
*/
+ @Readable
public static final String MOUNT_PLAY_NOTIFICATION_SND = "mount_play_not_snd";
/**
* Whether or not UMS auto-starts on UMS host detection. (0 = false, 1 = true)
* @hide
*/
+ @Readable
public static final String MOUNT_UMS_AUTOSTART = "mount_ums_autostart";
/**
* Whether or not a notification is displayed on UMS host detection. (0 = false, 1 = true)
* @hide
*/
+ @Readable
public static final String MOUNT_UMS_PROMPT = "mount_ums_prompt";
/**
* Whether or not a notification is displayed while UMS is enabled. (0 = false, 1 = true)
* @hide
*/
+ @Readable
public static final String MOUNT_UMS_NOTIFY_ENABLED = "mount_ums_notify_enabled";
/**
@@ -7693,6 +8043,7 @@
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@TestApi
+ @Readable
@SuppressLint("NoSettingsProvider")
public static final String ANR_SHOW_BACKGROUND = "anr_show_background";
@@ -7702,6 +8053,7 @@
* @hide
*/
@TestApi
+ @Readable
@SuppressLint("NoSettingsProvider")
public static final String SHOW_FIRST_CRASH_DIALOG_DEV_OPTION =
"show_first_crash_dialog_dev_option";
@@ -7713,6 +8065,7 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @Readable
public static final String VOICE_RECOGNITION_SERVICE = "voice_recognition_service";
/**
@@ -7723,6 +8076,7 @@
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@TestApi
+ @Readable
@SuppressLint("NoSettingsProvider")
public static final String SELECTED_SPELL_CHECKER = "selected_spell_checker";
@@ -7735,6 +8089,7 @@
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@TestApi
+ @Readable
@SuppressLint("NoSettingsProvider")
public static final String SELECTED_SPELL_CHECKER_SUBTYPE =
"selected_spell_checker_subtype";
@@ -7744,6 +8099,7 @@
*
* @hide
*/
+ @Readable
public static final String SPELL_CHECKER_ENABLED = "spell_checker_enabled";
/**
@@ -7756,6 +8112,7 @@
* @hide
*/
@UnsupportedAppUsage
+ @Readable
public static final String INCALL_POWER_BUTTON_BEHAVIOR = "incall_power_button_behavior";
/**
@@ -7770,6 +8127,7 @@
*
* @hide
*/
+ @Readable
public static final String MINIMAL_POST_PROCESSING_ALLOWED =
"minimal_post_processing_allowed";
@@ -7814,6 +8172,7 @@
* @see #MATCH_CONTENT_FRAMERATE_ALWAYS
* @hide
*/
+ @Readable
public static final String MATCH_CONTENT_FRAME_RATE =
"match_content_frame_rate";
@@ -7845,6 +8204,7 @@
*
* @hide
*/
+ @Readable
public static final String INCALL_BACK_BUTTON_BEHAVIOR = "incall_back_button_behavior";
/**
@@ -7870,6 +8230,7 @@
* Whether the device should wake when the wake gesture sensor detects motion.
* @hide
*/
+ @Readable
public static final String WAKE_GESTURE_ENABLED = "wake_gesture_enabled";
/**
@@ -7877,6 +8238,7 @@
* @hide
*/
@UnsupportedAppUsage
+ @Readable
public static final String DOZE_ENABLED = "doze_enabled";
/**
@@ -7887,36 +8249,42 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String DOZE_ALWAYS_ON = "doze_always_on";
/**
* Whether the device should pulse on pick up gesture.
* @hide
*/
+ @Readable
public static final String DOZE_PICK_UP_GESTURE = "doze_pulse_on_pick_up";
/**
* Whether the device should pulse on long press gesture.
* @hide
*/
+ @Readable
public static final String DOZE_PULSE_ON_LONG_PRESS = "doze_pulse_on_long_press";
/**
* Whether the device should pulse on double tap gesture.
* @hide
*/
+ @Readable
public static final String DOZE_DOUBLE_TAP_GESTURE = "doze_pulse_on_double_tap";
/**
* Whether the device should respond to the SLPI tap gesture.
* @hide
*/
+ @Readable
public static final String DOZE_TAP_SCREEN_GESTURE = "doze_tap_gesture";
/**
* Gesture that wakes up the display, showing some version of the lock screen.
* @hide
*/
+ @Readable
public static final String DOZE_WAKE_LOCK_SCREEN_GESTURE = "doze_wake_screen_gesture";
/**
@@ -7924,84 +8292,98 @@
* {@link Display.STATE_DOZE}.
* @hide
*/
+ @Readable
public static final String DOZE_WAKE_DISPLAY_GESTURE = "doze_wake_display_gesture";
/**
* Whether the device should suppress the current doze configuration and disable dozing.
* @hide
*/
+ @Readable
public static final String SUPPRESS_DOZE = "suppress_doze";
/**
* Gesture that skips media.
* @hide
*/
+ @Readable
public static final String SKIP_GESTURE = "skip_gesture";
/**
* Count of successful gestures.
* @hide
*/
+ @Readable
public static final String SKIP_GESTURE_COUNT = "skip_gesture_count";
/**
* Count of non-gesture interaction.
* @hide
*/
+ @Readable
public static final String SKIP_TOUCH_COUNT = "skip_touch_count";
/**
* Direction to advance media for skip gesture
* @hide
*/
+ @Readable
public static final String SKIP_DIRECTION = "skip_gesture_direction";
/**
* Gesture that silences sound (alarms, notification, calls).
* @hide
*/
+ @Readable
public static final String SILENCE_GESTURE = "silence_gesture";
/**
* Count of successful silence alarms gestures.
* @hide
*/
+ @Readable
public static final String SILENCE_ALARMS_GESTURE_COUNT = "silence_alarms_gesture_count";
/**
* Count of successful silence timer gestures.
* @hide
*/
+ @Readable
public static final String SILENCE_TIMER_GESTURE_COUNT = "silence_timer_gesture_count";
/**
* Count of successful silence call gestures.
* @hide
*/
+ @Readable
public static final String SILENCE_CALL_GESTURE_COUNT = "silence_call_gesture_count";
/**
* Count of non-gesture interaction.
* @hide
*/
+ @Readable
public static final String SILENCE_ALARMS_TOUCH_COUNT = "silence_alarms_touch_count";
/**
* Count of non-gesture interaction.
* @hide
*/
+ @Readable
public static final String SILENCE_TIMER_TOUCH_COUNT = "silence_timer_touch_count";
/**
* Count of non-gesture interaction.
* @hide
*/
+ @Readable
public static final String SILENCE_CALL_TOUCH_COUNT = "silence_call_touch_count";
/**
* Number of successful "Motion Sense" tap gestures to pause media.
* @hide
*/
+ @Readable
public static final String AWARE_TAP_PAUSE_GESTURE_COUNT = "aware_tap_pause_gesture_count";
/**
@@ -8009,12 +8391,14 @@
* have been used.
* @hide
*/
+ @Readable
public static final String AWARE_TAP_PAUSE_TOUCH_COUNT = "aware_tap_pause_touch_count";
/**
* For user preference if swipe bottom to expand notification gesture enabled.
* @hide
*/
+ @Readable
public static final String SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED =
"swipe_bottom_to_notification_enabled";
@@ -8022,24 +8406,28 @@
* For user preference if One-Handed Mode enabled.
* @hide
*/
+ @Readable
public static final String ONE_HANDED_MODE_ENABLED = "one_handed_mode_enabled";
/**
* For user preference if One-Handed Mode timeout.
* @hide
*/
+ @Readable
public static final String ONE_HANDED_MODE_TIMEOUT = "one_handed_mode_timeout";
/**
* For user taps app to exit One-Handed Mode.
* @hide
*/
+ @Readable
public static final String TAPS_APP_TO_EXIT = "taps_app_to_exit";
/**
* Internal use, one handed mode tutorial showed times.
* @hide
*/
+ @Readable
public static final String ONE_HANDED_TUTORIAL_SHOW_COUNT =
"one_handed_tutorial_show_count";
@@ -8049,6 +8437,7 @@
* UiModeManager.
* @hide
*/
+ @Readable
public static final String UI_NIGHT_MODE = "ui_night_mode";
/**
@@ -8057,12 +8446,14 @@
* UiModeManager.
* @hide
*/
+ @Readable
public static final String UI_NIGHT_MODE_OVERRIDE_ON = "ui_night_mode_override_on";
/**
* The last computed night mode bool the last time the phone was on
* @hide
*/
+ @Readable
public static final String UI_NIGHT_MODE_LAST_COMPUTED = "ui_night_mode_last_computed";
/**
@@ -8071,12 +8462,14 @@
* UiModeManager.
* @hide
*/
+ @Readable
public static final String UI_NIGHT_MODE_OVERRIDE_OFF = "ui_night_mode_override_off";
/**
* Whether screensavers are enabled.
* @hide
*/
+ @Readable
public static final String SCREENSAVER_ENABLED = "screensaver_enabled";
/**
@@ -8086,6 +8479,7 @@
* battery, or upon dock insertion (if SCREENSAVER_ACTIVATE_ON_DOCK is set to 1).
* @hide
*/
+ @Readable
public static final String SCREENSAVER_COMPONENTS = "screensaver_components";
/**
@@ -8093,6 +8487,7 @@
* when the device is inserted into a (desk) dock.
* @hide
*/
+ @Readable
public static final String SCREENSAVER_ACTIVATE_ON_DOCK = "screensaver_activate_on_dock";
/**
@@ -8100,12 +8495,14 @@
* when the screen times out when not on battery.
* @hide
*/
+ @Readable
public static final String SCREENSAVER_ACTIVATE_ON_SLEEP = "screensaver_activate_on_sleep";
/**
* If screensavers are enabled, the default screensaver component.
* @hide
*/
+ @Readable
public static final String SCREENSAVER_DEFAULT_COMPONENT = "screensaver_default_component";
/**
@@ -8114,12 +8511,14 @@
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@TestApi
+ @Readable
public static final String NFC_PAYMENT_DEFAULT_COMPONENT = "nfc_payment_default_component";
/**
* Whether NFC payment is handled by the foreground application or a default.
* @hide
*/
+ @Readable
public static final String NFC_PAYMENT_FOREGROUND = "nfc_payment_foreground";
/**
@@ -8127,6 +8526,7 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @Readable
public static final String SMS_DEFAULT_APPLICATION = "sms_default_application";
/**
@@ -8134,6 +8534,7 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @Readable
public static final String DIALER_DEFAULT_APPLICATION = "dialer_default_application";
/**
@@ -8141,6 +8542,7 @@
* application
* @hide
*/
+ @Readable
public static final String CALL_SCREENING_DEFAULT_COMPONENT =
"call_screening_default_component";
@@ -8151,6 +8553,7 @@
*
* @hide
*/
+ @Readable
public static final String EMERGENCY_ASSISTANCE_APPLICATION = "emergency_assistance_application";
/**
@@ -8159,6 +8562,7 @@
*
* @hide
*/
+ @Readable
public static final String ASSIST_STRUCTURE_ENABLED = "assist_structure_enabled";
/**
@@ -8167,6 +8571,7 @@
*
* @hide
*/
+ @Readable
public static final String ASSIST_SCREENSHOT_ENABLED = "assist_screenshot_enabled";
/**
@@ -8178,6 +8583,7 @@
*
* @hide
*/
+ @Readable
public static final String ASSIST_DISCLOSURE_ENABLED = "assist_disclosure_enabled";
/**
@@ -8189,7 +8595,7 @@
*
* @hide
*/
-
+ @Readable
public static final String SHOW_ROTATION_SUGGESTIONS = "show_rotation_suggestions";
/**
@@ -8216,6 +8622,7 @@
* introduced to rotation suggestions.
* @hide
*/
+ @Readable
public static final String NUM_ROTATION_SUGGESTIONS_ACCEPTED =
"num_rotation_suggestions_accepted";
@@ -8228,6 +8635,7 @@
* @hide
*/
@Deprecated
+ @Readable
public static final String ENABLED_NOTIFICATION_ASSISTANT =
"enabled_notification_assistant";
@@ -8241,6 +8649,7 @@
*/
@Deprecated
@UnsupportedAppUsage
+ @Readable
public static final String ENABLED_NOTIFICATION_LISTENERS = "enabled_notification_listeners";
/**
@@ -8252,6 +8661,7 @@
*/
@Deprecated
@TestApi
+ @Readable
public static final String ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES =
"enabled_notification_policy_access_packages";
@@ -8265,6 +8675,7 @@
* @hide
*/
@TestApi
+ @Readable
@RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
public static final String SYNC_PARENT_SOUNDS = "sync_parent_sounds";
@@ -8273,6 +8684,7 @@
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@TestApi
+ @Readable
public static final String IMMERSIVE_MODE_CONFIRMATIONS = "immersive_mode_confirmations";
/**
@@ -8280,6 +8692,7 @@
*
* @hide
*/
+ @Readable
public static final String PRINT_SERVICE_SEARCH_URI = "print_service_search_uri";
/**
@@ -8287,6 +8700,7 @@
*
* @hide
*/
+ @Readable
public static final String PAYMENT_SERVICE_SEARCH_URI = "payment_service_search_uri";
/**
@@ -8294,6 +8708,7 @@
*
* @hide
*/
+ @Readable
public static final String AUTOFILL_SERVICE_SEARCH_URI = "autofill_service_search_uri";
/**
@@ -8302,6 +8717,7 @@
* <p>
* Type : int (0 to show hints, 1 to skip showing hints)
*/
+ @Readable
public static final String SKIP_FIRST_USE_HINTS = "skip_first_use_hints";
/**
@@ -8309,6 +8725,7 @@
*
* @hide
*/
+ @Readable
public static final String UNSAFE_VOLUME_MUSIC_ACTIVE_MS = "unsafe_volume_music_active_ms";
/**
@@ -8319,6 +8736,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String LOCK_SCREEN_SHOW_NOTIFICATIONS =
"lock_screen_show_notifications";
@@ -8329,6 +8747,7 @@
*
* @hide
*/
+ @Readable
public static final String LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS =
"lock_screen_show_silent_notifications";
@@ -8339,6 +8758,7 @@
*
* @hide
*/
+ @Readable
public static final String SHOW_NOTIFICATION_SNOOZE = "show_notification_snooze";
/**
@@ -8347,6 +8767,7 @@
* {@link android.net.Uri#encode(String)} and separated by ':'.
* @hide
*/
+ @Readable
public static final String TV_INPUT_HIDDEN_INPUTS = "tv_input_hidden_inputs";
/**
@@ -8355,6 +8776,7 @@
* and separated by ','. Each pair is separated by ':'.
* @hide
*/
+ @Readable
public static final String TV_INPUT_CUSTOM_LABELS = "tv_input_custom_labels";
/**
@@ -8372,6 +8794,7 @@
*
* @hide
*/
+ @Readable
public static final String TV_APP_USES_NON_SYSTEM_INPUTS = "tv_app_uses_non_system_inputs";
/**
@@ -8381,6 +8804,7 @@
*
* @hide
*/
+ @Readable
public static final String USB_AUDIO_AUTOMATIC_ROUTING_DISABLED =
"usb_audio_automatic_routing_disabled";
@@ -8396,6 +8820,7 @@
*
* @hide
*/
+ @Readable
public static final String SLEEP_TIMEOUT = "sleep_timeout";
/**
@@ -8410,12 +8835,14 @@
*
* @hide
*/
+ @Readable
public static final String ATTENTIVE_TIMEOUT = "attentive_timeout";
/**
* Controls whether double tap to wake is enabled.
* @hide
*/
+ @Readable
public static final String DOUBLE_TAP_TO_WAKE = "double_tap_to_wake";
/**
@@ -8429,6 +8856,7 @@
* @hide
*/
@UnsupportedAppUsage
+ @Readable
public static final String ASSISTANT = "assistant";
/**
@@ -8436,6 +8864,7 @@
*
* @hide
*/
+ @Readable
public static final String CAMERA_GESTURE_DISABLED = "camera_gesture_disabled";
/**
@@ -8443,6 +8872,7 @@
*
* @hide
*/
+ @Readable
public static final String EMERGENCY_GESTURE_ENABLED = "emergency_gesture_enabled";
/**
@@ -8450,6 +8880,7 @@
*
* @hide
*/
+ @Readable
public static final String EMERGENCY_GESTURE_SOUND_ENABLED =
"emergency_gesture_sound_enabled";
@@ -8459,6 +8890,7 @@
*
* @hide
*/
+ @Readable
public static final String CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED =
"camera_double_tap_power_gesture_disabled";
@@ -8468,6 +8900,7 @@
*
* @hide
*/
+ @Readable
public static final String CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED =
"camera_double_twist_to_flip_enabled";
@@ -8477,6 +8910,7 @@
*
* @hide
*/
+ @Readable
public static final String CAMERA_LIFT_TRIGGER_ENABLED = "camera_lift_trigger_enabled";
/**
@@ -8492,6 +8926,7 @@
*
* @hide
*/
+ @Readable
public static final String FLASHLIGHT_AVAILABLE = "flashlight_available";
/**
@@ -8499,18 +8934,21 @@
*
* @hide
*/
+ @Readable
public static final String FLASHLIGHT_ENABLED = "flashlight_enabled";
/**
* Whether or not face unlock is allowed on Keyguard.
* @hide
*/
+ @Readable
public static final String FACE_UNLOCK_KEYGUARD_ENABLED = "face_unlock_keyguard_enabled";
/**
* Whether or not face unlock dismisses the keyguard.
* @hide
*/
+ @Readable
public static final String FACE_UNLOCK_DISMISSES_KEYGUARD =
"face_unlock_dismisses_keyguard";
@@ -8518,6 +8956,7 @@
* Whether or not media is shown automatically when bypassing as a heads up.
* @hide
*/
+ @Readable
public static final String SHOW_MEDIA_WHEN_BYPASSING =
"show_media_when_bypassing";
@@ -8526,6 +8965,7 @@
* truth is obtained through the HAL.
* @hide
*/
+ @Readable
public static final String FACE_UNLOCK_ATTENTION_REQUIRED =
"face_unlock_attention_required";
@@ -8534,6 +8974,7 @@
* cached value, the source of truth is obtained through the HAL.
* @hide
*/
+ @Readable
public static final String FACE_UNLOCK_DIVERSITY_REQUIRED =
"face_unlock_diversity_required";
@@ -8542,6 +8983,7 @@
* Whether or not face unlock is allowed for apps (through BiometricPrompt).
* @hide
*/
+ @Readable
public static final String FACE_UNLOCK_APP_ENABLED = "face_unlock_app_enabled";
/**
@@ -8551,6 +8993,7 @@
* setConfirmationRequired API.
* @hide
*/
+ @Readable
public static final String FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION =
"face_unlock_always_require_confirmation";
@@ -8565,12 +9008,14 @@
*
* @hide
*/
+ @Readable
public static final String FACE_UNLOCK_RE_ENROLL = "face_unlock_re_enroll";
/**
* Whether or not debugging is enabled.
* @hide
*/
+ @Readable
public static final String BIOMETRIC_DEBUG_ENABLED =
"biometric_debug_enabled";
@@ -8579,6 +9024,7 @@
*
* @hide
*/
+ @Readable
public static final String ASSIST_GESTURE_ENABLED = "assist_gesture_enabled";
/**
@@ -8586,6 +9032,7 @@
*
* @hide
*/
+ @Readable
public static final String ASSIST_GESTURE_SENSITIVITY = "assist_gesture_sensitivity";
/**
@@ -8593,6 +9040,7 @@
*
* @hide
*/
+ @Readable
public static final String ASSIST_GESTURE_SILENCE_ALERTS_ENABLED =
"assist_gesture_silence_alerts_enabled";
@@ -8601,6 +9049,7 @@
*
* @hide
*/
+ @Readable
public static final String ASSIST_GESTURE_WAKE_ENABLED =
"assist_gesture_wake_enabled";
@@ -8612,36 +9061,42 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String ASSIST_GESTURE_SETUP_COMPLETE = "assist_gesture_setup_complete";
/**
* Control whether Trust Agents are in active unlock or extend unlock mode.
* @hide
*/
+ @Readable
public static final String TRUST_AGENTS_EXTEND_UNLOCK = "trust_agents_extend_unlock";
/**
* Control whether the screen locks when trust is lost.
* @hide
*/
+ @Readable
public static final String LOCK_SCREEN_WHEN_TRUST_LOST = "lock_screen_when_trust_lost";
/**
* Control whether Night display is currently activated.
* @hide
*/
+ @Readable
public static final String NIGHT_DISPLAY_ACTIVATED = "night_display_activated";
/**
* Control whether Night display will automatically activate/deactivate.
* @hide
*/
+ @Readable
public static final String NIGHT_DISPLAY_AUTO_MODE = "night_display_auto_mode";
/**
* Control the color temperature of Night Display, represented in Kelvin.
* @hide
*/
+ @Readable
public static final String NIGHT_DISPLAY_COLOR_TEMPERATURE =
"night_display_color_temperature";
@@ -8650,6 +9105,7 @@
* Represented as milliseconds from midnight (e.g. 79200000 == 10pm).
* @hide
*/
+ @Readable
public static final String NIGHT_DISPLAY_CUSTOM_START_TIME =
"night_display_custom_start_time";
@@ -8658,6 +9114,7 @@
* Represented as milliseconds from midnight (e.g. 21600000 == 6am).
* @hide
*/
+ @Readable
public static final String NIGHT_DISPLAY_CUSTOM_END_TIME = "night_display_custom_end_time";
/**
@@ -8666,6 +9123,7 @@
* legacy cases, this is represented by the time in milliseconds (since epoch).
* @hide
*/
+ @Readable
public static final String NIGHT_DISPLAY_LAST_ACTIVATED_TIME =
"night_display_last_activated_time";
@@ -8673,6 +9131,7 @@
* Control whether display white balance is currently enabled.
* @hide
*/
+ @Readable
public static final String DISPLAY_WHITE_BALANCE_ENABLED = "display_white_balance_enabled";
/**
@@ -8683,6 +9142,7 @@
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@TestApi
+ @Readable
public static final String ENABLED_VR_LISTENERS = "enabled_vr_listeners";
/**
@@ -8692,6 +9152,7 @@
*
* @hide
*/
+ @Readable
public static final String VR_DISPLAY_MODE = "vr_display_mode";
/**
@@ -8725,6 +9186,7 @@
*
* @hide
*/
+ @Readable
public static final String CARRIER_APPS_HANDLED = "carrier_apps_handled";
/**
@@ -8732,6 +9194,7 @@
*
* @hide
*/
+ @Readable
public static final String MANAGED_PROFILE_CONTACT_REMOTE_SEARCH =
"managed_profile_contact_remote_search";
@@ -8740,6 +9203,7 @@
*
* @hide
*/
+ @Readable
public static final String CROSS_PROFILE_CALENDAR_ENABLED =
"cross_profile_calendar_enabled";
@@ -8748,6 +9212,7 @@
*
* @hide
*/
+ @Readable
public static final String AUTOMATIC_STORAGE_MANAGER_ENABLED =
"automatic_storage_manager_enabled";
@@ -8756,6 +9221,7 @@
*
* @hide
*/
+ @Readable
public static final String AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN =
"automatic_storage_manager_days_to_retain";
@@ -8771,6 +9237,7 @@
*
* @hide
*/
+ @Readable
public static final String AUTOMATIC_STORAGE_MANAGER_BYTES_CLEARED =
"automatic_storage_manager_bytes_cleared";
@@ -8779,6 +9246,7 @@
*
* @hide
*/
+ @Readable
public static final String AUTOMATIC_STORAGE_MANAGER_LAST_RUN =
"automatic_storage_manager_last_run";
/**
@@ -8788,6 +9256,7 @@
*
* @hide
*/
+ @Readable
public static final String AUTOMATIC_STORAGE_MANAGER_TURNED_OFF_BY_POLICY =
"automatic_storage_manager_turned_off_by_policy";
@@ -8795,6 +9264,7 @@
* Whether SystemUI navigation keys is enabled.
* @hide
*/
+ @Readable
public static final String SYSTEM_NAVIGATION_KEYS_ENABLED =
"system_navigation_keys_enabled";
@@ -8803,6 +9273,7 @@
*
* @hide
*/
+ @Readable
public static final String QS_TILES = "sysui_qs_tiles";
/**
@@ -8813,6 +9284,7 @@
*
* @hide
*/
+ @Readable
public static final String CONTROLS_ENABLED = "controls_enabled";
/**
@@ -8822,6 +9294,7 @@
* @hide
*/
@TestApi
+ @Readable
public static final String POWER_MENU_LOCKED_SHOW_CONTENT =
"power_menu_locked_show_content";
@@ -8831,18 +9304,21 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String INSTANT_APPS_ENABLED = "instant_apps_enabled";
/**
* Has this pairable device been paired or upgraded from a previously paired system.
* @hide
*/
+ @Readable
public static final String DEVICE_PAIRED = "device_paired";
/**
* Specifies additional package name for broadcasting the CMAS messages.
* @hide
*/
+ @Readable
public static final String CMAS_ADDITIONAL_BROADCAST_PKG = "cmas_additional_broadcast_pkg";
/**
@@ -8852,6 +9328,7 @@
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@TestApi
+ @Readable
public static final String NOTIFICATION_BADGING = "notification_badging";
/**
@@ -8861,6 +9338,7 @@
* The value 1 - enable, 0 - disable
* @hide
*/
+ @Readable
public static final String NOTIFICATION_HISTORY_ENABLED = "notification_history_enabled";
/**
@@ -8869,6 +9347,7 @@
* The value 1 - enable, 0 - disable
* @hide
*/
+ @Readable
public static final String BUBBLE_IMPORTANT_CONVERSATIONS
= "bubble_important_conversations";
@@ -8878,18 +9357,21 @@
*
* @hide
*/
+ @Readable
public static final String NOTIFICATION_DISMISS_RTL = "notification_dismiss_rtl";
/**
* Comma separated list of QS tiles that have been auto-added already.
* @hide
*/
+ @Readable
public static final String QS_AUTO_ADDED_TILES = "qs_auto_tiles";
/**
* Whether the Lockdown button should be shown in the power menu.
* @hide
*/
+ @Readable
public static final String LOCKDOWN_IN_POWER_MENU = "lockdown_in_power_menu";
/**
@@ -8917,6 +9399,7 @@
* Type: string
* @hide
*/
+ @Readable
public static final String BACKUP_MANAGER_CONSTANTS = "backup_manager_constants";
@@ -8934,6 +9417,7 @@
* Type: string
* @hide
*/
+ @Readable
public static final String BACKUP_LOCAL_TRANSPORT_PARAMETERS =
"backup_local_transport_parameters";
@@ -8942,6 +9426,7 @@
* the user is driving.
* @hide
*/
+ @Readable
public static final String BLUETOOTH_ON_WHILE_DRIVING = "bluetooth_on_while_driving";
/**
@@ -8951,6 +9436,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String VOLUME_HUSH_GESTURE = "volume_hush_gesture";
/** @hide */
@@ -8967,6 +9453,7 @@
* The number of times (integer) the user has manually enabled battery saver.
* @hide
*/
+ @Readable
public static final String LOW_POWER_MANUAL_ACTIVATION_COUNT =
"low_power_manual_activation_count";
@@ -8976,6 +9463,7 @@
*
* @hide
*/
+ @Readable
public static final String LOW_POWER_WARNING_ACKNOWLEDGED =
"low_power_warning_acknowledged";
@@ -8984,6 +9472,7 @@
* suppressed.
* @hide
*/
+ @Readable
public static final String SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION =
"suppress_auto_battery_saver_suggestion";
@@ -8992,6 +9481,7 @@
* Type: string
* @hide
*/
+ @Readable
public static final String PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE =
"packages_to_clear_data_before_full_restore";
@@ -9000,6 +9490,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String LOCATION_ACCESS_CHECK_INTERVAL_MILLIS =
"location_access_check_interval_millis";
@@ -9008,6 +9499,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String LOCATION_ACCESS_CHECK_DELAY_MILLIS =
"location_access_check_delay_millis";
@@ -9017,6 +9509,7 @@
*/
@SystemApi
@Deprecated
+ @Readable
public static final String LOCATION_PERMISSIONS_UPGRADE_TO_Q_MODE =
"location_permissions_upgrade_to_q_mode";
@@ -9025,6 +9518,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String AUTO_REVOKE_DISABLED = "auto_revoke_disabled";
/**
@@ -9035,6 +9529,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String THEME_CUSTOMIZATION_OVERLAY_PACKAGES =
"theme_customization_overlay_packages";
@@ -9045,6 +9540,7 @@
* 2 = fully gestural
* @hide
*/
+ @Readable
public static final String NAVIGATION_MODE =
"navigation_mode";
@@ -9052,6 +9548,7 @@
* Scale factor for the back gesture inset size on the left side of the screen.
* @hide
*/
+ @Readable
public static final String BACK_GESTURE_INSET_SCALE_LEFT =
"back_gesture_inset_scale_left";
@@ -9059,6 +9556,7 @@
* Scale factor for the back gesture inset size on the right side of the screen.
* @hide
*/
+ @Readable
public static final String BACK_GESTURE_INSET_SCALE_RIGHT =
"back_gesture_inset_scale_right";
@@ -9068,30 +9566,35 @@
* No VALIDATOR as this setting will not be backed up.
* @hide
*/
+ @Readable
public static final String NEARBY_SHARING_COMPONENT = "nearby_sharing_component";
/**
* Controls whether aware is enabled.
* @hide
*/
+ @Readable
public static final String AWARE_ENABLED = "aware_enabled";
/**
* Controls whether aware_lock is enabled.
* @hide
*/
+ @Readable
public static final String AWARE_LOCK_ENABLED = "aware_lock_enabled";
/**
* Controls whether tap gesture is enabled.
* @hide
*/
+ @Readable
public static final String TAP_GESTURE = "tap_gesture";
/**
* Controls whether the people strip is enabled.
* @hide
*/
+ @Readable
public static final String PEOPLE_STRIP = "people_strip";
/**
@@ -9101,6 +9604,7 @@
* @see Settings.Global#SHOW_MEDIA_ON_QUICK_SETTINGS
* @hide
*/
+ @Readable
public static final String MEDIA_CONTROLS_RESUME = "qs_media_resumption";
/**
@@ -9109,6 +9613,7 @@
* @see Settings.Secure#MEDIA_CONTROLS_RESUME
* @hide
*/
+ @Readable
public static final String MEDIA_CONTROLS_RESUME_BLOCKED = "qs_media_resumption_blocked";
/**
@@ -9120,6 +9625,7 @@
* @hide
*/
@TestApi
+ @Readable
public static final String ACCESSIBILITY_MAGNIFICATION_MODE =
"accessibility_magnification_mode";
@@ -9155,6 +9661,7 @@
* @hide
*/
@TestApi
+ @Readable
public static final String ACCESSIBILITY_MAGNIFICATION_CAPABILITY =
"accessibility_magnification_capability";
@@ -9164,6 +9671,7 @@
*
* @hide
*/
+ @Readable
public static final String ACCESSIBILITY_SHOW_WINDOW_MAGNIFICATION_PROMPT =
"accessibility_show_window_magnification_prompt";
@@ -9180,6 +9688,7 @@
* @see #ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU
* @hide
*/
+ @Readable
public static final String ACCESSIBILITY_BUTTON_MODE =
"accessibility_button_mode";
@@ -9208,6 +9717,7 @@
*
* @hide
*/
+ @Readable
public static final String ACCESSIBILITY_FLOATING_MENU_SIZE =
"accessibility_floating_menu_size";
@@ -9220,6 +9730,7 @@
*
* @hide
*/
+ @Readable
public static final String ACCESSIBILITY_FLOATING_MENU_ICON_TYPE =
"accessibility_floating_menu_icon_type";
@@ -9229,6 +9740,7 @@
*
* @hide
*/
+ @Readable
public static final String ACCESSIBILITY_FLOATING_MENU_OPACITY =
"accessibility_floating_menu_opacity";
@@ -9237,6 +9749,7 @@
*
* @hide
*/
+ @Readable
public static final String ADAPTIVE_CONNECTIVITY_ENABLED = "adaptive_connectivity_enabled";
/**
@@ -9248,6 +9761,7 @@
*
* @hide
*/
+ @Readable
public static final String[] LEGACY_RESTORE_SETTINGS = {
ENABLED_NOTIFICATION_LISTENERS,
ENABLED_NOTIFICATION_ASSISTANT,
@@ -9259,6 +9773,7 @@
*
* @hide
*/
+ @Readable
public static final String ASSIST_HANDLES_LEARNING_TIME_ELAPSED_MILLIS =
"reminder_exp_learning_time_elapsed";
@@ -9267,6 +9782,7 @@
*
* @hide
*/
+ @Readable
public static final String ASSIST_HANDLES_LEARNING_EVENT_COUNT =
"reminder_exp_learning_event_count";
@@ -9380,6 +9896,7 @@
* @hide
*/
@TestApi
+ @Readable
public static final String NOTIFICATION_BUBBLES = "notification_bubbles";
/**
@@ -9388,6 +9905,7 @@
* Type: int
* @hide
*/
+ @Readable
public static final String ADD_USERS_WHEN_LOCKED = "add_users_when_locked";
/**
@@ -9395,6 +9913,7 @@
* <p>1 = apply ramping ringer
* <p>0 = do not apply ramping ringer
*/
+ @Readable
public static final String APPLY_RAMPING_RINGER = "apply_ramping_ringer";
/**
@@ -9406,12 +9925,14 @@
* No longer used. Should be removed once all dependencies have been updated.
*/
@UnsupportedAppUsage
+ @Readable
public static final String ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED =
"enable_accessibility_global_gesture_enabled";
/**
* Whether Airplane Mode is on.
*/
+ @Readable
public static final String AIRPLANE_MODE_ON = "airplane_mode_on";
/**
@@ -9419,30 +9940,36 @@
* {@hide}
*/
@SystemApi
+ @Readable
public static final String THEATER_MODE_ON = "theater_mode_on";
/**
* Constant for use in AIRPLANE_MODE_RADIOS to specify Bluetooth radio.
*/
+ @Readable
public static final String RADIO_BLUETOOTH = "bluetooth";
/**
* Constant for use in AIRPLANE_MODE_RADIOS to specify Wi-Fi radio.
*/
+ @Readable
public static final String RADIO_WIFI = "wifi";
/**
* {@hide}
*/
+ @Readable
public static final String RADIO_WIMAX = "wimax";
/**
* Constant for use in AIRPLANE_MODE_RADIOS to specify Cellular radio.
*/
+ @Readable
public static final String RADIO_CELL = "cell";
/**
* Constant for use in AIRPLANE_MODE_RADIOS to specify NFC radio.
*/
+ @Readable
public static final String RADIO_NFC = "nfc";
/**
@@ -9450,6 +9977,7 @@
* is on. This overrides WIFI_ON and BLUETOOTH_ON, if Wi-Fi and bluetooth are
* included in the comma separated list.
*/
+ @Readable
public static final String AIRPLANE_MODE_RADIOS = "airplane_mode_radios";
/**
@@ -9461,6 +9989,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String AIRPLANE_MODE_TOGGLEABLE_RADIOS = "airplane_mode_toggleable_radios";
/**
@@ -9468,6 +9997,7 @@
*
* @hide
*/
+ @Readable
public static final String BLUETOOTH_CLASS_OF_DEVICE = "bluetooth_class_of_device";
/**
@@ -9475,6 +10005,7 @@
* See {@link android.bluetooth.BluetoothProfile}.
* {@hide}
*/
+ @Readable
public static final String BLUETOOTH_DISABLED_PROFILES = "bluetooth_disabled_profiles";
/**
@@ -9487,6 +10018,7 @@
* "00:11:22,0;01:02:03:04,2"
* @hide
*/
+ @Readable
public static final String BLUETOOTH_INTEROPERABILITY_LIST = "bluetooth_interoperability_list";
/**
@@ -9499,6 +10031,7 @@
* @deprecated This is no longer used or set by the platform.
*/
@Deprecated
+ @Readable
public static final String WIFI_SLEEP_POLICY = "wifi_sleep_policy";
/**
@@ -9530,60 +10063,70 @@
* Value to specify if the user prefers the date, time and time zone
* to be automatically fetched from the network (NITZ). 1=yes, 0=no
*/
+ @Readable
public static final String AUTO_TIME = "auto_time";
/**
* Value to specify if the user prefers the time zone
* to be automatically fetched from the network (NITZ). 1=yes, 0=no
*/
+ @Readable
public static final String AUTO_TIME_ZONE = "auto_time_zone";
/**
* URI for the car dock "in" event sound.
* @hide
*/
+ @Readable
public static final String CAR_DOCK_SOUND = "car_dock_sound";
/**
* URI for the car dock "out" event sound.
* @hide
*/
+ @Readable
public static final String CAR_UNDOCK_SOUND = "car_undock_sound";
/**
* URI for the desk dock "in" event sound.
* @hide
*/
+ @Readable
public static final String DESK_DOCK_SOUND = "desk_dock_sound";
/**
* URI for the desk dock "out" event sound.
* @hide
*/
+ @Readable
public static final String DESK_UNDOCK_SOUND = "desk_undock_sound";
/**
* Whether to play a sound for dock events.
* @hide
*/
+ @Readable
public static final String DOCK_SOUNDS_ENABLED = "dock_sounds_enabled";
/**
* Whether to play a sound for dock events, only when an accessibility service is on.
* @hide
*/
+ @Readable
public static final String DOCK_SOUNDS_ENABLED_WHEN_ACCESSIBILITY = "dock_sounds_enabled_when_accessbility";
/**
* URI for the "device locked" (keyguard shown) sound.
* @hide
*/
+ @Readable
public static final String LOCK_SOUND = "lock_sound";
/**
* URI for the "device unlocked" sound.
* @hide
*/
+ @Readable
public static final String UNLOCK_SOUND = "unlock_sound";
/**
@@ -9591,24 +10134,28 @@
* state without unlocking.
* @hide
*/
+ @Readable
public static final String TRUSTED_SOUND = "trusted_sound";
/**
* URI for the low battery sound file.
* @hide
*/
+ @Readable
public static final String LOW_BATTERY_SOUND = "low_battery_sound";
/**
* Whether to play a sound for low-battery alerts.
* @hide
*/
+ @Readable
public static final String POWER_SOUNDS_ENABLED = "power_sounds_enabled";
/**
* URI for the "wireless charging started" sound.
* @hide
*/
+ @Readable
public static final String WIRELESS_CHARGING_STARTED_SOUND =
"wireless_charging_started_sound";
@@ -9616,6 +10163,7 @@
* URI for "wired charging started" sound.
* @hide
*/
+ @Readable
public static final String CHARGING_STARTED_SOUND = "charging_started_sound";
/**
@@ -9645,6 +10193,7 @@
* </ul>
* These values can be OR-ed together.
*/
+ @Readable
public static final String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
/**
@@ -9652,6 +10201,7 @@
* in the power menu.
* @hide
*/
+ @Readable
public static final String BUGREPORT_IN_POWER_MENU = "bugreport_in_power_menu";
/**
@@ -9660,6 +10210,7 @@
*
* @hide
*/
+ @Readable
public static final String CUSTOM_BUGREPORT_HANDLER_APP = "custom_bugreport_handler_app";
/**
@@ -9668,29 +10219,34 @@
*
* @hide
*/
+ @Readable
public static final String CUSTOM_BUGREPORT_HANDLER_USER = "custom_bugreport_handler_user";
/**
* Whether ADB over USB is enabled.
*/
+ @Readable
public static final String ADB_ENABLED = "adb_enabled";
/**
* Whether ADB over Wifi is enabled.
* @hide
*/
+ @Readable
public static final String ADB_WIFI_ENABLED = "adb_wifi_enabled";
/**
* Whether Views are allowed to save their attribute data.
* @hide
*/
+ @Readable
public static final String DEBUG_VIEW_ATTRIBUTES = "debug_view_attributes";
/**
* Which application package is allowed to save View attribute data.
* @hide
*/
+ @Readable
public static final String DEBUG_VIEW_ATTRIBUTES_APPLICATION_PACKAGE =
"debug_view_attributes_application_package";
@@ -9698,12 +10254,14 @@
* Whether assisted GPS should be enabled or not.
* @hide
*/
+ @Readable
public static final String ASSISTED_GPS_ENABLED = "assisted_gps_enabled";
/**
* Whether bluetooth is enabled/disabled
* 0=disabled. 1=enabled.
*/
+ @Readable
public static final String BLUETOOTH_ON = "bluetooth_on";
/**
@@ -9712,6 +10270,7 @@
* 1 = CDMA Cell Broadcast SMS enabled
* @hide
*/
+ @Readable
public static final String CDMA_CELL_BROADCAST_SMS =
"cdma_cell_broadcast_sms";
@@ -9721,6 +10280,7 @@
* 2 = Roaming on any networks
* @hide
*/
+ @Readable
public static final String CDMA_ROAMING_MODE = "roaming_settings";
/**
@@ -9728,6 +10288,7 @@
* 1 = NV
* @hide
*/
+ @Readable
public static final String CDMA_SUBSCRIPTION_MODE = "subscription_mode";
/**
@@ -9737,52 +10298,56 @@
*
* @hide
*/
+ @Readable
public static final String DEFAULT_RESTRICT_BACKGROUND_DATA =
"default_restrict_background_data";
/** Inactivity timeout to track mobile data activity.
- *
- * If set to a positive integer, it indicates the inactivity timeout value in seconds to
- * infer the data activity of mobile network. After a period of no activity on mobile
- * networks with length specified by the timeout, an {@code ACTION_DATA_ACTIVITY_CHANGE}
- * intent is fired to indicate a transition of network status from "active" to "idle". Any
- * subsequent activity on mobile networks triggers the firing of {@code
- * ACTION_DATA_ACTIVITY_CHANGE} intent indicating transition from "idle" to "active".
- *
- * Network activity refers to transmitting or receiving data on the network interfaces.
- *
- * Tracking is disabled if set to zero or negative value.
- *
- * @hide
- */
- public static final String DATA_ACTIVITY_TIMEOUT_MOBILE = "data_activity_timeout_mobile";
+ *
+ * If set to a positive integer, it indicates the inactivity timeout value in seconds to
+ * infer the data activity of mobile network. After a period of no activity on mobile
+ * networks with length specified by the timeout, an {@code ACTION_DATA_ACTIVITY_CHANGE}
+ * intent is fired to indicate a transition of network status from "active" to "idle". Any
+ * subsequent activity on mobile networks triggers the firing of {@code
+ * ACTION_DATA_ACTIVITY_CHANGE} intent indicating transition from "idle" to "active".
+ *
+ * Network activity refers to transmitting or receiving data on the network interfaces.
+ *
+ * Tracking is disabled if set to zero or negative value.
+ *
+ * @hide
+ */
+ @Readable
+ public static final String DATA_ACTIVITY_TIMEOUT_MOBILE = "data_activity_timeout_mobile";
- /** Timeout to tracking Wifi data activity. Same as {@code DATA_ACTIVITY_TIMEOUT_MOBILE}
- * but for Wifi network.
- * @hide
- */
- public static final String DATA_ACTIVITY_TIMEOUT_WIFI = "data_activity_timeout_wifi";
+ /** Timeout to tracking Wifi data activity. Same as {@code DATA_ACTIVITY_TIMEOUT_MOBILE}
+ * but for Wifi network.
+ * @hide
+ */
+ @Readable
+ public static final String DATA_ACTIVITY_TIMEOUT_WIFI = "data_activity_timeout_wifi";
- /**
- * Whether or not data roaming is enabled. (0 = false, 1 = true)
- */
- public static final String DATA_ROAMING = "data_roaming";
+ /**
+ * Whether or not data roaming is enabled. (0 = false, 1 = true)
+ */
+ @Readable
+ public static final String DATA_ROAMING = "data_roaming";
- /**
- * The value passed to a Mobile DataConnection via bringUp which defines the
- * number of retries to preform when setting up the initial connection. The default
- * value defined in DataConnectionTrackerBase#DEFAULT_MDC_INITIAL_RETRY is currently 1.
- * @hide
- */
- public static final String MDC_INITIAL_MAX_RETRY = "mdc_initial_max_retry";
+ /**
+ * The value passed to a Mobile DataConnection via bringUp which defines the
+ * number of retries to preform when setting up the initial connection. The default
+ * value defined in DataConnectionTrackerBase#DEFAULT_MDC_INITIAL_RETRY is currently 1.
+ * @hide
+ */
+ public static final String MDC_INITIAL_MAX_RETRY = "mdc_initial_max_retry";
- /**
- * Whether any package can be on external storage. When this is true, any
- * package, regardless of manifest values, is a candidate for installing
- * or moving onto external storage. (0 = false, 1 = true)
- * @hide
- */
- public static final String FORCE_ALLOW_ON_EXTERNAL = "force_allow_on_external";
+ /**
+ * Whether any package can be on external storage. When this is true, any
+ * package, regardless of manifest values, is a candidate for installing
+ * or moving onto external storage. (0 = false, 1 = true)
+ * @hide
+ */
+ public static final String FORCE_ALLOW_ON_EXTERNAL = "force_allow_on_external";
/**
* The default SM-DP+ configured for this device.
@@ -9796,6 +10361,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String DEFAULT_SM_DP_PLUS = "default_sm_dp_plus";
/**
@@ -9807,6 +10373,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String EUICC_PROVISIONED = "euicc_provisioned";
/**
@@ -9822,6 +10389,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String EUICC_SUPPORTED_COUNTRIES = "euicc_supported_countries";
/**
@@ -9837,6 +10405,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String EUICC_UNSUPPORTED_COUNTRIES = "euicc_unsupported_countries";
/**
@@ -9845,6 +10414,7 @@
* (0 = false, 1 = true)
* @hide
*/
+ @Readable
public static final String DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES
= "force_resizable_activities";
@@ -9852,6 +10422,7 @@
* Whether to enable experimental freeform support for windows.
* @hide
*/
+ @Readable
public static final String DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT
= "enable_freeform_support";
@@ -9859,6 +10430,7 @@
* Whether to enable experimental desktop mode on secondary displays.
* @hide
*/
+ @Readable
public static final String DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS =
"force_desktop_mode_on_external_displays";
@@ -9866,6 +10438,7 @@
* Whether to allow non-resizable apps to be freeform.
* @hide
*/
+ @Readable
public static final String DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM =
"enable_sizecompat_freeform";
@@ -9876,6 +10449,7 @@
* (0 = false, 1 = true)
* @hide
*/
+ @Readable
public static final String DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR =
"render_shadows_in_compositor";
@@ -9884,6 +10458,7 @@
* (0 = false, 1 = true)
* @hide
*/
+ @Readable
public static final String DEVELOPMENT_USE_BLAST_ADAPTER_VR =
"use_blast_adapter_vr";
@@ -9892,6 +10467,7 @@
* (0 = false, 1 = true)
* @hide
*/
+ @Readable
public static final String DEVELOPMENT_USE_BLAST_ADAPTER_SV =
"use_blast_adapter_sv";
@@ -9901,21 +10477,24 @@
*
* @hide
*/
+ @Readable
public static final String DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH =
"wm_display_settings_path";
- /**
+ /**
* Whether user has enabled development settings.
*/
- public static final String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
+ @Readable
+ public static final String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
- /**
+ /**
* Whether the device has been provisioned (0 = false, 1 = true).
* <p>On a multiuser device with a separate system user, the screen may be locked
* as soon as this is set to true and further activities cannot be launched on the
* system user unless they are marked to show over keyguard.
*/
- public static final String DEVICE_PROVISIONED = "device_provisioned";
+ @Readable
+ public static final String DEVICE_PROVISIONED = "device_provisioned";
/**
* Indicates whether mobile data should be allowed while the device is being provisioned.
@@ -9928,52 +10507,58 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String DEVICE_PROVISIONING_MOBILE_DATA_ENABLED =
"device_provisioning_mobile_data";
- /**
+ /**
* The saved value for WindowManagerService.setForcedDisplaySize().
* Two integers separated by a comma. If unset, then use the real display size.
* @hide
*/
- public static final String DISPLAY_SIZE_FORCED = "display_size_forced";
+ @Readable
+ public static final String DISPLAY_SIZE_FORCED = "display_size_forced";
- /**
+ /**
* The saved value for WindowManagerService.setForcedDisplayScalingMode().
* 0 or unset if scaling is automatic, 1 if scaling is disabled.
* @hide
*/
- public static final String DISPLAY_SCALING_FORCE = "display_scaling_force";
+ @Readable
+ public static final String DISPLAY_SCALING_FORCE = "display_scaling_force";
- /**
+ /**
* The maximum size, in bytes, of a download that the download manager will transfer over
* a non-wifi connection.
* @hide
*/
- public static final String DOWNLOAD_MAX_BYTES_OVER_MOBILE =
+ @Readable
+ public static final String DOWNLOAD_MAX_BYTES_OVER_MOBILE =
"download_manager_max_bytes_over_mobile";
- /**
+ /**
* The recommended maximum size, in bytes, of a download that the download manager should
* transfer over a non-wifi connection. Over this size, the use will be warned, but will
* have the option to start the download over the mobile connection anyway.
* @hide
*/
- public static final String DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE =
+ @Readable
+ public static final String DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE =
"download_manager_recommended_max_bytes_over_mobile";
- /**
+ /**
* @deprecated Use {@link android.provider.Settings.Secure#INSTALL_NON_MARKET_APPS} instead
*/
- @Deprecated
- public static final String INSTALL_NON_MARKET_APPS = Secure.INSTALL_NON_MARKET_APPS;
+ @Deprecated
+ public static final String INSTALL_NON_MARKET_APPS = Secure.INSTALL_NON_MARKET_APPS;
- /**
+ /**
* Whether HDMI control shall be enabled. If disabled, no CEC/MHL command will be
* sent or processed. (0 = false, 1 = true)
* @hide
*/
- public static final String HDMI_CONTROL_ENABLED = "hdmi_control_enabled";
+ @Readable
+ public static final String HDMI_CONTROL_ENABLED = "hdmi_control_enabled";
/**
* Controls whether volume control commands via HDMI CEC are enabled. (0 = false, 1 =
@@ -10009,16 +10594,18 @@
* @hide
* @see android.hardware.hdmi.HdmiControlManager#setHdmiCecVolumeControlEnabled(boolean)
*/
+ @Readable
public static final String HDMI_CONTROL_VOLUME_CONTROL_ENABLED =
"hdmi_control_volume_control_enabled";
- /**
+ /**
* Whether HDMI System Audio Control feature is enabled. If enabled, TV will try to turn on
* system audio mode if there's a connected CEC-enabled AV Receiver. Then audio stream will
* be played on AVR instead of TV spaeker. If disabled, the system audio mode will never be
* activated.
* @hide
*/
+ @Readable
public static final String HDMI_SYSTEM_AUDIO_CONTROL_ENABLED =
"hdmi_system_audio_control_enabled";
@@ -10028,6 +10615,7 @@
* disabled, you can only switch the input via controls on this device.
* @hide
*/
+ @Readable
public static final String HDMI_CEC_SWITCH_ENABLED =
"hdmi_cec_switch_enabled";
@@ -10035,6 +10623,7 @@
* HDMI CEC version to use. Defaults to v1.4b.
* @hide
*/
+ @Readable
public static final String HDMI_CEC_VERSION =
"hdmi_cec_version";
@@ -10044,6 +10633,7 @@
*
* @hide
*/
+ @Readable
public static final String HDMI_CONTROL_AUTO_WAKEUP_ENABLED =
"hdmi_control_auto_wakeup_enabled";
@@ -10053,6 +10643,7 @@
*
* @hide
*/
+ @Readable
public static final String HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED =
"hdmi_control_auto_device_off_enabled";
@@ -10074,6 +10665,7 @@
*
* @hide
*/
+ @Readable
public static final String HDMI_CONTROL_SEND_STANDBY_ON_SLEEP =
"hdmi_control_send_standby_on_sleep";
@@ -10081,6 +10673,7 @@
* Whether or not media is shown automatically when bypassing as a heads up.
* @hide
*/
+ @Readable
public static final String SHOW_MEDIA_ON_QUICK_SETTINGS =
"qs_media_player";
@@ -10090,6 +10683,7 @@
*
* @hide
*/
+ @Readable
public static final String LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS =
"location_background_throttle_interval_ms";
@@ -10098,6 +10692,7 @@
* to request.
* @hide
*/
+ @Readable
public static final String LOCATION_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS =
"location_background_throttle_proximity_alert_interval_ms";
@@ -10105,6 +10700,7 @@
* Packages that are whitelisted for background throttling (throttling will not be applied).
* @hide
*/
+ @Readable
public static final String LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST =
"location_background_throttle_package_whitelist";
@@ -10114,6 +10710,7 @@
* @hide
*/
@TestApi
+ @Readable
public static final String LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST =
"location_ignore_settings_package_whitelist";
@@ -10122,23 +10719,26 @@
* (0 = false, 1 = true)
* @hide
*/
- public static final String MHL_INPUT_SWITCHING_ENABLED = "mhl_input_switching_enabled";
+ @Readable
+ public static final String MHL_INPUT_SWITCHING_ENABLED = "mhl_input_switching_enabled";
- /**
+ /**
* Whether TV will charge the mobile device connected at MHL port. (0 = false, 1 = true)
* @hide
*/
- public static final String MHL_POWER_CHARGE_ENABLED = "mhl_power_charge_enabled";
+ @Readable
+ public static final String MHL_POWER_CHARGE_ENABLED = "mhl_power_charge_enabled";
- /**
+ /**
* Whether mobile data connections are allowed by the user. See
* ConnectivityManager for more info.
* @hide
*/
- @UnsupportedAppUsage
- public static final String MOBILE_DATA = "mobile_data";
+ @UnsupportedAppUsage
+ @Readable
+ public static final String MOBILE_DATA = "mobile_data";
- /**
+ /**
* Whether the mobile data connection should remain active even when higher
* priority networks like WiFi are active, to help make network switching faster.
*
@@ -10147,7 +10747,8 @@
* (0 = disabled, 1 = enabled)
* @hide
*/
- public static final String MOBILE_DATA_ALWAYS_ON = "mobile_data_always_on";
+ @Readable
+ public static final String MOBILE_DATA_ALWAYS_ON = "mobile_data_always_on";
/**
* Whether the wifi data connection should remain active even when higher
@@ -10160,195 +10761,249 @@
* (0 = disabled, 1 = enabled)
* @hide
*/
+ @Readable
public static final String WIFI_ALWAYS_REQUESTED = "wifi_always_requested";
/**
* Size of the event buffer for IP connectivity metrics.
* @hide
*/
+ @Readable
public static final String CONNECTIVITY_METRICS_BUFFER_SIZE =
"connectivity_metrics_buffer_size";
- /** {@hide} */
- public static final String NETSTATS_ENABLED = "netstats_enabled";
- /** {@hide} */
- public static final String NETSTATS_POLL_INTERVAL = "netstats_poll_interval";
- /** {@hide} */
- @Deprecated
- public static final String NETSTATS_TIME_CACHE_MAX_AGE = "netstats_time_cache_max_age";
- /** {@hide} */
- public static final String NETSTATS_GLOBAL_ALERT_BYTES = "netstats_global_alert_bytes";
- /** {@hide} */
- public static final String NETSTATS_SAMPLE_ENABLED = "netstats_sample_enabled";
- /** {@hide} */
- public static final String NETSTATS_AUGMENT_ENABLED = "netstats_augment_enabled";
- /** {@hide} */
- public static final String NETSTATS_COMBINE_SUBTYPE_ENABLED = "netstats_combine_subtype_enabled";
+ /** {@hide} */
+ @Readable
+ public static final String NETSTATS_ENABLED = "netstats_enabled";
+ /** {@hide} */
+ @Readable
+ public static final String NETSTATS_POLL_INTERVAL = "netstats_poll_interval";
+ /**
+ * @deprecated
+ * {@hide}
+ */
+ @Deprecated
+ @Readable
+ public static final String NETSTATS_TIME_CACHE_MAX_AGE = "netstats_time_cache_max_age";
+ /** {@hide} */
+ @Readable
+ public static final String NETSTATS_GLOBAL_ALERT_BYTES = "netstats_global_alert_bytes";
+ /** {@hide} */
+ @Readable
+ public static final String NETSTATS_SAMPLE_ENABLED = "netstats_sample_enabled";
+ /** {@hide} */
+ @Readable
+ public static final String NETSTATS_AUGMENT_ENABLED = "netstats_augment_enabled";
+ /** {@hide} */
+ @Readable
+ public static final String NETSTATS_COMBINE_SUBTYPE_ENABLED =
+ "netstats_combine_subtype_enabled";
- /** {@hide} */
- public static final String NETSTATS_DEV_BUCKET_DURATION = "netstats_dev_bucket_duration";
- /** {@hide} */
- public static final String NETSTATS_DEV_PERSIST_BYTES = "netstats_dev_persist_bytes";
- /** {@hide} */
- public static final String NETSTATS_DEV_ROTATE_AGE = "netstats_dev_rotate_age";
- /** {@hide} */
- public static final String NETSTATS_DEV_DELETE_AGE = "netstats_dev_delete_age";
+ /** {@hide} */
+ @Readable
+ public static final String NETSTATS_DEV_BUCKET_DURATION = "netstats_dev_bucket_duration";
+ /** {@hide} */
+ @Readable
+ public static final String NETSTATS_DEV_PERSIST_BYTES = "netstats_dev_persist_bytes";
+ /** {@hide} */
+ @Readable
+ public static final String NETSTATS_DEV_ROTATE_AGE = "netstats_dev_rotate_age";
+ /** {@hide} */
+ @Readable
+ public static final String NETSTATS_DEV_DELETE_AGE = "netstats_dev_delete_age";
- /** {@hide} */
- public static final String NETSTATS_UID_BUCKET_DURATION = "netstats_uid_bucket_duration";
- /** {@hide} */
- public static final String NETSTATS_UID_PERSIST_BYTES = "netstats_uid_persist_bytes";
- /** {@hide} */
- public static final String NETSTATS_UID_ROTATE_AGE = "netstats_uid_rotate_age";
- /** {@hide} */
- public static final String NETSTATS_UID_DELETE_AGE = "netstats_uid_delete_age";
+ /** {@hide} */
+ @Readable
+ public static final String NETSTATS_UID_BUCKET_DURATION = "netstats_uid_bucket_duration";
+ /** {@hide} */
+ @Readable
+ public static final String NETSTATS_UID_PERSIST_BYTES = "netstats_uid_persist_bytes";
+ /** {@hide} */
+ @Readable
+ public static final String NETSTATS_UID_ROTATE_AGE = "netstats_uid_rotate_age";
+ /** {@hide} */
+ @Readable
+ public static final String NETSTATS_UID_DELETE_AGE = "netstats_uid_delete_age";
- /** {@hide} */
- public static final String NETSTATS_UID_TAG_BUCKET_DURATION = "netstats_uid_tag_bucket_duration";
- /** {@hide} */
- public static final String NETSTATS_UID_TAG_PERSIST_BYTES = "netstats_uid_tag_persist_bytes";
- /** {@hide} */
- public static final String NETSTATS_UID_TAG_ROTATE_AGE = "netstats_uid_tag_rotate_age";
- /** {@hide} */
- public static final String NETSTATS_UID_TAG_DELETE_AGE = "netstats_uid_tag_delete_age";
+ /** {@hide} */
+ @Readable
+ public static final String NETSTATS_UID_TAG_BUCKET_DURATION =
+ "netstats_uid_tag_bucket_duration";
+ /** {@hide} */
+ @Readable
+ public static final String NETSTATS_UID_TAG_PERSIST_BYTES =
+ "netstats_uid_tag_persist_bytes";
+ /** {@hide} */
+ @Readable
+ public static final String NETSTATS_UID_TAG_ROTATE_AGE = "netstats_uid_tag_rotate_age";
+ /** {@hide} */
+ @Readable
+ public static final String NETSTATS_UID_TAG_DELETE_AGE = "netstats_uid_tag_delete_age";
- /** {@hide} */
- public static final String NETPOLICY_QUOTA_ENABLED = "netpolicy_quota_enabled";
- /** {@hide} */
- public static final String NETPOLICY_QUOTA_UNLIMITED = "netpolicy_quota_unlimited";
- /** {@hide} */
- public static final String NETPOLICY_QUOTA_LIMITED = "netpolicy_quota_limited";
- /** {@hide} */
- public static final String NETPOLICY_QUOTA_FRAC_JOBS = "netpolicy_quota_frac_jobs";
- /** {@hide} */
- public static final String NETPOLICY_QUOTA_FRAC_MULTIPATH = "netpolicy_quota_frac_multipath";
+ /** {@hide} */
+ @Readable
+ public static final String NETPOLICY_QUOTA_ENABLED = "netpolicy_quota_enabled";
+ /** {@hide} */
+ @Readable
+ public static final String NETPOLICY_QUOTA_UNLIMITED = "netpolicy_quota_unlimited";
+ /** {@hide} */
+ @Readable
+ public static final String NETPOLICY_QUOTA_LIMITED = "netpolicy_quota_limited";
+ /** {@hide} */
+ @Readable
+ public static final String NETPOLICY_QUOTA_FRAC_JOBS = "netpolicy_quota_frac_jobs";
+ /** {@hide} */
+ @Readable
+ public static final String NETPOLICY_QUOTA_FRAC_MULTIPATH =
+ "netpolicy_quota_frac_multipath";
- /** {@hide} */
- public static final String NETPOLICY_OVERRIDE_ENABLED = "netpolicy_override_enabled";
+ /** {@hide} */
+ @Readable
+ public static final String NETPOLICY_OVERRIDE_ENABLED = "netpolicy_override_enabled";
- /**
+ /**
* User preference for which network(s) should be used. Only the
* connectivity service should touch this.
*/
- public static final String NETWORK_PREFERENCE = "network_preference";
+ @Readable
+ public static final String NETWORK_PREFERENCE = "network_preference";
- /**
+ /**
* Which package name to use for network scoring. If null, or if the package is not a valid
* scorer app, external network scores will neither be requested nor accepted.
* @hide
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final String NETWORK_SCORER_APP = "network_scorer_app";
+ @Readable
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ public static final String NETWORK_SCORER_APP = "network_scorer_app";
/**
* Whether night display forced auto mode is available.
* 0 = unavailable, 1 = available.
* @hide
*/
+ @Readable
public static final String NIGHT_DISPLAY_FORCED_AUTO_MODE_AVAILABLE =
"night_display_forced_auto_mode_available";
- /**
+ /**
* If the NITZ_UPDATE_DIFF time is exceeded then an automatic adjustment
* to SystemClock will be allowed even if NITZ_UPDATE_SPACING has not been
* exceeded.
* @hide
*/
- public static final String NITZ_UPDATE_DIFF = "nitz_update_diff";
+ @Readable
+ public static final String NITZ_UPDATE_DIFF = "nitz_update_diff";
- /**
+ /**
* The length of time in milli-seconds that automatic small adjustments to
* SystemClock are ignored if NITZ_UPDATE_DIFF is not exceeded.
* @hide
*/
- public static final String NITZ_UPDATE_SPACING = "nitz_update_spacing";
+ @Readable
+ public static final String NITZ_UPDATE_SPACING = "nitz_update_spacing";
- /** Preferred NTP server. {@hide} */
- public static final String NTP_SERVER = "ntp_server";
- /** Timeout in milliseconds to wait for NTP server. {@hide} */
- public static final String NTP_TIMEOUT = "ntp_timeout";
+ /** Preferred NTP server. {@hide} */
+ @Readable
+ public static final String NTP_SERVER = "ntp_server";
+ /** Timeout in milliseconds to wait for NTP server. {@hide} */
+ @Readable
+ public static final String NTP_TIMEOUT = "ntp_timeout";
- /** {@hide} */
- public static final String STORAGE_BENCHMARK_INTERVAL = "storage_benchmark_interval";
+ /** {@hide} */
+ @Readable
+ public static final String STORAGE_BENCHMARK_INTERVAL = "storage_benchmark_interval";
/**
* Whether or not Settings should enable psd API.
* {@hide}
*/
+ @Readable
public static final String SETTINGS_USE_PSD_API = "settings_use_psd_api";
/**
* Whether or not Settings should enable external provider API.
* {@hide}
*/
+ @Readable
public static final String SETTINGS_USE_EXTERNAL_PROVIDER_API =
"settings_use_external_provider_api";
- /**
+ /**
* Sample validity in seconds to configure for the system DNS resolver.
* {@hide}
*/
- public static final String DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS =
+ @Readable
+ public static final String DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS =
"dns_resolver_sample_validity_seconds";
- /**
+ /**
* Success threshold in percent for use with the system DNS resolver.
* {@hide}
*/
- public static final String DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT =
+ @Readable
+ public static final String DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT =
"dns_resolver_success_threshold_percent";
- /**
+ /**
* Minimum number of samples needed for statistics to be considered meaningful in the
* system DNS resolver.
* {@hide}
*/
- public static final String DNS_RESOLVER_MIN_SAMPLES = "dns_resolver_min_samples";
+ @Readable
+ public static final String DNS_RESOLVER_MIN_SAMPLES = "dns_resolver_min_samples";
- /**
+ /**
* Maximum number taken into account for statistics purposes in the system DNS resolver.
* {@hide}
*/
- public static final String DNS_RESOLVER_MAX_SAMPLES = "dns_resolver_max_samples";
+ @Readable
+ public static final String DNS_RESOLVER_MAX_SAMPLES = "dns_resolver_max_samples";
- /**
+ /**
* Whether to disable the automatic scheduling of system updates.
* 1 = system updates won't be automatically scheduled (will always
* present notification instead).
* 0 = system updates will be automatically scheduled. (default)
* @hide
*/
- @SystemApi
- public static final String OTA_DISABLE_AUTOMATIC_UPDATE = "ota_disable_automatic_update";
+ @SystemApi
+ @Readable
+ public static final String OTA_DISABLE_AUTOMATIC_UPDATE = "ota_disable_automatic_update";
- /** Timeout for package verification.
+ /** Timeout for package verification.
* @hide */
- public static final String PACKAGE_VERIFIER_TIMEOUT = "verifier_timeout";
+ @Readable
+ public static final String PACKAGE_VERIFIER_TIMEOUT = "verifier_timeout";
/** Timeout for app integrity verification.
* @hide */
+ @Readable
public static final String APP_INTEGRITY_VERIFICATION_TIMEOUT =
"app_integrity_verification_timeout";
- /** Default response code for package verification.
+ /** Default response code for package verification.
* @hide */
- public static final String PACKAGE_VERIFIER_DEFAULT_RESPONSE = "verifier_default_response";
+ @Readable
+ public static final String PACKAGE_VERIFIER_DEFAULT_RESPONSE = "verifier_default_response";
- /**
+ /**
* Show package verification setting in the Settings app.
* 1 = show (default)
* 0 = hide
* @hide
*/
- public static final String PACKAGE_VERIFIER_SETTING_VISIBLE = "verifier_setting_visible";
+ @Readable
+ public static final String PACKAGE_VERIFIER_SETTING_VISIBLE = "verifier_setting_visible";
- /**
+ /**
* Run package verification on apps installed through ADB/ADT/USB
* 1 = perform package verification on ADB installs (default)
* 0 = bypass package verification on ADB installs
* @hide
*/
- public static final String PACKAGE_VERIFIER_INCLUDE_ADB = "verifier_verify_adb_installs";
+ @Readable
+ public static final String PACKAGE_VERIFIER_INCLUDE_ADB = "verifier_verify_adb_installs";
/**
* Run integrity checks for integrity rule providers.
@@ -10356,117 +11011,131 @@
* 1 = perform integrity verification on installs from rule providers
* @hide
*/
+ @Readable
public static final String INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER =
"verify_integrity_for_rule_provider";
- /**
+ /**
* Time since last fstrim (milliseconds) after which we force one to happen
* during device startup. If unset, the default is 3 days.
* @hide
*/
- public static final String FSTRIM_MANDATORY_INTERVAL = "fstrim_mandatory_interval";
+ @Readable
+ public static final String FSTRIM_MANDATORY_INTERVAL = "fstrim_mandatory_interval";
- /**
+ /**
* The interval in milliseconds at which to check packet counts on the
* mobile data interface when screen is on, to detect possible data
* connection problems.
* @hide
*/
- public static final String PDP_WATCHDOG_POLL_INTERVAL_MS =
+ @Readable
+ public static final String PDP_WATCHDOG_POLL_INTERVAL_MS =
"pdp_watchdog_poll_interval_ms";
- /**
+ /**
* The interval in milliseconds at which to check packet counts on the
* mobile data interface when screen is off, to detect possible data
* connection problems.
* @hide
*/
- public static final String PDP_WATCHDOG_LONG_POLL_INTERVAL_MS =
+ @Readable
+ public static final String PDP_WATCHDOG_LONG_POLL_INTERVAL_MS =
"pdp_watchdog_long_poll_interval_ms";
- /**
+ /**
* The interval in milliseconds at which to check packet counts on the
* mobile data interface after {@link #PDP_WATCHDOG_TRIGGER_PACKET_COUNT}
* outgoing packets has been reached without incoming packets.
* @hide
*/
- public static final String PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS =
+ @Readable
+ public static final String PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS =
"pdp_watchdog_error_poll_interval_ms";
- /**
+ /**
* The number of outgoing packets sent without seeing an incoming packet
* that triggers a countdown (of {@link #PDP_WATCHDOG_ERROR_POLL_COUNT}
* device is logged to the event log
* @hide
*/
- public static final String PDP_WATCHDOG_TRIGGER_PACKET_COUNT =
+ @Readable
+ public static final String PDP_WATCHDOG_TRIGGER_PACKET_COUNT =
"pdp_watchdog_trigger_packet_count";
- /**
+ /**
* The number of polls to perform (at {@link #PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS})
* after hitting {@link #PDP_WATCHDOG_TRIGGER_PACKET_COUNT} before
* attempting data connection recovery.
* @hide
*/
- public static final String PDP_WATCHDOG_ERROR_POLL_COUNT =
+ @Readable
+ public static final String PDP_WATCHDOG_ERROR_POLL_COUNT =
"pdp_watchdog_error_poll_count";
- /**
+ /**
* The number of failed PDP reset attempts before moving to something more
* drastic: re-registering to the network.
* @hide
*/
- public static final String PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT =
+ @Readable
+ public static final String PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT =
"pdp_watchdog_max_pdp_reset_fail_count";
- /**
+ /**
* URL to open browser on to allow user to manage a prepay account
* @hide
*/
- public static final String SETUP_PREPAID_DATA_SERVICE_URL =
+ @Readable
+ public static final String SETUP_PREPAID_DATA_SERVICE_URL =
"setup_prepaid_data_service_url";
- /**
+ /**
* URL to attempt a GET on to see if this is a prepay device
* @hide
*/
- public static final String SETUP_PREPAID_DETECTION_TARGET_URL =
+ @Readable
+ public static final String SETUP_PREPAID_DETECTION_TARGET_URL =
"setup_prepaid_detection_target_url";
- /**
+ /**
* Host to check for a redirect to after an attempt to GET
* SETUP_PREPAID_DETECTION_TARGET_URL. (If we redirected there,
* this is a prepaid device with zero balance.)
* @hide
*/
- public static final String SETUP_PREPAID_DETECTION_REDIR_HOST =
+ @Readable
+ public static final String SETUP_PREPAID_DETECTION_REDIR_HOST =
"setup_prepaid_detection_redir_host";
- /**
+ /**
* The interval in milliseconds at which to check the number of SMS sent out without asking
* for use permit, to limit the un-authorized SMS usage.
*
* @hide
*/
- public static final String SMS_OUTGOING_CHECK_INTERVAL_MS =
+ @Readable
+ public static final String SMS_OUTGOING_CHECK_INTERVAL_MS =
"sms_outgoing_check_interval_ms";
- /**
+ /**
* The number of outgoing SMS sent without asking for user permit (of {@link
* #SMS_OUTGOING_CHECK_INTERVAL_MS}
*
* @hide
*/
- public static final String SMS_OUTGOING_CHECK_MAX_COUNT =
+ @Readable
+ public static final String SMS_OUTGOING_CHECK_MAX_COUNT =
"sms_outgoing_check_max_count";
- /**
+ /**
* Used to disable SMS short code confirmation - defaults to true.
* True indcates we will do the check, etc. Set to false to disable.
* @see com.android.internal.telephony.SmsUsageMonitor
* @hide
*/
- public static final String SMS_SHORT_CODE_CONFIRMATION = "sms_short_code_confirmation";
+ @Readable
+ public static final String SMS_SHORT_CODE_CONFIRMATION = "sms_short_code_confirmation";
/**
* Used to select which country we use to determine premium sms codes.
@@ -10475,6 +11144,7 @@
* or com.android.internal.telephony.SMSDispatcher.PREMIUM_RULE_USE_BOTH.
* @hide
*/
+ @Readable
public static final String SMS_SHORT_CODE_RULE = "sms_short_code_rule";
/**
@@ -10482,6 +11152,7 @@
* build config value.
* @hide
*/
+ @Readable
public static final String TCP_DEFAULT_INIT_RWND = "tcp_default_init_rwnd";
/**
@@ -10489,6 +11160,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String TETHER_SUPPORTED = "tether_supported";
/**
@@ -10496,6 +11168,7 @@
* which defaults to false.
* @hide
*/
+ @Readable
public static final String TETHER_DUN_REQUIRED = "tether_dun_required";
/**
@@ -10507,6 +11180,7 @@
* note that empty fields can be omitted: "name,apn,,,,,,,,,310,260,,DUN"
* @hide
*/
+ @Readable
public static final String TETHER_DUN_APN = "tether_dun_apn";
/**
@@ -10517,6 +11191,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String TETHER_OFFLOAD_DISABLED = "tether_offload_disabled";
/**
@@ -10526,6 +11201,7 @@
* is interpreted as |false|.
* @hide
*/
+ @Readable
public static final String TETHER_ENABLE_LEGACY_DHCP_SERVER =
"tether_enable_legacy_dhcp_server";
@@ -10540,6 +11216,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String CARRIER_APP_WHITELIST = "carrier_app_whitelist";
/**
@@ -10550,62 +11227,71 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String CARRIER_APP_NAMES = "carrier_app_names";
- /**
+ /**
* USB Mass Storage Enabled
*/
- public static final String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
+ @Readable
+ public static final String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
- /**
+ /**
* If this setting is set (to anything), then all references
* to Gmail on the device must change to Google Mail.
*/
- public static final String USE_GOOGLE_MAIL = "use_google_mail";
+ @Readable
+ public static final String USE_GOOGLE_MAIL = "use_google_mail";
/**
* Whether or not switching/creating users is enabled by user.
* @hide
*/
+ @Readable
public static final String USER_SWITCHER_ENABLED = "user_switcher_enabled";
/**
* Webview Data reduction proxy key.
* @hide
*/
+ @Readable
public static final String WEBVIEW_DATA_REDUCTION_PROXY_KEY =
"webview_data_reduction_proxy_key";
- /**
+ /**
* Name of the package used as WebView provider (if unset the provider is instead determined
* by the system).
* @hide
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final String WEBVIEW_PROVIDER = "webview_provider";
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @Readable
+ public static final String WEBVIEW_PROVIDER = "webview_provider";
- /**
+ /**
* Developer setting to enable WebView multiprocess rendering.
* @hide
*/
- @SystemApi
- public static final String WEBVIEW_MULTIPROCESS = "webview_multiprocess";
+ @SystemApi
+ @Readable
+ public static final String WEBVIEW_MULTIPROCESS = "webview_multiprocess";
- /**
+ /**
* The maximum number of notifications shown in 24 hours when switching networks.
* @hide
*/
- public static final String NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT =
+ @Readable
+ public static final String NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT =
"network_switch_notification_daily_limit";
- /**
+ /**
* The minimum time in milliseconds between notifications when switching networks.
* @hide
*/
- public static final String NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS =
+ @Readable
+ public static final String NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS =
"network_switch_notification_rate_limit_millis";
- /**
+ /**
* Whether to automatically switch away from wifi networks that lose Internet access.
* Only meaningful if config_networkAvoidBadWifi is set to 0, otherwise the system always
* avoids such networks. Valid values are:
@@ -10616,16 +11302,18 @@
*
* @hide
*/
- public static final String NETWORK_AVOID_BAD_WIFI = "network_avoid_bad_wifi";
+ @Readable
+ public static final String NETWORK_AVOID_BAD_WIFI = "network_avoid_bad_wifi";
- /**
+ /**
* User setting for ConnectivityManager.getMeteredMultipathPreference(). This value may be
* overridden by the system based on device or application state. If null, the value
* specified by config_networkMeteredMultipathPreference is used.
*
* @hide
*/
- public static final String NETWORK_METERED_MULTIPATH_PREFERENCE =
+ @Readable
+ public static final String NETWORK_METERED_MULTIPATH_PREFERENCE =
"network_metered_multipath_preference";
/**
@@ -10634,6 +11322,7 @@
* from data plan or data limit/warning set by the user.
* @hide
*/
+ @Readable
public static final String NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES =
"network_default_daily_multipath_quota_bytes";
@@ -10641,10 +11330,11 @@
* Network watchlist last report time.
* @hide
*/
+ @Readable
public static final String NETWORK_WATCHLIST_LAST_REPORT_TIME =
"network_watchlist_last_report_time";
- /**
+ /**
* The thresholds of the wifi throughput badging (SD, HD etc.) as a comma-delimited list of
* colon-delimited key-value pairs. The key is the badging enum value defined in
* android.net.ScoredNetwork and the value is the minimum sustained network throughput in
@@ -10652,25 +11342,28 @@
*
* @hide
*/
- @SystemApi
- public static final String WIFI_BADGING_THRESHOLDS = "wifi_badging_thresholds";
+ @SystemApi
+ @Readable
+ public static final String WIFI_BADGING_THRESHOLDS = "wifi_badging_thresholds";
- /**
+ /**
* Whether Wifi display is enabled/disabled
* 0=disabled. 1=enabled.
* @hide
*/
- public static final String WIFI_DISPLAY_ON = "wifi_display_on";
+ @Readable
+ public static final String WIFI_DISPLAY_ON = "wifi_display_on";
- /**
+ /**
* Whether Wifi display certification mode is enabled/disabled
* 0=disabled. 1=enabled.
* @hide
*/
- public static final String WIFI_DISPLAY_CERTIFICATION_ON =
+ @Readable
+ public static final String WIFI_DISPLAY_CERTIFICATION_ON =
"wifi_display_certification_on";
- /**
+ /**
* WPS Configuration method used by Wifi display, this setting only
* takes effect when WIFI_DISPLAY_CERTIFICATION_ON is 1 (enabled).
*
@@ -10682,10 +11375,11 @@
* WpsInfo.DISPLAY: use Display
* @hide
*/
- public static final String WIFI_DISPLAY_WPS_CONFIG =
+ @Readable
+ public static final String WIFI_DISPLAY_WPS_CONFIG =
"wifi_display_wps_config";
- /**
+ /**
* Whether to notify the user of open networks.
* <p>
* If not connected and the scan results have an open network, we will
@@ -10697,68 +11391,78 @@
* @deprecated This feature is no longer controlled by this setting in
* {@link android.os.Build.VERSION_CODES#O}.
*/
- @Deprecated
- public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON =
+ @Deprecated
+ @Readable
+ public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON =
"wifi_networks_available_notification_on";
- /**
+ /**
* {@hide}
*/
- public static final String WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON =
+ @Readable
+ public static final String WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON =
"wimax_networks_available_notification_on";
- /**
+ /**
* Delay (in seconds) before repeating the Wi-Fi networks available notification.
* Connecting to a network will reset the timer.
* @deprecated This is no longer used or set by the platform.
*/
- @Deprecated
- public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY =
+ @Deprecated
+ @Readable
+ public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY =
"wifi_networks_available_repeat_delay";
- /**
+ /**
* 802.11 country code in ISO 3166 format
* @hide
*/
- public static final String WIFI_COUNTRY_CODE = "wifi_country_code";
+ @Readable
+ public static final String WIFI_COUNTRY_CODE = "wifi_country_code";
- /**
+ /**
* The interval in milliseconds to issue wake up scans when wifi needs
* to connect. This is necessary to connect to an access point when
* device is on the move and the screen is off.
* @hide
*/
- public static final String WIFI_FRAMEWORK_SCAN_INTERVAL_MS =
+ @Readable
+ public static final String WIFI_FRAMEWORK_SCAN_INTERVAL_MS =
"wifi_framework_scan_interval_ms";
- /**
+ /**
* The interval in milliseconds after which Wi-Fi is considered idle.
* When idle, it is possible for the device to be switched from Wi-Fi to
* the mobile data network.
* @hide
*/
- public static final String WIFI_IDLE_MS = "wifi_idle_ms";
+ @Readable
+ public static final String WIFI_IDLE_MS = "wifi_idle_ms";
- /**
+ /**
* When the number of open networks exceeds this number, the
* least-recently-used excess networks will be removed.
* @deprecated This is no longer used or set by the platform.
*/
- @Deprecated
- public static final String WIFI_NUM_OPEN_NETWORKS_KEPT = "wifi_num_open_networks_kept";
+ @Deprecated
+ @Readable
+ public static final String WIFI_NUM_OPEN_NETWORKS_KEPT = "wifi_num_open_networks_kept";
- /**
+ /**
* Whether the Wi-Fi should be on. Only the Wi-Fi service should touch this.
*/
- public static final String WIFI_ON = "wifi_on";
+ @Readable
+ public static final String WIFI_ON = "wifi_on";
- /**
+ /**
* Setting to allow scans to be enabled even wifi is turned off for connectivity.
* @hide
* @deprecated To be removed. Use {@link WifiManager#setScanAlwaysAvailable(boolean)} for
* setting the value and {@link WifiManager#isScanAlwaysAvailable()} for query.
*/
- public static final String WIFI_SCAN_ALWAYS_AVAILABLE =
+ @Deprecated
+ @Readable
+ public static final String WIFI_SCAN_ALWAYS_AVAILABLE =
"wifi_scan_always_enabled";
/**
@@ -10768,6 +11472,8 @@
* @hide
* @deprecated To be removed.
*/
+ @Deprecated
+ @Readable
public static final String WIFI_P2P_PENDING_FACTORY_RESET =
"wifi_p2p_pending_factory_reset";
@@ -10780,6 +11486,8 @@
* setAutoShutdownEnabled(boolean)} for setting the value and {@link SoftApConfiguration#
* isAutoShutdownEnabled()} for query.
*/
+ @Deprecated
+ @Readable
public static final String SOFT_AP_TIMEOUT_ENABLED = "soft_ap_timeout_enabled";
/**
@@ -10792,6 +11500,7 @@
*/
@Deprecated
@SystemApi
+ @Readable
public static final String WIFI_WAKEUP_ENABLED = "wifi_wakeup_enabled";
/**
@@ -10801,6 +11510,7 @@
* Type: int (0 for false, 1 for true)
* @hide
*/
+ @Readable
public static final String WIFI_MIGRATION_COMPLETED = "wifi_migration_completed";
/**
@@ -10809,6 +11519,7 @@
* Type: int (0 for false, 1 for true)
* @hide
*/
+ @Readable
public static final String NETWORK_SCORING_UI_ENABLED = "network_scoring_ui_enabled";
/**
@@ -10818,6 +11529,7 @@
* Type: long
* @hide
*/
+ @Readable
public static final String SPEED_LABEL_CACHE_EVICTION_AGE_MILLIS =
"speed_label_cache_eviction_age_millis";
@@ -10836,6 +11548,8 @@
* @hide
* @deprecated To be removed.
*/
+ @Deprecated
+ @Readable
public static final String NETWORK_RECOMMENDATIONS_ENABLED =
"network_recommendations_enabled";
@@ -10849,6 +11563,7 @@
* Type: string - package name
* @hide
*/
+ @Readable
public static final String NETWORK_RECOMMENDATIONS_PACKAGE =
"network_recommendations_package";
@@ -10860,6 +11575,7 @@
* @hide
*/
@TestApi
+ @Readable
public static final String USE_OPEN_WIFI_PACKAGE = "use_open_wifi_package";
/**
@@ -10869,6 +11585,7 @@
* Type: long
* @hide
*/
+ @Readable
public static final String RECOMMENDED_NETWORK_EVALUATOR_CACHE_EXPIRY_MS =
"recommended_network_evaluator_cache_expiry_ms";
@@ -10880,6 +11597,8 @@
* @deprecated Use {@link WifiManager#setScanThrottleEnabled(boolean)} for setting the value
* and {@link WifiManager#isScanThrottleEnabled()} for query.
*/
+ @Deprecated
+ @Readable
public static final String WIFI_SCAN_THROTTLE_ENABLED = "wifi_scan_throttle_enabled";
/**
@@ -10887,24 +11606,28 @@
* connectivity.
* @hide
*/
+ @Readable
public static final String BLE_SCAN_ALWAYS_AVAILABLE = "ble_scan_always_enabled";
/**
* The length in milliseconds of a BLE scan window in a low-power scan mode.
* @hide
*/
+ @Readable
public static final String BLE_SCAN_LOW_POWER_WINDOW_MS = "ble_scan_low_power_window_ms";
/**
* The length in milliseconds of a BLE scan window in a balanced scan mode.
* @hide
*/
+ @Readable
public static final String BLE_SCAN_BALANCED_WINDOW_MS = "ble_scan_balanced_window_ms";
/**
* The length in milliseconds of a BLE scan window in a low-latency scan mode.
* @hide
*/
+ @Readable
public static final String BLE_SCAN_LOW_LATENCY_WINDOW_MS =
"ble_scan_low_latency_window_ms";
@@ -10912,6 +11635,7 @@
* The length in milliseconds of a BLE scan interval in a low-power scan mode.
* @hide
*/
+ @Readable
public static final String BLE_SCAN_LOW_POWER_INTERVAL_MS =
"ble_scan_low_power_interval_ms";
@@ -10919,6 +11643,7 @@
* The length in milliseconds of a BLE scan interval in a balanced scan mode.
* @hide
*/
+ @Readable
public static final String BLE_SCAN_BALANCED_INTERVAL_MS =
"ble_scan_balanced_interval_ms";
@@ -10926,6 +11651,7 @@
* The length in milliseconds of a BLE scan interval in a low-latency scan mode.
* @hide
*/
+ @Readable
public static final String BLE_SCAN_LOW_LATENCY_INTERVAL_MS =
"ble_scan_low_latency_interval_ms";
@@ -10933,26 +11659,30 @@
* The mode that BLE scanning clients will be moved to when in the background.
* @hide
*/
+ @Readable
public static final String BLE_SCAN_BACKGROUND_MODE = "ble_scan_background_mode";
- /**
+ /**
* The interval in milliseconds to scan as used by the wifi supplicant
* @hide
*/
- public static final String WIFI_SUPPLICANT_SCAN_INTERVAL_MS =
+ @Readable
+ public static final String WIFI_SUPPLICANT_SCAN_INTERVAL_MS =
"wifi_supplicant_scan_interval_ms";
/**
* whether frameworks handles wifi auto-join
* @hide
*/
- public static final String WIFI_ENHANCED_AUTO_JOIN =
+ @Readable
+ public static final String WIFI_ENHANCED_AUTO_JOIN =
"wifi_enhanced_auto_join";
/**
* whether settings show RSSI
* @hide
*/
+ @Readable
public static final String WIFI_NETWORK_SHOW_RSSI =
"wifi_network_show_rssi";
@@ -10960,31 +11690,36 @@
* The interval in milliseconds to scan at supplicant when p2p is connected
* @hide
*/
- public static final String WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS =
+ @Readable
+ public static final String WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS =
"wifi_scan_interval_p2p_connected_ms";
- /**
+ /**
* Whether the Wi-Fi watchdog is enabled.
*/
- public static final String WIFI_WATCHDOG_ON = "wifi_watchdog_on";
+ @Readable
+ public static final String WIFI_WATCHDOG_ON = "wifi_watchdog_on";
- /**
+ /**
* Setting to turn off poor network avoidance on Wi-Fi. Feature is enabled by default and
* the setting needs to be set to 0 to disable it.
* @hide
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final String WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED =
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @Readable
+ public static final String WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED =
"wifi_watchdog_poor_network_test_enabled";
- /**
+ /**
* Setting to enable verbose logging in Wi-Fi; disabled by default, and setting to 1
* will enable it. In the future, additional values may be supported.
* @hide
* @deprecated Use {@link WifiManager#setVerboseLoggingEnabled(boolean)} for setting the
* value and {@link WifiManager#isVerboseLoggingEnabled()} for query.
*/
- public static final String WIFI_VERBOSE_LOGGING_ENABLED =
+ @Deprecated
+ @Readable
+ public static final String WIFI_VERBOSE_LOGGING_ENABLED =
"wifi_verbose_logging_enabled";
/**
@@ -10994,6 +11729,7 @@
* @hide
*/
@Deprecated
+ @Readable
public static final String WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED =
"wifi_connected_mac_randomization_enabled";
@@ -11010,24 +11746,28 @@
* @hide
* @deprecated This is no longer used or set by the platform.
*/
+ @Deprecated
+ @Readable
public static final String WIFI_SCORE_PARAMS =
"wifi_score_params";
- /**
+ /**
* The maximum number of times we will retry a connection to an access
* point for which we have failed in acquiring an IP address from DHCP.
* A value of N means that we will make N+1 connection attempts in all.
*/
- public static final String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
+ @Readable
+ public static final String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
- /**
+ /**
* Maximum amount of time in milliseconds to hold a wakelock while waiting for mobile
* data connectivity to be established after a disconnect from Wi-Fi.
*/
- public static final String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS =
+ @Readable
+ public static final String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS =
"wifi_mobile_data_transition_wakelock_timeout_ms";
- /**
+ /**
* This setting controls whether WiFi configurations created by a Device Owner app
* should be locked down (that is, be editable or removable only by the Device Owner App,
* not even by Settings app).
@@ -11035,10 +11775,11 @@
* are locked down. Value of zero means they are not. Default value in the absence of
* actual value to this setting is 0.
*/
- public static final String WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN =
+ @Readable
+ public static final String WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN =
"wifi_device_owner_configs_lockdown";
- /**
+ /**
* The operational wifi frequency band
* Set to one of {@link WifiManager#WIFI_FREQUENCY_BAND_AUTO},
* {@link WifiManager#WIFI_FREQUENCY_BAND_5GHZ} or
@@ -11046,18 +11787,21 @@
*
* @hide
*/
- public static final String WIFI_FREQUENCY_BAND = "wifi_frequency_band";
+ @Readable
+ public static final String WIFI_FREQUENCY_BAND = "wifi_frequency_band";
- /**
+ /**
* The Wi-Fi peer-to-peer device name
* @hide
* @deprecated Use {@link WifiP2pManager#setDeviceName(WifiP2pManager.Channel, String,
* WifiP2pManager.ActionListener)} for setting the value and
* {@link android.net.wifi.p2p.WifiP2pDevice#deviceName} for query.
*/
- public static final String WIFI_P2P_DEVICE_NAME = "wifi_p2p_device_name";
+ @Deprecated
+ @Readable
+ public static final String WIFI_P2P_DEVICE_NAME = "wifi_p2p_device_name";
- /**
+ /**
* Timeout for ephemeral networks when all known BSSIDs go out of range. We will disconnect
* from an ephemeral network if there is no BSSID for that network with a non-null score that
* has been seen in this time period.
@@ -11066,53 +11810,60 @@
* for a non-null score from the currently connected or target BSSID.
* @hide
*/
- public static final String WIFI_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS =
+ @Readable
+ public static final String WIFI_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS =
"wifi_ephemeral_out_of_range_timeout_ms";
- /**
+ /**
* The number of milliseconds to delay when checking for data stalls during
* non-aggressive detection. (screen is turned off.)
* @hide
*/
- public static final String DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS =
+ @Readable
+ public static final String DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS =
"data_stall_alarm_non_aggressive_delay_in_ms";
- /**
+ /**
* The number of milliseconds to delay when checking for data stalls during
* aggressive detection. (screen on or suspected data stall)
* @hide
*/
- public static final String DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS =
+ @Readable
+ public static final String DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS =
"data_stall_alarm_aggressive_delay_in_ms";
- /**
+ /**
* The number of milliseconds to allow the provisioning apn to remain active
* @hide
*/
- public static final String PROVISIONING_APN_ALARM_DELAY_IN_MS =
+ @Readable
+ public static final String PROVISIONING_APN_ALARM_DELAY_IN_MS =
"provisioning_apn_alarm_delay_in_ms";
- /**
+ /**
* The interval in milliseconds at which to check gprs registration
* after the first registration mismatch of gprs and voice service,
* to detect possible data network registration problems.
*
* @hide
*/
- public static final String GPRS_REGISTER_CHECK_PERIOD_MS =
+ @Readable
+ public static final String GPRS_REGISTER_CHECK_PERIOD_MS =
"gprs_register_check_period_ms";
- /**
+ /**
* Nonzero causes Log.wtf() to crash.
* @hide
*/
- public static final String WTF_IS_FATAL = "wtf_is_fatal";
+ @Readable
+ public static final String WTF_IS_FATAL = "wtf_is_fatal";
- /**
+ /**
* Ringer mode. This is used internally, changing this value will not
* change the ringer mode. See AudioManager.
*/
- public static final String MODE_RINGER = "mode_ringer";
+ @Readable
+ public static final String MODE_RINGER = "mode_ringer";
/**
* Overlay display devices setting.
@@ -11153,6 +11904,7 @@
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@TestApi
+ @Readable
public static final String OVERLAY_DISPLAY_DEVICES = "overlay_display_devices";
/**
@@ -11161,10 +11913,12 @@
*
* @hide
*/
+ @Readable
public static final String
BATTERY_DISCHARGE_DURATION_THRESHOLD = "battery_discharge_duration_threshold";
/** @hide */
+ @Readable
public static final String BATTERY_DISCHARGE_THRESHOLD = "battery_discharge_threshold";
/**
@@ -11176,6 +11930,7 @@
*
* @hide
*/
+ @Readable
public static final String SEND_ACTION_APP_ERROR = "send_action_app_error";
/**
@@ -11183,6 +11938,7 @@
*
* @hide
*/
+ @Readable
public static final String DROPBOX_AGE_SECONDS = "dropbox_age_seconds";
/**
@@ -11191,6 +11947,7 @@
*
* @hide
*/
+ @Readable
public static final String DROPBOX_MAX_FILES = "dropbox_max_files";
/**
@@ -11199,6 +11956,7 @@
*
* @hide
*/
+ @Readable
public static final String DROPBOX_QUOTA_KB = "dropbox_quota_kb";
/**
@@ -11207,6 +11965,7 @@
*
* @hide
*/
+ @Readable
public static final String DROPBOX_QUOTA_PERCENT = "dropbox_quota_percent";
/**
@@ -11215,6 +11974,7 @@
*
* @hide
*/
+ @Readable
public static final String DROPBOX_RESERVE_PERCENT = "dropbox_reserve_percent";
/**
@@ -11222,6 +11982,7 @@
*
* @hide
*/
+ @Readable
public static final String DROPBOX_TAG_PREFIX = "dropbox:";
/**
@@ -11232,6 +11993,7 @@
*
* @hide
*/
+ @Readable
public static final String ERROR_LOGCAT_PREFIX = "logcat_for_";
/**
@@ -11245,6 +12007,7 @@
*
* @hide
*/
+ @Readable
public static final String MAX_ERROR_BYTES_PREFIX = "max_error_bytes_for_";
/**
@@ -11253,6 +12016,7 @@
*
* @hide
*/
+ @Readable
public static final String SYS_FREE_STORAGE_LOG_INTERVAL = "sys_free_storage_log_interval";
/**
@@ -11262,6 +12026,7 @@
*
* @hide
*/
+ @Readable
public static final String
DISK_FREE_CHANGE_REPORTING_THRESHOLD = "disk_free_change_reporting_threshold";
@@ -11274,6 +12039,7 @@
*
* @hide
*/
+ @Readable
public static final String
SYS_STORAGE_THRESHOLD_PERCENTAGE = "sys_storage_threshold_percentage";
@@ -11285,6 +12051,7 @@
*
* @hide
*/
+ @Readable
public static final String
SYS_STORAGE_THRESHOLD_MAX_BYTES = "sys_storage_threshold_max_bytes";
@@ -11295,6 +12062,7 @@
*
* @hide
*/
+ @Readable
public static final String
SYS_STORAGE_FULL_THRESHOLD_BYTES = "sys_storage_full_threshold_bytes";
@@ -11304,6 +12072,7 @@
*
* @hide
*/
+ @Readable
public static final String
SYS_STORAGE_CACHE_PERCENTAGE = "sys_storage_cache_percentage";
@@ -11313,6 +12082,7 @@
*
* @hide
*/
+ @Readable
public static final String
SYS_STORAGE_CACHE_MAX_BYTES = "sys_storage_cache_max_bytes";
@@ -11322,6 +12092,7 @@
*
* @hide
*/
+ @Readable
public static final String
SYNC_MAX_RETRY_DELAY_IN_SECONDS = "sync_max_retry_delay_in_seconds";
@@ -11331,6 +12102,7 @@
*
* @hide
*/
+ @Readable
public static final String CONNECTIVITY_CHANGE_DELAY = "connectivity_change_delay";
@@ -11340,7 +12112,7 @@
*
* @hide
*/
-
+ @Readable
public static final String CONNECTIVITY_SAMPLING_INTERVAL_IN_SECONDS =
"connectivity_sampling_interval_in_seconds";
@@ -11350,6 +12122,7 @@
*
* @hide
*/
+ @Readable
public static final String PAC_CHANGE_DELAY = "pac_change_delay";
/**
@@ -11382,6 +12155,7 @@
* The default for this setting is CAPTIVE_PORTAL_MODE_PROMPT.
* @hide
*/
+ @Readable
public static final String CAPTIVE_PORTAL_MODE = "captive_portal_mode";
/**
@@ -11392,6 +12166,7 @@
* @hide
*/
@Deprecated
+ @Readable
public static final String
CAPTIVE_PORTAL_DETECTION_ENABLED = "captive_portal_detection_enabled";
@@ -11402,6 +12177,7 @@
*
* @hide
*/
+ @Readable
public static final String CAPTIVE_PORTAL_SERVER = "captive_portal_server";
/**
@@ -11410,6 +12186,7 @@
*
* @hide
*/
+ @Readable
public static final String CAPTIVE_PORTAL_HTTPS_URL = "captive_portal_https_url";
/**
@@ -11418,6 +12195,7 @@
*
* @hide
*/
+ @Readable
public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url";
/**
@@ -11426,6 +12204,7 @@
*
* @hide
*/
+ @Readable
public static final String CAPTIVE_PORTAL_FALLBACK_URL = "captive_portal_fallback_url";
/**
@@ -11434,6 +12213,7 @@
*
* @hide
*/
+ @Readable
public static final String CAPTIVE_PORTAL_OTHER_FALLBACK_URLS =
"captive_portal_other_fallback_urls";
@@ -11443,6 +12223,7 @@
* by "@@,@@".
* @hide
*/
+ @Readable
public static final String CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS =
"captive_portal_fallback_probe_specs";
@@ -11453,6 +12234,7 @@
*
* @hide
*/
+ @Readable
public static final String CAPTIVE_PORTAL_USE_HTTPS = "captive_portal_use_https";
/**
@@ -11461,6 +12243,7 @@
*
* @hide
*/
+ @Readable
public static final String CAPTIVE_PORTAL_USER_AGENT = "captive_portal_user_agent";
/**
@@ -11468,6 +12251,7 @@
*
* @hide
*/
+ @Readable
public static final String DATA_STALL_RECOVERY_ON_BAD_NETWORK =
"data_stall_recovery_on_bad_network";
@@ -11476,6 +12260,7 @@
*
* @hide
*/
+ @Readable
public static final String MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS =
"min_duration_between_recovery_steps";
/**
@@ -11483,6 +12268,7 @@
*
* @hide
*/
+ @Readable
public static final String NSD_ON = "nsd_on";
/**
@@ -11490,6 +12276,7 @@
*
* @hide
*/
+ @Readable
public static final String SET_INSTALL_LOCATION = "set_install_location";
/**
@@ -11499,6 +12286,7 @@
* 2 = sdcard
* @hide
*/
+ @Readable
public static final String DEFAULT_INSTALL_LOCATION = "default_install_location";
/**
@@ -11507,6 +12295,7 @@
*
* @hide
*/
+ @Readable
public static final String
INET_CONDITION_DEBOUNCE_UP_DELAY = "inet_condition_debounce_up_delay";
@@ -11516,10 +12305,12 @@
*
* @hide
*/
+ @Readable
public static final String
INET_CONDITION_DEBOUNCE_DOWN_DELAY = "inet_condition_debounce_down_delay";
/** {@hide} */
+ @Readable
public static final String
READ_EXTERNAL_STORAGE_ENFORCED_DEFAULT = "read_external_storage_enforced_default";
@@ -11527,6 +12318,7 @@
* Host name and port for global http proxy. Uses ':' seperator for
* between host and port.
*/
+ @Readable
public static final String HTTP_PROXY = "http_proxy";
/**
@@ -11534,6 +12326,7 @@
*
* @hide
*/
+ @Readable
public static final String GLOBAL_HTTP_PROXY_HOST = "global_http_proxy_host";
/**
@@ -11541,6 +12334,7 @@
*
* @hide
*/
+ @Readable
public static final String GLOBAL_HTTP_PROXY_PORT = "global_http_proxy_port";
/**
@@ -11552,6 +12346,7 @@
*
* @hide
*/
+ @Readable
public static final String
GLOBAL_HTTP_PROXY_EXCLUSION_LIST = "global_http_proxy_exclusion_list";
@@ -11559,6 +12354,7 @@
* The location PAC File for the proxy.
* @hide
*/
+ @Readable
public static final String
GLOBAL_HTTP_PROXY_PAC = "global_proxy_pac_url";
@@ -11568,6 +12364,7 @@
*
* @hide
*/
+ @Readable
public static final String SET_GLOBAL_HTTP_PROXY = "set_global_http_proxy";
/**
@@ -11575,6 +12372,7 @@
*
* @hide
*/
+ @Readable
public static final String DEFAULT_DNS_SERVER = "default_dns_server";
/**
@@ -11587,11 +12385,13 @@
*
* @hide
*/
+ @Readable
public static final String PRIVATE_DNS_MODE = "private_dns_mode";
/**
* @hide
*/
+ @Readable
public static final String PRIVATE_DNS_SPECIFIER = "private_dns_specifier";
/**
@@ -11603,46 +12403,60 @@
*
* {@hide}
*/
+ @Readable
public static final String PRIVATE_DNS_DEFAULT_MODE = "private_dns_default_mode";
/** {@hide} */
+ @Readable
public static final String
BLUETOOTH_BTSNOOP_DEFAULT_MODE = "bluetooth_btsnoop_default_mode";
/** {@hide} */
+ @Readable
public static final String
BLUETOOTH_HEADSET_PRIORITY_PREFIX = "bluetooth_headset_priority_";
/** {@hide} */
+ @Readable
public static final String
BLUETOOTH_A2DP_SINK_PRIORITY_PREFIX = "bluetooth_a2dp_sink_priority_";
/** {@hide} */
+ @Readable
public static final String
BLUETOOTH_A2DP_SRC_PRIORITY_PREFIX = "bluetooth_a2dp_src_priority_";
/** {@hide} */
+ @Readable
public static final String BLUETOOTH_A2DP_SUPPORTS_OPTIONAL_CODECS_PREFIX =
"bluetooth_a2dp_supports_optional_codecs_";
/** {@hide} */
+ @Readable
public static final String BLUETOOTH_A2DP_OPTIONAL_CODECS_ENABLED_PREFIX =
"bluetooth_a2dp_optional_codecs_enabled_";
/** {@hide} */
+ @Readable
public static final String
BLUETOOTH_INPUT_DEVICE_PRIORITY_PREFIX = "bluetooth_input_device_priority_";
/** {@hide} */
+ @Readable
public static final String
BLUETOOTH_MAP_PRIORITY_PREFIX = "bluetooth_map_priority_";
/** {@hide} */
+ @Readable
public static final String
BLUETOOTH_MAP_CLIENT_PRIORITY_PREFIX = "bluetooth_map_client_priority_";
/** {@hide} */
+ @Readable
public static final String
BLUETOOTH_PBAP_CLIENT_PRIORITY_PREFIX = "bluetooth_pbap_client_priority_";
/** {@hide} */
+ @Readable
public static final String
BLUETOOTH_SAP_PRIORITY_PREFIX = "bluetooth_sap_priority_";
/** {@hide} */
+ @Readable
public static final String
BLUETOOTH_PAN_PRIORITY_PREFIX = "bluetooth_pan_priority_";
/** {@hide} */
+ @Readable
public static final String
BLUETOOTH_HEARING_AID_PRIORITY_PREFIX = "bluetooth_hearing_aid_priority_";
@@ -11651,6 +12465,7 @@
*
* {@hide}
*/
+ @Readable
public static final String
ENABLE_RADIO_BUG_DETECTION = "enable_radio_bug_detection";
@@ -11659,6 +12474,7 @@
*
* {@hide}
*/
+ @Readable
public static final String
RADIO_BUG_WAKELOCK_TIMEOUT_COUNT_THRESHOLD =
"radio_bug_wakelock_timeout_count_threshold";
@@ -11668,6 +12484,7 @@
*
* {@hide}
*/
+ @Readable
public static final String
RADIO_BUG_SYSTEM_ERROR_COUNT_THRESHOLD =
"radio_bug_system_error_count_threshold";
@@ -11714,6 +12531,7 @@
* @hide
* @see com.android.server.am.ActivityManagerConstants
*/
+ @Readable
public static final String ACTIVITY_MANAGER_CONSTANTS = "activity_manager_constants";
/**
@@ -11722,6 +12540,7 @@
* Default: 1
* @hide
*/
+ @Readable
public static final String ACTIVITY_STARTS_LOGGING_ENABLED
= "activity_starts_logging_enabled";
@@ -11731,6 +12550,7 @@
* Default: 1
* @hide
*/
+ @Readable
public static final String FOREGROUND_SERVICE_STARTS_LOGGING_ENABLED =
"foreground_service_starts_logging_enabled";
@@ -11738,6 +12558,7 @@
* @hide
* @see com.android.server.appbinding.AppBindingConstants
*/
+ @Readable
public static final String APP_BINDING_CONSTANTS = "app_binding_constants";
/**
@@ -11760,6 +12581,7 @@
* @see com.android.server.AppOpsService.Constants
*/
@TestApi
+ @Readable
public static final String APP_OPS_CONSTANTS = "app_ops_constants";
/**
@@ -11795,6 +12617,7 @@
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@TestApi
+ @Readable
public static final String BATTERY_SAVER_CONSTANTS = "battery_saver_constants";
/**
@@ -11812,6 +12635,7 @@
*
* @hide
*/
+ @Readable
public static final String BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS =
"battery_saver_device_specific_constants";
@@ -11841,6 +12665,7 @@
* </pre>
* @hide
*/
+ @Readable
public static final String BATTERY_TIP_CONSTANTS = "battery_tip_constants";
/**
@@ -11866,6 +12691,7 @@
* </pre>
* @hide
*/
+ @Readable
public static final String ANOMALY_DETECTION_CONSTANTS = "anomaly_detection_constants";
/**
@@ -11873,6 +12699,7 @@
* current version is 1.
* @hide
*/
+ @Readable
public static final String ANOMALY_CONFIG_VERSION = "anomaly_config_version";
/**
@@ -11880,6 +12707,7 @@
* {@link android.app.StatsManager}.
* @hide
*/
+ @Readable
public static final String ANOMALY_CONFIG = "anomaly_config";
/**
@@ -11899,6 +12727,7 @@
* </pre>
* @hide
*/
+ @Readable
public static final String ALWAYS_ON_DISPLAY_CONSTANTS = "always_on_display_constants";
/**
@@ -11909,6 +12738,7 @@
* Any other value defaults to enabled.
* @hide
*/
+ @Readable
public static final String SYS_UIDCPUPOWER = "sys_uidcpupower";
/**
@@ -11920,6 +12750,7 @@
* Any other value defaults to disabled.
* @hide
*/
+ @Readable
public static final String SYS_TRACED = "sys_traced";
/**
@@ -11928,6 +12759,7 @@
*
* @hide
*/
+ @Readable
public static final String FPS_DEVISOR = "fps_divisor";
/**
@@ -11937,6 +12769,7 @@
*
* @hide
*/
+ @Readable
public static final String DISPLAY_PANEL_LPM = "display_panel_lpm";
/**
@@ -11951,6 +12784,7 @@
* Need to reboot the device for this setting to take effect.
* @hide
*/
+ @Readable
public static final String APP_TIME_LIMIT_USAGE_SOURCE = "app_time_limit_usage_source";
/**
@@ -11958,6 +12792,7 @@
* 0 = disable, 1 = enable.
* @hide
*/
+ @Readable
public static final String ART_VERIFIER_VERIFY_DEBUGGABLE =
"art_verifier_verify_debuggable";
@@ -11978,6 +12813,7 @@
* @hide
* @see com.android.server.power.PowerManagerConstants
*/
+ @Readable
public static final String POWER_MANAGER_CONSTANTS = "power_manager_constants";
/**
@@ -12003,6 +12839,7 @@
* @hide
* @see com.android.server.pm.ShortcutService.ConfigConstants
*/
+ @Readable
public static final String SHORTCUT_MANAGER_CONSTANTS = "shortcut_manager_constants";
/**
@@ -12020,6 +12857,7 @@
* @hide
* see also com.android.server.devicepolicy.DevicePolicyConstants
*/
+ @Readable
public static final String DEVICE_POLICY_CONSTANTS = "device_policy_constants";
/**
@@ -12056,6 +12894,7 @@
* @hide
* see also android.view.textclassifier.TextClassificationConstants
*/
+ @Readable
public static final String TEXT_CLASSIFIER_CONSTANTS = "text_classifier_constants";
/**
@@ -12080,6 +12919,7 @@
* @hide
* see also com.android.internal.os.BatteryStatsImpl.Constants
*/
+ @Readable
public static final String BATTERY_STATS_CONSTANTS = "battery_stats_constants";
/**
@@ -12090,6 +12930,7 @@
* @hide
* @see com.android.server.content.SyncManagerConstants
*/
+ @Readable
public static final String SYNC_MANAGER_CONSTANTS = "sync_manager_constants";
/**
@@ -12109,6 +12950,7 @@
*
* @hide
*/
+ @Readable
public static final String BROADCAST_FG_CONSTANTS = "bcast_fg_constants";
/**
@@ -12119,6 +12961,7 @@
*
* @hide
*/
+ @Readable
public static final String BROADCAST_BG_CONSTANTS = "bcast_bg_constants";
/**
@@ -12129,6 +12972,7 @@
*
* @hide
*/
+ @Readable
public static final String BROADCAST_OFFLOAD_CONSTANTS = "bcast_offload_constants";
/**
@@ -12141,6 +12985,7 @@
* @see #ADAPTIVE_BATTERY_MANAGEMENT_ENABLED
*/
@SystemApi
+ @Readable
public static final String APP_STANDBY_ENABLED = "app_standby_enabled";
/**
@@ -12151,6 +12996,7 @@
* @hide
* @see #APP_STANDBY_ENABLED
*/
+ @Readable
public static final String ADAPTIVE_BATTERY_MANAGEMENT_ENABLED =
"adaptive_battery_management_enabled";
@@ -12162,6 +13008,7 @@
*
* @hide
*/
+ @Readable
public static final String ENABLE_RESTRICTED_BUCKET = "enable_restricted_bucket";
/**
@@ -12179,6 +13026,7 @@
*
* @hide
*/
+ @Readable
public static final String APP_AUTO_RESTRICTION_ENABLED =
"app_auto_restriction_enabled";
@@ -12188,6 +13036,7 @@
* Default: 1
* @hide
*/
+ @Readable
public static final String FORCED_APP_STANDBY_ENABLED = "forced_app_standby_enabled";
/**
@@ -12196,6 +13045,7 @@
* Default: 0
* @hide
*/
+ @Readable
public static final String FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED
= "forced_app_standby_for_small_battery_enabled";
@@ -12205,6 +13055,7 @@
* Default: 0
* @hide
*/
+ @Readable
public static final String USER_ABSENT_RADIOS_OFF_FOR_SMALL_BATTERY_ENABLED
= "user_absent_radios_off_for_small_battery_enabled";
@@ -12214,6 +13065,7 @@
* Default: 0
* @hide
*/
+ @Readable
public static final String USER_ABSENT_TOUCH_OFF_FOR_SMALL_BATTERY_ENABLED
= "user_absent_touch_off_for_small_battery_enabled";
@@ -12223,6 +13075,7 @@
* Default: 1
* @hide
*/
+ @Readable
public static final String WIFI_ON_WHEN_PROXY_DISCONNECTED
= "wifi_on_when_proxy_disconnected";
@@ -12241,6 +13094,7 @@
* Type: string
* @hide
*/
+ @Readable
public static final String TIME_ONLY_MODE_CONSTANTS
= "time_only_mode_constants";
@@ -12251,6 +13105,7 @@
* Default: 0
* @hide
*/
+ @Readable
public static final String UNGAZE_SLEEP_ENABLED = "ungaze_sleep_enabled";
/**
@@ -12259,6 +13114,7 @@
* Default: 0
* @hide
*/
+ @Readable
public static final String NETWORK_WATCHLIST_ENABLED = "network_watchlist_enabled";
/**
@@ -12267,6 +13123,7 @@
* Default: 1
* @hide
*/
+ @Readable
public static final String SHOW_HIDDEN_LAUNCHER_ICON_APPS_ENABLED =
"show_hidden_icon_apps_enabled";
@@ -12276,6 +13133,7 @@
* Default: 0
* @hide
*/
+ @Readable
public static final String SHOW_NEW_APP_INSTALLED_NOTIFICATION_ENABLED =
"show_new_app_installed_notification_enabled";
@@ -12289,6 +13147,7 @@
*
* @hide
*/
+ @Readable
public static final String KEEP_PROFILE_IN_BACKGROUND = "keep_profile_in_background";
/**
@@ -12310,6 +13169,7 @@
*
* @hide
*/
+ @Readable
public static final String ADB_ALLOWED_CONNECTION_TIME =
"adb_allowed_connection_time";
@@ -12317,12 +13177,14 @@
* Scaling factor for normal window animations. Setting to 0 will
* disable window animations.
*/
+ @Readable
public static final String WINDOW_ANIMATION_SCALE = "window_animation_scale";
/**
* Scaling factor for activity transition animations. Setting to 0 will
* disable window animations.
*/
+ @Readable
public static final String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
/**
@@ -12330,6 +13192,7 @@
* start delay and duration of all such animations. Setting to 0 will
* cause animations to end immediately. The default value is 1.
*/
+ @Readable
public static final String ANIMATOR_DURATION_SCALE = "animator_duration_scale";
/**
@@ -12338,6 +13201,7 @@
*
* @hide
*/
+ @Readable
public static final String FANCY_IME_ANIMATIONS = "fancy_ime_animations";
/**
@@ -12346,6 +13210,7 @@
* TODO: remove this settings before code freeze (bug/1907571)
* @hide
*/
+ @Readable
public static final String COMPATIBILITY_MODE = "compatibility_mode";
/**
@@ -12355,6 +13220,7 @@
* 2 = Vibrate
* @hide
*/
+ @Readable
public static final String EMERGENCY_TONE = "emergency_tone";
/**
@@ -12363,6 +13229,7 @@
* boolean (1 or 0).
* @hide
*/
+ @Readable
public static final String CALL_AUTO_RETRY = "call_auto_retry";
/**
@@ -12370,6 +13237,7 @@
* The value is a boolean (1 or 0).
* @hide
*/
+ @Readable
public static final String EMERGENCY_AFFORDANCE_NEEDED = "emergency_affordance_needed";
/**
@@ -12379,6 +13247,7 @@
*
* @hide
*/
+ @Readable
public static final String ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS =
"enable_automatic_system_server_heap_dumps";
@@ -12387,18 +13256,21 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @Readable
public static final String PREFERRED_NETWORK_MODE =
"preferred_network_mode";
/**
* Name of an application package to be debugged.
*/
+ @Readable
public static final String DEBUG_APP = "debug_app";
/**
* If 1, when launching DEBUG_APP it will wait for the debugger before
* starting user code. If 0, it will run normally.
*/
+ @Readable
public static final String WAIT_FOR_DEBUGGER = "wait_for_debugger";
/**
@@ -12407,12 +13279,14 @@
* 1 = yes
* @hide
*/
+ @Readable
public static final String ENABLE_GPU_DEBUG_LAYERS = "enable_gpu_debug_layers";
/**
* App allowed to load GPU debug layers
* @hide
*/
+ @Readable
public static final String GPU_DEBUG_APP = "gpu_debug_app";
/**
@@ -12420,6 +13294,7 @@
* to dumpable apps that opt-in.
* @hide
*/
+ @Readable
public static final String ANGLE_DEBUG_PACKAGE = "angle_debug_package";
/**
@@ -12427,12 +13302,14 @@
* The value is a boolean (1 or 0).
* @hide
*/
+ @Readable
public static final String ANGLE_GL_DRIVER_ALL_ANGLE = "angle_gl_driver_all_angle";
/**
* List of PKGs that have an OpenGL driver selected
* @hide
*/
+ @Readable
public static final String ANGLE_GL_DRIVER_SELECTION_PKGS =
"angle_gl_driver_selection_pkgs";
@@ -12440,6 +13317,7 @@
* List of selected OpenGL drivers, corresponding to the PKGs in GLOBAL_SETTINGS_DRIVER_PKGS
* @hide
*/
+ @Readable
public static final String ANGLE_GL_DRIVER_SELECTION_VALUES =
"angle_gl_driver_selection_values";
@@ -12447,6 +13325,7 @@
* List of package names that should check ANGLE rules
* @hide
*/
+ @Readable
public static final String ANGLE_ALLOWLIST = "angle_allowlist";
/**
@@ -12456,6 +13335,7 @@
* e.g. feature1:feature2:feature3,feature1:feature3:feature5
* @hide
*/
+ @Readable
public static final String ANGLE_EGL_FEATURES = "angle_egl_features";
/**
@@ -12463,6 +13343,7 @@
* The value is a boolean (1 or 0).
* @hide
*/
+ @Readable
public static final String SHOW_ANGLE_IN_USE_DIALOG_BOX = "show_angle_in_use_dialog_box";
/**
@@ -12473,6 +13354,7 @@
* 3 = All Apps use system graphics driver
* @hide
*/
+ @Readable
public static final String UPDATABLE_DRIVER_ALL_APPS = "updatable_driver_all_apps";
/**
@@ -12480,6 +13362,7 @@
* i.e. <pkg1>,<pkg2>,...,<pkgN>
* @hide
*/
+ @Readable
public static final String UPDATABLE_DRIVER_PRODUCTION_OPT_IN_APPS =
"updatable_driver_production_opt_in_apps";
@@ -12488,6 +13371,7 @@
* i.e. <pkg1>,<pkg2>,...,<pkgN>
* @hide
*/
+ @Readable
public static final String UPDATABLE_DRIVER_PRERELEASE_OPT_IN_APPS =
"updatable_driver_prerelease_opt_in_apps";
@@ -12496,6 +13380,7 @@
* i.e. <pkg1>,<pkg2>,...,<pkgN>
* @hide
*/
+ @Readable
public static final String UPDATABLE_DRIVER_PRODUCTION_OPT_OUT_APPS =
"updatable_driver_production_opt_out_apps";
@@ -12503,6 +13388,7 @@
* Apps on the denylist that are forbidden to use updatable production driver.
* @hide
*/
+ @Readable
public static final String UPDATABLE_DRIVER_PRODUCTION_DENYLIST =
"updatable_driver_production_denylist";
@@ -12511,6 +13397,7 @@
* updatable production driver.
* @hide
*/
+ @Readable
public static final String UPDATABLE_DRIVER_PRODUCTION_DENYLISTS =
"updatable_driver_production_denylists";
@@ -12520,6 +13407,7 @@
* i.e. <apk1>,<apk2>,...,<apkN>
* @hide
*/
+ @Readable
public static final String UPDATABLE_DRIVER_PRODUCTION_ALLOWLIST =
"updatable_driver_production_allowlist";
@@ -12529,6 +13417,7 @@
* i.e. <lib1>:<lib2>:...:<libN>
* @hide
*/
+ @Readable
public static final String UPDATABLE_DRIVER_SPHAL_LIBRARIES =
"updatable_driver_sphal_libraries";
@@ -12537,6 +13426,7 @@
* i.e. <layer1>:<layer2>:...:<layerN>
* @hide
*/
+ @Readable
public static final String GPU_DEBUG_LAYERS = "gpu_debug_layers";
/**
@@ -12544,12 +13434,14 @@
* i.e. <layer1>:<layer2>:...:<layerN>
* @hide
*/
+ @Readable
public static final String GPU_DEBUG_LAYERS_GLES = "gpu_debug_layers_gles";
/**
* Addition app for GPU layer discovery
* @hide
*/
+ @Readable
public static final String GPU_DEBUG_LAYER_APP = "gpu_debug_layer_app";
/**
@@ -12559,6 +13451,7 @@
* {@link android.os.Build.VERSION_CODES#N_MR1}.
*/
@Deprecated
+ @Readable
public static final String SHOW_PROCESSES = "show_processes";
/**
@@ -12566,6 +13459,7 @@
* @hide
*/
@TestApi
+ @Readable
public static final String LOW_POWER_MODE = "low_power";
/**
@@ -12574,6 +13468,7 @@
* @hide
*/
@TestApi
+ @Readable
public static final String LOW_POWER_MODE_STICKY = "low_power_sticky";
/**
@@ -12583,6 +13478,7 @@
*
* @hide
*/
+ @Readable
public static final String LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL =
"low_power_sticky_auto_disable_level";
@@ -12592,6 +13488,7 @@
*
* @hide
*/
+ @Readable
public static final String LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED =
"low_power_sticky_auto_disable_enabled";
@@ -12605,6 +13502,7 @@
* @see android.os.PowerManager#getPowerSaveModeTrigger()
* @hide
*/
+ @Readable
public static final String LOW_POWER_MODE_TRIGGER_LEVEL = "low_power_trigger_level";
/**
@@ -12615,6 +13513,7 @@
* @hide
*/
@TestApi
+ @Readable
public static final String AUTOMATIC_POWER_SAVE_MODE = "automatic_power_save_mode";
/**
@@ -12625,6 +13524,7 @@
* @hide
*/
@TestApi
+ @Readable
public static final String DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD =
"dynamic_power_savings_disable_threshold";
@@ -12635,6 +13535,7 @@
* @hide
*/
@TestApi
+ @Readable
public static final String DYNAMIC_POWER_SAVINGS_ENABLED = "dynamic_power_savings_enabled";
/**
@@ -12646,6 +13547,7 @@
* @hide
*/
@Deprecated
+ @Readable
public static final String TIME_REMAINING_ESTIMATE_MILLIS =
"time_remaining_estimate_millis";
@@ -12659,6 +13561,7 @@
* @hide
*/
@Deprecated
+ @Readable
public static final String TIME_REMAINING_ESTIMATE_BASED_ON_USAGE =
"time_remaining_estimate_based_on_usage";
@@ -12671,6 +13574,7 @@
* @hide
*/
@Deprecated
+ @Readable
public static final String AVERAGE_TIME_TO_DISCHARGE = "average_time_to_discharge";
/**
@@ -12682,6 +13586,7 @@
* @deprecated No longer needed due to {@link PowerManager#getBatteryDischargePrediction}.
*/
@Deprecated
+ @Readable
public static final String BATTERY_ESTIMATES_LAST_UPDATE_TIME =
"battery_estimates_last_update_time";
@@ -12691,12 +13596,14 @@
*
* @hide
*/
+ @Readable
public static final String LOW_POWER_MODE_TRIGGER_LEVEL_MAX = "low_power_trigger_level_max";
/**
* See com.android.settingslib.fuelgauge.BatterySaverUtils.
* @hide
*/
+ @Readable
public static final String LOW_POWER_MODE_SUGGESTION_PARAMS =
"low_power_mode_suggestion_params";
@@ -12705,6 +13612,7 @@
* processes as soon as they are no longer needed. If 0, the normal
* extended lifetime is used.
*/
+ @Readable
public static final String ALWAYS_FINISH_ACTIVITIES = "always_finish_activities";
/**
@@ -12714,6 +13622,7 @@
* @hide
*/
@TestApi
+ @Readable
public static final String HIDE_ERROR_DIALOGS = "hide_error_dialogs";
/**
@@ -12722,6 +13631,7 @@
* 1 = enabled
* @hide
*/
+ @Readable
public static final String DOCK_AUDIO_MEDIA_ENABLED = "dock_audio_media_enabled";
/**
@@ -12781,6 +13691,7 @@
* ENCODED_SURROUND_OUTPUT_MANUAL
* @hide
*/
+ @Readable
public static final String ENCODED_SURROUND_OUTPUT = "encoded_surround_output";
/**
@@ -12792,6 +13703,7 @@
*
* @hide
*/
+ @Readable
public static final String ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS =
"encoded_surround_output_enabled_formats";
@@ -12799,36 +13711,42 @@
* Persisted safe headphone volume management state by AudioService
* @hide
*/
+ @Readable
public static final String AUDIO_SAFE_VOLUME_STATE = "audio_safe_volume_state";
/**
* URL for tzinfo (time zone) updates
* @hide
*/
+ @Readable
public static final String TZINFO_UPDATE_CONTENT_URL = "tzinfo_content_url";
/**
* URL for tzinfo (time zone) update metadata
* @hide
*/
+ @Readable
public static final String TZINFO_UPDATE_METADATA_URL = "tzinfo_metadata_url";
/**
* URL for selinux (mandatory access control) updates
* @hide
*/
+ @Readable
public static final String SELINUX_UPDATE_CONTENT_URL = "selinux_content_url";
/**
* URL for selinux (mandatory access control) update metadata
* @hide
*/
+ @Readable
public static final String SELINUX_UPDATE_METADATA_URL = "selinux_metadata_url";
/**
* URL for sms short code updates
* @hide
*/
+ @Readable
public static final String SMS_SHORT_CODES_UPDATE_CONTENT_URL =
"sms_short_codes_content_url";
@@ -12836,6 +13754,7 @@
* URL for sms short code update metadata
* @hide
*/
+ @Readable
public static final String SMS_SHORT_CODES_UPDATE_METADATA_URL =
"sms_short_codes_metadata_url";
@@ -12843,30 +13762,35 @@
* URL for apn_db updates
* @hide
*/
+ @Readable
public static final String APN_DB_UPDATE_CONTENT_URL = "apn_db_content_url";
/**
* URL for apn_db update metadata
* @hide
*/
+ @Readable
public static final String APN_DB_UPDATE_METADATA_URL = "apn_db_metadata_url";
/**
* URL for cert pinlist updates
* @hide
*/
+ @Readable
public static final String CERT_PIN_UPDATE_CONTENT_URL = "cert_pin_content_url";
/**
* URL for cert pinlist updates
* @hide
*/
+ @Readable
public static final String CERT_PIN_UPDATE_METADATA_URL = "cert_pin_metadata_url";
/**
* URL for intent firewall updates
* @hide
*/
+ @Readable
public static final String INTENT_FIREWALL_UPDATE_CONTENT_URL =
"intent_firewall_content_url";
@@ -12874,6 +13798,7 @@
* URL for intent firewall update metadata
* @hide
*/
+ @Readable
public static final String INTENT_FIREWALL_UPDATE_METADATA_URL =
"intent_firewall_metadata_url";
@@ -12881,18 +13806,21 @@
* URL for lang id model updates
* @hide
*/
+ @Readable
public static final String LANG_ID_UPDATE_CONTENT_URL = "lang_id_content_url";
/**
* URL for lang id model update metadata
* @hide
*/
+ @Readable
public static final String LANG_ID_UPDATE_METADATA_URL = "lang_id_metadata_url";
/**
* URL for smart selection model updates
* @hide
*/
+ @Readable
public static final String SMART_SELECTION_UPDATE_CONTENT_URL =
"smart_selection_content_url";
@@ -12900,6 +13828,7 @@
* URL for smart selection model update metadata
* @hide
*/
+ @Readable
public static final String SMART_SELECTION_UPDATE_METADATA_URL =
"smart_selection_metadata_url";
@@ -12907,6 +13836,7 @@
* URL for conversation actions model updates
* @hide
*/
+ @Readable
public static final String CONVERSATION_ACTIONS_UPDATE_CONTENT_URL =
"conversation_actions_content_url";
@@ -12914,6 +13844,7 @@
* URL for conversation actions model update metadata
* @hide
*/
+ @Readable
public static final String CONVERSATION_ACTIONS_UPDATE_METADATA_URL =
"conversation_actions_metadata_url";
@@ -12921,12 +13852,14 @@
* SELinux enforcement status. If 0, permissive; if 1, enforcing.
* @hide
*/
+ @Readable
public static final String SELINUX_STATUS = "selinux_status";
/**
* Developer setting to force RTL layout.
* @hide
*/
+ @Readable
public static final String DEVELOPMENT_FORCE_RTL = "debug.force_rtl";
/**
@@ -12937,6 +13870,7 @@
*
* @hide
*/
+ @Readable
public static final String LOW_BATTERY_SOUND_TIMEOUT = "low_battery_sound_timeout";
/**
@@ -12946,6 +13880,7 @@
*
* @hide
*/
+ @Readable
public static final String WIFI_BOUNCE_DELAY_OVERRIDE_MS = "wifi_bounce_delay_override_ms";
/**
@@ -12955,6 +13890,7 @@
*
* @hide
*/
+ @Readable
public static final String POLICY_CONTROL = "policy_control";
/**
@@ -12962,6 +13898,7 @@
*
* @hide
*/
+ @Readable
public static final String EMULATE_DISPLAY_CUTOUT = "emulate_display_cutout";
/** @hide */ public static final int EMULATE_DISPLAY_CUTOUT_OFF = 0;
@@ -12972,6 +13909,7 @@
*
* @hide
*/
+ @Readable
public static final String BLOCKED_SLICES = "blocked_slices";
/**
@@ -12981,6 +13919,7 @@
* @hide
*/
@UnsupportedAppUsage
+ @Readable
public static final String ZEN_MODE = "zen_mode";
/** @hide */
@@ -13020,6 +13959,7 @@
*
* @hide
*/
+ @Readable
public static final String ZEN_MODE_RINGER_LEVEL = "zen_mode_ringer_level";
/**
@@ -13028,6 +13968,7 @@
* @hide
*/
@UnsupportedAppUsage
+ @Readable
public static final String ZEN_MODE_CONFIG_ETAG = "zen_mode_config_etag";
/**
@@ -13057,6 +13998,7 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @Readable
public static final String HEADS_UP_NOTIFICATIONS_ENABLED =
"heads_up_notifications_enabled";
@@ -13070,6 +14012,7 @@
/**
* The name of the device
*/
+ @Readable
public static final String DEVICE_NAME = "device_name";
/**
@@ -13078,6 +14021,7 @@
* Type: int (0 for false, 1 for true)
* @hide
*/
+ @Readable
public static final String NETWORK_SCORING_PROVISIONED = "network_scoring_provisioned";
/**
@@ -13089,6 +14033,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String REQUIRE_PASSWORD_TO_DECRYPT = "require_password_to_decrypt";
/**
@@ -13102,6 +14047,7 @@
* {@link android.provider.Telephony.SimInfo#COLUMN_ENHANCED_4G_MODE_ENABLED} instead.
*/
@Deprecated
+ @Readable
public static final String ENHANCED_4G_MODE_ENABLED =
Telephony.SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED;
@@ -13114,6 +14060,7 @@
* @deprecated Use {@link android.provider.Telephony.SimInfo#COLUMN_VT_IMS_ENABLED} instead.
*/
@Deprecated
+ @Readable
public static final String VT_IMS_ENABLED = Telephony.SimInfo.COLUMN_VT_IMS_ENABLED;
/**
@@ -13126,6 +14073,7 @@
* {@link android.provider.Telephony.SimInfo#COLUMN_WFC_IMS_ENABLED} instead.
*/
@Deprecated
+ @Readable
public static final String WFC_IMS_ENABLED = Telephony.SimInfo.COLUMN_WFC_IMS_ENABLED;
/**
@@ -13137,6 +14085,7 @@
* @deprecated Use {@link android.provider.Telephony.SimInfo#COLUMN_WFC_IMS_MODE} instead.
*/
@Deprecated
+ @Readable
public static final String WFC_IMS_MODE = Telephony.SimInfo.COLUMN_WFC_IMS_MODE;
/**
@@ -13149,6 +14098,7 @@
* instead.
*/
@Deprecated
+ @Readable
public static final String WFC_IMS_ROAMING_MODE =
Telephony.SimInfo.COLUMN_WFC_IMS_ROAMING_MODE;
@@ -13162,6 +14112,7 @@
* instead
*/
@Deprecated
+ @Readable
public static final String WFC_IMS_ROAMING_ENABLED =
Telephony.SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED;
@@ -13172,6 +14123,7 @@
* Type: int (0 for false, 1 for true)
* @hide
*/
+ @Readable
public static final String LTE_SERVICE_FORCED = "lte_service_forced";
@@ -13181,6 +14133,7 @@
* See WindowManagerPolicy.WindowManagerFuncs
* @hide
*/
+ @Readable
public static final String LID_BEHAVIOR = "lid_behavior";
/**
@@ -13189,6 +14142,7 @@
* Type: int
* @hide
*/
+ @Readable
public static final String EPHEMERAL_COOKIE_MAX_SIZE_BYTES =
"ephemeral_cookie_max_size_bytes";
@@ -13200,6 +14154,7 @@
*
* @hide
*/
+ @Readable
public static final String ENABLE_EPHEMERAL_FEATURE = "enable_ephemeral_feature";
/**
@@ -13210,6 +14165,7 @@
*
* @hide
*/
+ @Readable
public static final String INSTANT_APP_DEXOPT_ENABLED = "instant_app_dexopt_enabled";
/**
@@ -13218,6 +14174,7 @@
* Type: long
* @hide
*/
+ @Readable
public static final String INSTALLED_INSTANT_APP_MIN_CACHE_PERIOD =
"installed_instant_app_min_cache_period";
@@ -13227,6 +14184,7 @@
* Type: long
* @hide
*/
+ @Readable
public static final String INSTALLED_INSTANT_APP_MAX_CACHE_PERIOD =
"installed_instant_app_max_cache_period";
@@ -13236,6 +14194,7 @@
* Type: long
* @hide
*/
+ @Readable
public static final String UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD =
"uninstalled_instant_app_min_cache_period";
@@ -13245,6 +14204,7 @@
* Type: long
* @hide
*/
+ @Readable
public static final String UNINSTALLED_INSTANT_APP_MAX_CACHE_PERIOD =
"uninstalled_instant_app_max_cache_period";
@@ -13254,6 +14214,7 @@
* Type: long
* @hide
*/
+ @Readable
public static final String UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD =
"unused_static_shared_lib_min_cache_period";
@@ -13263,6 +14224,7 @@
* Type: int
* @hide
*/
+ @Readable
public static final String ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED =
"allow_user_switching_when_system_user_locked";
@@ -13271,6 +14233,7 @@
* <p>
* Type: int
*/
+ @Readable
public static final String BOOT_COUNT = "boot_count";
/**
@@ -13281,6 +14244,7 @@
* before the user restrictions are loaded.
* @hide
*/
+ @Readable
public static final String SAFE_BOOT_DISALLOWED = "safe_boot_disallowed";
/**
@@ -13292,6 +14256,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String DEVICE_DEMO_MODE = "device_demo_mode";
/**
@@ -13301,6 +14266,7 @@
*
* @hide
*/
+ @Readable
public static final String NETWORK_ACCESS_TIMEOUT_MS = "network_access_timeout_ms";
/**
@@ -13311,6 +14277,7 @@
*
* @hide
*/
+ @Readable
public static final String DATABASE_DOWNGRADE_REASON = "database_downgrade_reason";
/**
@@ -13321,6 +14288,7 @@
*
* @hide
*/
+ @Readable
public static final String DATABASE_CREATION_BUILDID = "database_creation_buildid";
/**
@@ -13329,6 +14297,7 @@
*
* @hide
*/
+ @Readable
public static final String CONTACTS_DATABASE_WAL_ENABLED = "contacts_database_wal_enabled";
/**
@@ -13336,6 +14305,7 @@
*
* @hide
*/
+ @Readable
public static final String LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED =
"location_settings_link_to_permissions_enabled";
@@ -13346,6 +14316,7 @@
*
* @hide
*/
+ @Readable
public static final String EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS =
"euicc_removing_invisible_profiles_timeout_millis";
@@ -13355,6 +14326,7 @@
*
* @hide
*/
+ @Readable
public static final String EUICC_FACTORY_RESET_TIMEOUT_MILLIS =
"euicc_factory_reset_timeout_millis";
@@ -13364,6 +14336,7 @@
*
* @hide
*/
+ @Readable
public static final String STORAGE_SETTINGS_CLOBBER_THRESHOLD =
"storage_settings_clobber_threshold";
@@ -13373,6 +14346,7 @@
*
* @hide
*/
+ @Readable
public static final String OVERRIDE_SETTINGS_PROVIDER_RESTORE_ANY_VERSION =
"override_settings_provider_restore_any_version";
/**
@@ -13383,6 +14357,7 @@
*
* @hide
*/
+ @Readable
public static final String CHAINED_BATTERY_ATTRIBUTION_ENABLED =
"chained_battery_attribution_enabled";
@@ -13395,6 +14370,7 @@
*
* @hide
*/
+ @Readable
public static final String ENABLE_ADB_INCREMENTAL_INSTALL_DEFAULT =
"enable_adb_incremental_install_default";
@@ -13412,6 +14388,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES =
"autofill_compat_mode_allowed_packages";
@@ -13425,6 +14402,7 @@
*
* @hide
*/
+ @Readable
public static final String AUTOFILL_LOGGING_LEVEL = "autofill_logging_level";
/**
@@ -13432,6 +14410,7 @@
*
* @hide
*/
+ @Readable
public static final String AUTOFILL_MAX_PARTITIONS_SIZE = "autofill_max_partitions_size";
/**
@@ -13440,6 +14419,7 @@
*
* @hide
*/
+ @Readable
public static final String AUTOFILL_MAX_VISIBLE_DATASETS = "autofill_max_visible_datasets";
/**
@@ -13448,6 +14428,7 @@
* @hide
*/
@TestApi
+ @Readable
public static final String HIDDEN_API_BLACKLIST_EXEMPTIONS =
"hidden_api_blacklist_exemptions";
@@ -13460,14 +14441,16 @@
* @hide
*/
@TestApi
+ @Readable
public static final String HIDDEN_API_POLICY = "hidden_api_policy";
- /**
+ /**
* Flag for forcing {@link com.android.server.compat.OverrideValidatorImpl}
* to consider this a non-debuggable build.
*
* @hide
*/
+ @Readable
public static final String FORCE_NON_DEBUGGABLE_FINAL_BUILD_FOR_COMPAT =
"force_non_debuggable_final_build_for_compat";
@@ -13477,6 +14460,7 @@
*
* @hide
*/
+ @Readable
public static final String SIGNED_CONFIG_VERSION = "signed_config_version";
/**
@@ -13485,6 +14469,7 @@
*
* @hide
*/
+ @Readable
public static final String SOUND_TRIGGER_DETECTION_SERVICE_OP_TIMEOUT =
"sound_trigger_detection_service_op_timeout";
@@ -13494,6 +14479,7 @@
*
* @hide
*/
+ @Readable
public static final String MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY =
"max_sound_trigger_detection_service_ops_per_day";
@@ -13501,6 +14487,7 @@
* Indicates whether aware is available in the current location.
* @hide
*/
+ @Readable
public static final String AWARE_ALLOWED = "aware_allowed";
/**
@@ -13509,6 +14496,7 @@
* Used by PhoneWindowManager.
* @hide
*/
+ @Readable
public static final String POWER_BUTTON_LONG_PRESS =
"power_button_long_press";
@@ -13518,6 +14506,7 @@
* Used by PhoneWindowManager.
* @hide
*/
+ @Readable
public static final String POWER_BUTTON_VERY_LONG_PRESS =
"power_button_very_long_press";
@@ -13543,7 +14532,8 @@
CONTENT_URI,
CALL_METHOD_GET_GLOBAL,
CALL_METHOD_PUT_GLOBAL,
- sProviderHolder);
+ sProviderHolder,
+ Global.class);
// Certain settings have been moved from global to the per-user secure namespace
@UnsupportedAppUsage
@@ -13572,6 +14562,11 @@
sNameValueCache.clearGenerationTrackerForTest();
}
+ /** @hide */
+ public static void getPublicSettings(Set<String> allKeys, Set<String> readableKeys) {
+ getPublicSettingsForClass(Global.class, allKeys, readableKeys);
+ }
+
/**
* Look up a name in the database.
* @param resolver to access the database with
@@ -13981,6 +14976,7 @@
* Subscription Id to be used for voice call on a multi sim device.
* @hide
*/
+ @Readable
public static final String MULTI_SIM_VOICE_CALL_SUBSCRIPTION = "multi_sim_voice_call";
/**
@@ -13989,18 +14985,21 @@
* @hide
*/
@UnsupportedAppUsage
+ @Readable
public static final String MULTI_SIM_VOICE_PROMPT = "multi_sim_voice_prompt";
/**
* Subscription Id to be used for data call on a multi sim device.
* @hide
*/
+ @Readable
public static final String MULTI_SIM_DATA_CALL_SUBSCRIPTION = "multi_sim_data_call";
/**
* Subscription Id to be used for SMS on a multi sim device.
* @hide
*/
+ @Readable
public static final String MULTI_SIM_SMS_SUBSCRIPTION = "multi_sim_sms";
/**
@@ -14008,6 +15007,7 @@
* The value 1 - enable, 0 - disable
* @hide
*/
+ @Readable
public static final String MULTI_SIM_SMS_PROMPT = "multi_sim_sms_prompt";
/** User preferred subscriptions setting.
@@ -14017,6 +15017,7 @@
* @hide
*/
@UnsupportedAppUsage
+ @Readable
public static final String[] MULTI_SIM_USER_PREFERRED_SUBS = {"user_preferred_sub1",
"user_preferred_sub2","user_preferred_sub3"};
@@ -14024,6 +15025,7 @@
* Which subscription is enabled for a physical slot.
* @hide
*/
+ @Readable
public static final String ENABLED_SUBSCRIPTION_FOR_SLOT = "enabled_subscription_for_slot";
/**
@@ -14031,6 +15033,7 @@
* The value 1 - enable, 0 - disable
* @hide
*/
+ @Readable
public static final String MODEM_STACK_ENABLED_FOR_SLOT = "modem_stack_enabled_for_slot";
/**
@@ -14038,6 +15041,7 @@
* The value 1 - enable, 0 - disable
* @hide
*/
+ @Readable
public static final String NEW_CONTACT_AGGREGATOR = "new_contact_aggregator";
/**
@@ -14047,12 +15051,14 @@
* @removed
*/
@Deprecated
+ @Readable
public static final String CONTACT_METADATA_SYNC = "contact_metadata_sync";
/**
* Whether to enable contacts metadata syncing or not
* The value 1 - enable, 0 - disable
*/
+ @Readable
public static final String CONTACT_METADATA_SYNC_ENABLED = "contact_metadata_sync_enabled";
/**
@@ -14060,6 +15066,7 @@
* The value 1 - enable, 0 - disable
* @hide
*/
+ @Readable
public static final String ENABLE_CELLULAR_ON_BOOT = "enable_cellular_on_boot";
/**
@@ -14068,6 +15075,7 @@
* Should be a float, and includes updates only.
* @hide
*/
+ @Readable
public static final String MAX_NOTIFICATION_ENQUEUE_RATE = "max_notification_enqueue_rate";
/**
@@ -14076,6 +15084,7 @@
* The value 1 - enable, 0 - disable
* @hide
*/
+ @Readable
public static final String SHOW_NOTIFICATION_CHANNEL_WARNINGS =
"show_notification_channel_warnings";
@@ -14083,6 +15092,7 @@
* Whether cell is enabled/disabled
* @hide
*/
+ @Readable
public static final String CELL_ON = "cell_on";
/**
@@ -14111,30 +15121,35 @@
* Whether to show the high temperature warning notification.
* @hide
*/
+ @Readable
public static final String SHOW_TEMPERATURE_WARNING = "show_temperature_warning";
/**
* Whether to show the usb high temperature alarm notification.
* @hide
*/
+ @Readable
public static final String SHOW_USB_TEMPERATURE_ALARM = "show_usb_temperature_alarm";
/**
* Temperature at which the high temperature warning notification should be shown.
* @hide
*/
+ @Readable
public static final String WARNING_TEMPERATURE = "warning_temperature";
/**
* Whether the diskstats logging task is enabled/disabled.
* @hide
*/
+ @Readable
public static final String ENABLE_DISKSTATS_LOGGING = "enable_diskstats_logging";
/**
* Whether the cache quota calculation task is enabled/disabled.
* @hide
*/
+ @Readable
public static final String ENABLE_CACHE_QUOTA_CALCULATION =
"enable_cache_quota_calculation";
@@ -14142,6 +15157,7 @@
* Whether the Deletion Helper no threshold toggle is available.
* @hide
*/
+ @Readable
public static final String ENABLE_DELETION_HELPER_NO_THRESHOLD_TOGGLE =
"enable_deletion_helper_no_threshold_toggle";
@@ -14162,6 +15178,7 @@
* Options will be used in order up to the maximum allowed by the UI.
* @hide
*/
+ @Readable
public static final String NOTIFICATION_SNOOZE_OPTIONS =
"notification_snooze_options";
@@ -14173,6 +15190,7 @@
* The value 1 - enable, 0 - disable
* @hide
*/
+ @Readable
public static final String NOTIFICATION_FEEDBACK_ENABLED = "notification_feedback_enabled";
/**
@@ -14184,6 +15202,7 @@
*
* @hide
*/
+ @Readable
public static final String BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT =
"blocking_helper_dismiss_to_view_ratio";
@@ -14195,6 +15214,7 @@
*
* @hide
*/
+ @Readable
public static final String BLOCKING_HELPER_STREAK_LIMIT = "blocking_helper_streak_limit";
/**
@@ -14222,6 +15242,7 @@
*
* @hide
*/
+ @Readable
public static final String SQLITE_COMPATIBILITY_WAL_FLAGS =
"sqlite_compatibility_wal_flags";
@@ -14231,6 +15252,7 @@
* 1 = yes
* @hide
*/
+ @Readable
public static final String ENABLE_GNSS_RAW_MEAS_FULL_TRACKING =
"enable_gnss_raw_meas_full_tracking";
@@ -14242,6 +15264,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT =
"install_carrier_app_notification_persistent";
@@ -14253,6 +15276,7 @@
* @hide
*/
@SystemApi
+ @Readable
public static final String INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS =
"install_carrier_app_notification_sleep_millis";
@@ -14262,6 +15286,7 @@
* everything else is unspecified.
* @hide
*/
+ @Readable
public static final String ZRAM_ENABLED =
"zram_enabled";
@@ -14271,6 +15296,7 @@
* "device_default" will let the system decide whether to enable the freezer or not
* @hide
*/
+ @Readable
public static final String CACHED_APPS_FREEZER_ENABLED = "cached_apps_freezer";
/**
@@ -14293,6 +15319,7 @@
* @see com.android.systemui.statusbar.policy.SmartReplyConstants
* @hide
*/
+ @Readable
public static final String SMART_REPLIES_IN_NOTIFICATIONS_FLAGS =
"smart_replies_in_notifications_flags";
@@ -14309,6 +15336,7 @@
* </pre>
* @hide
*/
+ @Readable
public static final String SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS =
"smart_suggestions_in_notifications_flags";
@@ -14318,6 +15346,7 @@
* @hide
*/
@TestApi
+ @Readable
@SuppressLint("NoSettingsProvider")
public static final String SHOW_FIRST_CRASH_DIALOG = "show_first_crash_dialog";
@@ -14325,6 +15354,7 @@
* If nonzero, crash dialogs will show an option to restart the app.
* @hide
*/
+ @Readable
public static final String SHOW_RESTART_IN_CRASH_DIALOG = "show_restart_in_crash_dialog";
/**
@@ -14332,6 +15362,7 @@
* this app.
* @hide
*/
+ @Readable
public static final String SHOW_MUTE_IN_CRASH_DIALOG = "show_mute_in_crash_dialog";
@@ -14387,6 +15418,7 @@
*
* @hide
*/
+ @Readable
public static final String BACKUP_AGENT_TIMEOUT_PARAMETERS =
"backup_agent_timeout_parameters";
@@ -14401,6 +15433,7 @@
*
* @hide
*/
+ @Readable
public static final String GNSS_SATELLITE_BLOCKLIST = "gnss_satellite_blocklist";
/**
@@ -14412,6 +15445,7 @@
*
* @hide
*/
+ @Readable
public static final String GNSS_HAL_LOCATION_REQUEST_DURATION_MILLIS =
"gnss_hal_location_request_duration_millis";
@@ -14428,6 +15462,7 @@
*
* @hide
*/
+ @Readable
public static final String BINDER_CALLS_STATS = "binder_calls_stats";
/**
@@ -14441,6 +15476,7 @@
*
* @hide
*/
+ @Readable
public static final String LOOPER_STATS = "looper_stats";
/**
@@ -14455,6 +15491,7 @@
*
* @hide
*/
+ @Readable
public static final String KERNEL_CPU_THREAD_READER = "kernel_cpu_thread_reader";
/**
@@ -14462,6 +15499,7 @@
* reboot. The value "1" enables native flags health check; otherwise it's disabled.
* @hide
*/
+ @Readable
public static final String NATIVE_FLAGS_HEALTH_CHECK_ENABLED =
"native_flags_health_check_enabled";
@@ -14471,6 +15509,7 @@
*
* @hide
*/
+ @Readable
public static final String APPOP_HISTORY_MODE = "mode";
/**
@@ -14480,6 +15519,7 @@
*
* @hide
*/
+ @Readable
public static final String APPOP_HISTORY_BASE_INTERVAL_MILLIS = "baseIntervalMillis";
/**
@@ -14488,6 +15528,7 @@
*
* @hide
*/
+ @Readable
public static final String APPOP_HISTORY_INTERVAL_MULTIPLIER = "intervalMultiplier";
/**
@@ -14509,6 +15550,7 @@
*
* @hide
*/
+ @Readable
public static final String APPOP_HISTORY_PARAMETERS =
"appop_history_parameters";
@@ -14526,6 +15568,7 @@
*
* @hide
*/
+ @Readable
public static final String AUTO_REVOKE_PARAMETERS =
"auto_revoke_parameters";
@@ -14537,6 +15580,7 @@
* @see com.android.internal.os.BatteryStatsImpl.Constants.KEY_BATTERY_CHARGED_DELAY_MS
* @hide
*/
+ @Readable
public static final String BATTERY_CHARGING_STATE_UPDATE_DELAY =
"battery_charging_state_update_delay";
@@ -14545,6 +15589,7 @@
*
* @hide
*/
+ @Readable
public static final String TEXT_CLASSIFIER_ACTION_MODEL_PARAMS =
"text_classifier_action_model_params";
@@ -14558,6 +15603,7 @@
*
* @hide
*/
+ @Readable
public static final String POWER_BUTTON_SUPPRESSION_DELAY_AFTER_GESTURE_WAKE =
"power_button_suppression_delay_after_gesture_wake";
@@ -14566,6 +15612,7 @@
*
* @hide
*/
+ @Readable
public static final String ADVANCED_BATTERY_USAGE_AMOUNT = "advanced_battery_usage_amount";
/**
@@ -14580,6 +15627,7 @@
* 2: always on - All 5G NSA tracking indications are on whether the screen is on or off.
* @hide
*/
+ @Readable
public static final String NR_NSA_TRACKING_SCREEN_OFF_MODE =
"nr_nsa_tracking_screen_off_mode";
@@ -14590,6 +15638,7 @@
* 1: Enabled
* @hide
*/
+ @Readable
public static final String SHOW_PEOPLE_SPACE = "show_people_space";
/**
@@ -14600,6 +15649,7 @@
* 2: All conversations
* @hide
*/
+ @Readable
public static final String PEOPLE_SPACE_CONVERSATION_TYPE =
"people_space_conversation_type";
@@ -14610,6 +15660,7 @@
* 1: Enabled
* @hide
*/
+ @Readable
public static final String SHOW_NEW_LOCKSCREEN = "show_new_lockscreen";
/**
@@ -14619,6 +15670,7 @@
* 1: Enabled
* @hide
*/
+ @Readable
public static final String SHOW_NEW_NOTIF_DISMISS = "show_new_notif_dismiss";
/**
@@ -14633,6 +15685,7 @@
* 1: Enabled (All apps will receive the new rules)
* @hide
*/
+ @Readable
public static final String BACKPORT_S_NOTIF_RULES = "backport_s_notif_rules";
/**
@@ -14676,6 +15729,7 @@
*
* @hide
*/
+ @Readable
public static final String BLOCK_UNTRUSTED_TOUCHES_MODE = "block_untrusted_touches";
/**
@@ -14702,6 +15756,7 @@
*
* @hide
*/
+ @Readable
public static final String MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH =
"maximum_obscuring_opacity_for_touch";
@@ -14714,6 +15769,7 @@
* 1: enabled
* @hide
*/
+ @Readable
public static final String RESTRICTED_NETWORKING_MODE = "restricted_networking_mode";
}
@@ -14735,7 +15791,8 @@
CALL_METHOD_PUT_CONFIG,
CALL_METHOD_LIST_CONFIG,
CALL_METHOD_SET_ALL_CONFIG,
- sProviderHolder);
+ sProviderHolder,
+ Config.class);
/**
* Look up a name in the database.
diff --git a/core/java/android/se/OWNERS b/core/java/android/se/OWNERS
index f1539dc..5682fd3 100644
--- a/core/java/android/se/OWNERS
+++ b/core/java/android/se/OWNERS
@@ -1,4 +1,5 @@
# Bug component: 456592
-cbrubaker@google.com
-vishwath@google.com
+zachoverflow@google.com
+alisher@google.com
+jackcwyu@google.com
diff --git a/core/java/android/se/omapi/OWNERS b/core/java/android/se/omapi/OWNERS
index f1539dc..5682fd3 100644
--- a/core/java/android/se/omapi/OWNERS
+++ b/core/java/android/se/omapi/OWNERS
@@ -1,4 +1,5 @@
# Bug component: 456592
-cbrubaker@google.com
-vishwath@google.com
+zachoverflow@google.com
+alisher@google.com
+jackcwyu@google.com
diff --git a/core/java/android/se/omapi/SEService.java b/core/java/android/se/omapi/SEService.java
index a5c5c61..333af91 100644
--- a/core/java/android/se/omapi/SEService.java
+++ b/core/java/android/se/omapi/SEService.java
@@ -22,7 +22,10 @@
package android.se.omapi;
+import android.annotation.BroadcastBehavior;
import android.annotation.NonNull;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -71,6 +74,28 @@
}
/**
+ * Broadcast Action: Intent to notify if the secure element state is changed.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(registeredOnly = true, protectedBroadcast = true)
+ public static final String ACTION_SECURE_ELEMENT_STATE_CHANGED =
+ "android.se.omapi.action.SECURE_ELEMENT_STATE_CHANGED";
+
+ /**
+ * Mandatory extra containing the reader name of the state changed secure element.
+ *
+ * @see Reader#getName()
+ */
+ public static final String EXTRA_READER_NAME = "android.se.omapi.extra.READER_NAME";
+
+ /**
+ * Mandatory extra containing the connected state of the state changed secure element.
+ *
+ * True if the secure element is connected correctly, false otherwise.
+ */
+ public static final String EXTRA_READER_STATE = "android.se.omapi.extra.READER_STATE";
+
+ /**
* Listener object that allows the notification of the caller if this
* SEService could be bound to the backend.
*/
diff --git a/core/java/android/service/attestation/IImpressionAttestationService.aidl b/core/java/android/service/attestation/IImpressionAttestationService.aidl
index fcbc51f..5ff8f17 100644
--- a/core/java/android/service/attestation/IImpressionAttestationService.aidl
+++ b/core/java/android/service/attestation/IImpressionAttestationService.aidl
@@ -39,7 +39,7 @@
* {@link #SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS}.
* @param Callback The callback invoked to send back the impression token.
*/
- void generateImpressionToken(in String salt, in HardwareBuffer screenshot, in Rect bounds,
+ void generateImpressionToken(in byte[] salt, in HardwareBuffer screenshot, in Rect bounds,
in String hashAlgorithm, in RemoteCallback callback);
/**
@@ -51,6 +51,6 @@
* @param impressionToken The token to verify that it was generated by the system.
* @param callback The callback invoked to send back the verification status.
*/
- void verifyImpressionToken(in String salt, in ImpressionToken impressionToken,
+ void verifyImpressionToken(in byte[] salt, in ImpressionToken impressionToken,
in RemoteCallback callback);
}
diff --git a/core/java/android/service/attestation/ImpressionAttestationService.java b/core/java/android/service/attestation/ImpressionAttestationService.java
index 05ad5f0..968d533 100644
--- a/core/java/android/service/attestation/ImpressionAttestationService.java
+++ b/core/java/android/service/attestation/ImpressionAttestationService.java
@@ -100,7 +100,7 @@
* Returns null when the arguments sent are invalid.
*/
@Nullable
- public abstract ImpressionToken onGenerateImpressionToken(@NonNull String salt,
+ public abstract ImpressionToken onGenerateImpressionToken(@NonNull byte[] salt,
@NonNull HardwareBuffer screenshot, @NonNull Rect bounds,
@NonNull String hashAlgorithm);
@@ -109,16 +109,16 @@
*
* @param salt The salt value to use when verifying the hmac. This should be the
* same value that was passed to
- * {@link #onGenerateImpressionToken(String,
+ * {@link #onGenerateImpressionToken(byte[],
* HardwareBuffer, Rect, String)} to
* generate the token.
* @param impressionToken The token to verify that it was generated by the system.
* @return true if the token can be verified that it was generated by the system.
*/
- public abstract boolean onVerifyImpressionToken(@NonNull String salt,
+ public abstract boolean onVerifyImpressionToken(@NonNull byte[] salt,
@NonNull ImpressionToken impressionToken);
- private void generateImpressionToken(String salt, HardwareBuffer screenshot, Rect bounds,
+ private void generateImpressionToken(byte[] salt, HardwareBuffer screenshot, Rect bounds,
String hashAlgorithm, RemoteCallback callback) {
ImpressionToken impressionToken = onGenerateImpressionToken(salt, screenshot, bounds,
hashAlgorithm);
@@ -127,7 +127,7 @@
callback.sendResult(data);
}
- private void verifyImpressionToken(String salt, ImpressionToken impressionToken,
+ private void verifyImpressionToken(byte[] salt, ImpressionToken impressionToken,
RemoteCallback callback) {
boolean verificationStatus = onVerifyImpressionToken(salt, impressionToken);
final Bundle data = new Bundle();
@@ -138,7 +138,7 @@
private final class ImpressionAttestationServiceWrapper extends
IImpressionAttestationService.Stub {
@Override
- public void generateImpressionToken(String salt, HardwareBuffer screenshot, Rect bounds,
+ public void generateImpressionToken(byte[] salt, HardwareBuffer screenshot, Rect bounds,
String hashAlgorithm, RemoteCallback callback) {
mHandler.sendMessage(
obtainMessage(ImpressionAttestationService::generateImpressionToken,
@@ -147,7 +147,7 @@
}
@Override
- public void verifyImpressionToken(String salt, ImpressionToken impressionToken,
+ public void verifyImpressionToken(byte[] salt, ImpressionToken impressionToken,
RemoteCallback callback) {
mHandler.sendMessage(obtainMessage(ImpressionAttestationService::verifyImpressionToken,
ImpressionAttestationService.this, salt, impressionToken, callback));
diff --git a/core/java/android/service/resumeonreboot/IResumeOnRebootService.aidl b/core/java/android/service/resumeonreboot/IResumeOnRebootService.aidl
new file mode 100644
index 0000000..d9b403c
--- /dev/null
+++ b/core/java/android/service/resumeonreboot/IResumeOnRebootService.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.resumeonreboot;
+
+import android.os.RemoteCallback;
+
+/** @hide */
+interface IResumeOnRebootService {
+ oneway void wrapSecret(in byte[] unwrappedBlob, in long lifeTimeInMillis, in RemoteCallback resultCallback);
+ oneway void unwrap(in byte[] wrappedBlob, in RemoteCallback resultCallback);
+}
\ No newline at end of file
diff --git a/core/java/android/service/resumeonreboot/ResumeOnRebootService.java b/core/java/android/service/resumeonreboot/ResumeOnRebootService.java
new file mode 100644
index 0000000..4ebaa96
--- /dev/null
+++ b/core/java/android/service/resumeonreboot/ResumeOnRebootService.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.resumeonreboot;
+
+import android.annotation.DurationMillisLong;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.ParcelableException;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+
+import com.android.internal.os.BackgroundThread;
+
+import java.io.IOException;
+
+/**
+ * Base class for service that provides wrapping/unwrapping of the opaque blob needed for
+ * ResumeOnReboot operation. The package needs to provide a wrap/unwrap implementation for handling
+ * the opaque blob, that's secure even when on device keystore and clock is compromised. This can
+ * be achieved by using tamper-resistant hardware such as a secure element with a secure clock, or
+ * using a remote server to store and retrieve data and manage timing.
+ *
+ * <p>To extend this class, you must declare the service in your manifest file with the
+ * {@link android.Manifest.permission#BIND_RESUME_ON_REBOOT_SERVICE} permission,
+ * include an intent filter with the {@link #SERVICE_INTERFACE} action and mark the service as
+ * direct-boot aware. In addition, the package that contains the service must be granted
+ * {@link android.Manifest.permission#BIND_RESUME_ON_REBOOT_SERVICE}.
+ * For example:</p>
+ * <pre>
+ * <service android:name=".FooResumeOnRebootService"
+ * android:exported="true"
+ * android:priority="100"
+ * android:directBootAware="true"
+ * android:permission="android.permission.BIND_RESUME_ON_REBOOT_SERVICE">
+ * <intent-filter>
+ * <action android:name="android.service.resumeonreboot.ResumeOnRebootService" />
+ * </intent-filter>
+ * </service>
+ * </pre>
+ *
+ * //TODO: Replace this with public link when available.
+ *
+ * @hide
+ * @see
+ * <a href="https://goto.google.com/server-based-ror">https://goto.google.com/server-based-ror</a>
+ */
+@SystemApi
+public abstract class ResumeOnRebootService extends Service {
+
+ /**
+ * The intent that the service must respond to. Add it to the intent filter of the service.
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+ public static final String SERVICE_INTERFACE =
+ "android.service.resumeonreboot.ResumeOnRebootService";
+ /** @hide */
+ public static final String UNWRAPPED_BLOB_KEY = "unrwapped_blob_key";
+ /** @hide */
+ public static final String WRAPPED_BLOB_KEY = "wrapped_blob_key";
+ /** @hide */
+ public static final String EXCEPTION_KEY = "exception_key";
+
+ private final Handler mHandler = BackgroundThread.getHandler();
+
+ /**
+ * Implementation for wrapping the opaque blob used for resume-on-reboot prior to
+ * reboot. The service should not assume any structure of the blob to be wrapped. The
+ * implementation should wrap the opaque blob in a reasonable time or throw {@link IOException}
+ * if it's unable to complete the action.
+ *
+ * @param blob The opaque blob with size on the order of 100 bytes.
+ * @param lifeTimeInMillis The life time of the blob. This must be strictly enforced by the
+ * implementation and any attempt to unWrap the wrapped blob returned by
+ * this function after expiration should
+ * fail.
+ * @return Wrapped blob to be persisted across reboot with size on the order of 100 bytes.
+ * @throws IOException if the implementation is unable to wrap the blob successfully.
+ */
+ @NonNull
+ public abstract byte[] onWrap(@NonNull byte[] blob, @DurationMillisLong long lifeTimeInMillis)
+ throws IOException;
+
+ /**
+ * Implementation for unwrapping the wrapped blob used for resume-on-reboot after reboot. This
+ * operation would happen after reboot during direct boot mode (i.e before device is unlocked
+ * for the first time). The implementation should unwrap the wrapped blob in a reasonable time
+ * and returns the result or throw {@link IOException} if it's unable to complete the action
+ * and {@link IllegalArgumentException} if {@code unwrapBlob} fails because the wrappedBlob is
+ * stale.
+ *
+ * @param wrappedBlob The wrapped blob with size on the order of 100 bytes.
+ * @return Unwrapped blob used for resume-on-reboot with the size on the order of 100 bytes.
+ * @throws IOException if the implementation is unable to unwrap the wrapped blob successfully.
+ */
+ @NonNull
+ public abstract byte[] onUnwrap(@NonNull byte[] wrappedBlob) throws IOException;
+
+ private final android.service.resumeonreboot.IResumeOnRebootService mInterface =
+ new android.service.resumeonreboot.IResumeOnRebootService.Stub() {
+
+ @Override
+ public void wrapSecret(byte[] unwrappedBlob,
+ @DurationMillisLong long lifeTimeInMillis,
+ RemoteCallback resultCallback) throws RemoteException {
+ mHandler.post(() -> {
+ try {
+ byte[] wrappedBlob = onWrap(unwrappedBlob,
+ lifeTimeInMillis);
+ Bundle bundle = new Bundle();
+ bundle.putByteArray(WRAPPED_BLOB_KEY, wrappedBlob);
+ resultCallback.sendResult(bundle);
+ } catch (Throwable e) {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(EXCEPTION_KEY, new ParcelableException(e));
+ resultCallback.sendResult(bundle);
+ }
+ });
+ }
+
+ @Override
+ public void unwrap(byte[] wrappedBlob, RemoteCallback resultCallback)
+ throws RemoteException {
+ mHandler.post(() -> {
+ try {
+ byte[] unwrappedBlob = onUnwrap(wrappedBlob);
+ Bundle bundle = new Bundle();
+ bundle.putByteArray(UNWRAPPED_BLOB_KEY, unwrappedBlob);
+ resultCallback.sendResult(bundle);
+ } catch (Throwable e) {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(EXCEPTION_KEY, new ParcelableException(e));
+ resultCallback.sendResult(bundle);
+ }
+ });
+ }
+ };
+
+ @Nullable
+ @Override
+ public IBinder onBind(@Nullable Intent intent) {
+ return mInterface.asBinder();
+ }
+}
diff --git a/core/java/android/service/textservice/OWNERS b/core/java/android/service/textservice/OWNERS
index 10b8b76..0471e29 100644
--- a/core/java/android/service/textservice/OWNERS
+++ b/core/java/android/service/textservice/OWNERS
@@ -1,3 +1,3 @@
-# Bug component: 34867
+# Bug component: 816455
-include ../../inputmethodservice/OWNERS
\ No newline at end of file
+include /services/core/java/com/android/server/textservices/OWNERS
diff --git a/core/java/android/service/textservice/SpellCheckerService.java b/core/java/android/service/textservice/SpellCheckerService.java
index bd1b44c..e492584 100644
--- a/core/java/android/service/textservice/SpellCheckerService.java
+++ b/core/java/android/service/textservice/SpellCheckerService.java
@@ -16,11 +16,6 @@
package android.service.textservice;
-import com.android.internal.textservice.ISpellCheckerService;
-import com.android.internal.textservice.ISpellCheckerServiceCallback;
-import com.android.internal.textservice.ISpellCheckerSession;
-import com.android.internal.textservice.ISpellCheckerSessionListener;
-
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
@@ -34,6 +29,11 @@
import android.view.textservice.SuggestionsInfo;
import android.view.textservice.TextInfo;
+import com.android.internal.textservice.ISpellCheckerService;
+import com.android.internal.textservice.ISpellCheckerServiceCallback;
+import com.android.internal.textservice.ISpellCheckerSession;
+import com.android.internal.textservice.ISpellCheckerSessionListener;
+
import java.lang.ref.WeakReference;
import java.text.BreakIterator;
import java.util.ArrayList;
@@ -231,6 +231,18 @@
public Bundle getBundle() {
return mInternalSession.getBundle();
}
+
+ /**
+ * Returns result attributes supported for this session.
+ *
+ * <p>The session implementation should not set attributes that are not included in the
+ * return value of {@code getSupportedAttributes()} when creating {@link SuggestionsInfo}.
+ *
+ * @return The supported result attributes for this session
+ */
+ public @SuggestionsInfo.ResultAttrs int getSupportedAttributes() {
+ return mInternalSession.getSupportedAttributes();
+ }
}
// Preventing from exposing ISpellCheckerSession.aidl, create an internal class.
@@ -239,13 +251,16 @@
private final Session mSession;
private final String mLocale;
private final Bundle mBundle;
+ private final @SuggestionsInfo.ResultAttrs int mSupportedAttributes;
public InternalISpellCheckerSession(String locale, ISpellCheckerSessionListener listener,
- Bundle bundle, Session session) {
+ Bundle bundle, Session session,
+ @SuggestionsInfo.ResultAttrs int supportedAttributes) {
mListener = listener;
mSession = session;
mLocale = locale;
mBundle = bundle;
+ mSupportedAttributes = supportedAttributes;
session.setInternalISpellCheckerSession(this);
}
@@ -303,6 +318,10 @@
public Bundle getBundle() {
return mBundle;
}
+
+ public @SuggestionsInfo.ResultAttrs int getSupportedAttributes() {
+ return mSupportedAttributes;
+ }
}
private static class SpellCheckerServiceBinder extends ISpellCheckerService.Stub {
@@ -323,11 +342,14 @@
* {@link Session#onGetSuggestionsMultiple(TextInfo[], int, boolean)} and
* {@link Session#onGetSuggestions(TextInfo, int)}
* @param bundle bundle to be returned from {@link Session#getBundle()}
+ * @param supportedAttributes A union of {@link SuggestionsInfo} attributes that the spell
+ * checker can set in the spell checking results.
* @param callback IPC channel to return the result to the caller in an asynchronous manner
*/
@Override
public void getISpellCheckerSession(
String locale, ISpellCheckerSessionListener listener, Bundle bundle,
+ @SuggestionsInfo.ResultAttrs int supportedAttributes,
ISpellCheckerServiceCallback callback) {
final SpellCheckerService service = mInternalServiceRef.get();
final InternalISpellCheckerSession internalSession;
@@ -337,8 +359,8 @@
internalSession = null;
} else {
final Session session = service.createSession();
- internalSession =
- new InternalISpellCheckerSession(locale, listener, bundle, session);
+ internalSession = new InternalISpellCheckerSession(
+ locale, listener, bundle, session, supportedAttributes);
session.onCreate();
}
try {
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 63ee927..aa05787 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -225,7 +225,7 @@
private static native void nativeSetFixedTransformHint(long transactionObj, long nativeObject,
int transformHint);
private static native void nativeSetFocusedWindow(long transactionObj, IBinder toToken,
- IBinder focusedToken, int displayId);
+ String windowName, IBinder focusedToken, String focusedWindowName, int displayId);
private static native void nativeSetFrameTimelineVsync(long transactionObj,
long frameTimelineVsyncId);
private static native void nativeAddJankDataListener(long nativeListener,
@@ -3282,8 +3282,10 @@
*
* @hide
*/
- public Transaction setFocusedWindow(@NonNull IBinder token, int displayId) {
- nativeSetFocusedWindow(mNativeObject, token, null /* focusedToken */, displayId);
+ public Transaction setFocusedWindow(@NonNull IBinder token, String windowName,
+ int displayId) {
+ nativeSetFocusedWindow(mNativeObject, token, windowName,
+ null /* focusedToken */, null /* focusedWindowName */, displayId);
return this;
}
@@ -3298,9 +3300,12 @@
* @hide
*/
public Transaction requestFocusTransfer(@NonNull IBinder token,
+ String windowName,
@NonNull IBinder focusedToken,
+ String focusedWindowName,
int displayId) {
- nativeSetFocusedWindow(mNativeObject, token, focusedToken, displayId);
+ nativeSetFocusedWindow(mNativeObject, token, windowName, focusedToken,
+ focusedWindowName, displayId);
return this;
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 7ac57b5..f603ef7 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -1193,11 +1193,9 @@
private void setBufferSize(Transaction transaction) {
if (mUseBlastAdapter) {
- mBlastBufferQueue.update(mBlastSurfaceControl, mSurfaceWidth,
- mSurfaceHeight);
+ mBlastBufferQueue.update(mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight, mFormat);
} else {
- transaction.setBufferSize(mSurfaceControl, mSurfaceWidth,
- mSurfaceHeight);
+ transaction.setBufferSize(mSurfaceControl, mSurfaceWidth, mSurfaceHeight);
}
}
@@ -1241,15 +1239,14 @@
.setName(name + "(BLAST)")
.setLocalOwnerView(this)
.setBufferSize(mSurfaceWidth, mSurfaceHeight)
- .setFormat(mFormat)
.setParent(mSurfaceControl)
.setFlags(mSurfaceFlags)
.setHidden(false)
.setBLASTLayer()
.setCallsite("SurfaceView.updateSurface")
.build();
- mBlastBufferQueue = new BLASTBufferQueue(name,
- mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight, true /* TODO */);
+ mBlastBufferQueue = new BLASTBufferQueue(name, mBlastSurfaceControl, mSurfaceWidth,
+ mSurfaceHeight, mFormat, true /* TODO */);
} else {
previousSurfaceControl = mSurfaceControl;
mSurfaceControl = builder
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index d694962..96d7304 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1852,20 +1852,22 @@
return mBoundsLayer;
}
- Surface getOrCreateBLASTSurface(int width, int height) {
+ Surface getOrCreateBLASTSurface(int width, int height,
+ @Nullable WindowManager.LayoutParams params) {
if (!mSurfaceControl.isValid()) {
return null;
}
+ int format = params == null ? PixelFormat.TRANSLUCENT : params.format;
Surface ret = null;
if (mBlastBufferQueue == null) {
- mBlastBufferQueue = new BLASTBufferQueue(mTag,
- mSurfaceControl, width, height, mEnableTripleBuffering);
+ mBlastBufferQueue = new BLASTBufferQueue(mTag, mSurfaceControl, width, height,
+ format, mEnableTripleBuffering);
// We only return the Surface the first time, as otherwise
// it hasn't changed and there is no need to update.
ret = mBlastBufferQueue.createSurface();
} else {
- mBlastBufferQueue.update(mSurfaceControl, width, height);
+ mBlastBufferQueue.update(mSurfaceControl, width, height, format);
}
return ret;
@@ -7608,8 +7610,8 @@
if (!useBLAST()) {
mSurface.copyFrom(mSurfaceControl);
} else {
- final Surface blastSurface = getOrCreateBLASTSurface(mSurfaceSize.x,
- mSurfaceSize.y);
+ final Surface blastSurface = getOrCreateBLASTSurface(mSurfaceSize.x, mSurfaceSize.y,
+ params);
// If blastSurface == null that means it hasn't changed since the last time we
// called. In this situation, avoid calling transferFrom as we would then
// inc the generation ID and cause EGL resources to be recreated.
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index c2d990a..8b8645c 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -2151,9 +2151,8 @@
* visible window.
* @hide
*/
- @SystemApi
@RequiresPermission(permission.SYSTEM_APPLICATION_OVERLAY)
- public static final int SYSTEM_FLAG_SYSTEM_APPLICATION_OVERLAY = 0x00000008;
+ public static final int PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY = 0x00000008;
/** In a multiuser system if this flag is set and the owner is a system process then this
* window will appear on all user screens. This overrides the default behavior of window
@@ -2352,7 +2351,6 @@
@IntDef(flag = true, prefix = { "SYSTEM_FLAG_" }, value = {
SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
SYSTEM_FLAG_SHOW_FOR_ALL_USERS,
- SYSTEM_FLAG_SYSTEM_APPLICATION_OVERLAY,
})
public @interface SystemFlags {}
@@ -2386,7 +2384,7 @@
PRIVATE_FLAG_TRUSTED_OVERLAY,
PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME,
PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP,
- SYSTEM_FLAG_SYSTEM_APPLICATION_OVERLAY,
+ PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY,
})
public @interface PrivateFlags {}
@@ -2501,9 +2499,9 @@
equals = PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP,
name = "INTERCEPT_GLOBAL_DRAG_AND_DROP"),
@ViewDebug.FlagToString(
- mask = SYSTEM_FLAG_SYSTEM_APPLICATION_OVERLAY,
- equals = SYSTEM_FLAG_SYSTEM_APPLICATION_OVERLAY,
- name = "SYSTEM_FLAG_SYSTEM_APPLICATION_OVERLAY")
+ mask = PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY,
+ equals = PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY,
+ name = "PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY")
})
@PrivateFlags
@TestApi
@@ -3375,6 +3373,37 @@
}
/**
+ * When set on {@link LayoutParams#TYPE_APPLICATION_OVERLAY} windows they stay visible,
+ * even if {@link LayoutParams#SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS} is set for
+ * another visible window.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(permission.SYSTEM_APPLICATION_OVERLAY)
+ public void setSystemApplicationOverlay(boolean isSystemApplicationOverlay) {
+ if (isSystemApplicationOverlay) {
+ privateFlags |= PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY;
+ } else {
+ privateFlags &= ~PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY;
+ }
+ }
+
+ /**
+ * Returns if this window is marked as being a system application overlay.
+ * @see LayoutParams#setSystemApplicationOverlay(boolean)
+ *
+ * <p>Note: the owner of the window must hold
+ * {@link android.Manifest.permission.SYSTEM_APPLICATION_OVERLAY} for this to have any
+ * effect.
+ * @hide
+ */
+ @SystemApi
+ public boolean isSystemApplicationOverlay() {
+ return (privateFlags & PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY)
+ == PRIVATE_FLAG_SYSTEM_APPLICATION_OVERLAY;
+ }
+
+ /**
* @return the insets types that this window is avoiding overlapping.
*/
public @InsetsType int getFitInsetsTypes() {
diff --git a/core/java/android/view/WindowManagerPolicyConstants.java b/core/java/android/view/WindowManagerPolicyConstants.java
index dd55f04..7668d80 100644
--- a/core/java/android/view/WindowManagerPolicyConstants.java
+++ b/core/java/android/view/WindowManagerPolicyConstants.java
@@ -17,6 +17,7 @@
package android.view;
import android.annotation.IntDef;
+import android.os.PowerManager;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -108,6 +109,27 @@
void onPointerEvent(MotionEvent motionEvent);
}
+ @IntDef(prefix = { "OFF_BECAUSE_OF_" }, value = {
+ OFF_BECAUSE_OF_ADMIN,
+ OFF_BECAUSE_OF_USER,
+ OFF_BECAUSE_OF_TIMEOUT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface OffReason{}
+
+ static @OffReason int translateSleepReasonToOffReason(
+ @PowerManager.GoToSleepReason int reason) {
+ switch (reason) {
+ case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:
+ return OFF_BECAUSE_OF_ADMIN;
+ case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:
+ case PowerManager.GO_TO_SLEEP_REASON_INATTENTIVE:
+ return OFF_BECAUSE_OF_TIMEOUT;
+ default:
+ return OFF_BECAUSE_OF_USER;
+ }
+ }
+
/** Screen turned off because of a device admin */
int OFF_BECAUSE_OF_ADMIN = 1;
/** Screen turned off because of power button */
@@ -137,6 +159,23 @@
}
}
+ static @OnReason int translateWakeReasonToOnReason(@PowerManager.WakeReason int reason) {
+ switch (reason) {
+ case PowerManager.WAKE_REASON_POWER_BUTTON:
+ case PowerManager.WAKE_REASON_PLUGGED_IN:
+ case PowerManager.WAKE_REASON_GESTURE:
+ case PowerManager.WAKE_REASON_CAMERA_LAUNCH:
+ case PowerManager.WAKE_REASON_WAKE_KEY:
+ case PowerManager.WAKE_REASON_WAKE_MOTION:
+ case PowerManager.WAKE_REASON_LID:
+ return ON_BECAUSE_OF_USER;
+ case PowerManager.WAKE_REASON_APPLICATION:
+ return ON_BECAUSE_OF_APPLICATION;
+ default:
+ return ON_BECAUSE_OF_UNKNOWN;
+ }
+ }
+
/** Screen turned on because of a user-initiated action. */
int ON_BECAUSE_OF_USER = 1;
/** Screen turned on because of an application request or event */
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 0a4b784..5140c09 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -2926,7 +2926,10 @@
? SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES
: SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES;
try {
- mService.showInputMethodPickerFromSystem(mClient, mode, displayId);
+ final Completable.Void value = Completable.createVoid();
+ mService.showInputMethodPickerFromSystem(
+ mClient, mode, displayId, ResultCallbacks.of(value));
+ Completable.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2934,7 +2937,10 @@
private void showInputMethodPickerLocked() {
try {
- mService.showInputMethodPickerFromClient(mClient, SHOW_IM_PICKER_MODE_AUTO);
+ final Completable.Void value = Completable.createVoid();
+ mService.showInputMethodPickerFromClient(
+ mClient, SHOW_IM_PICKER_MODE_AUTO, ResultCallbacks.of(value));
+ Completable.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2970,7 +2976,10 @@
*/
public void showInputMethodAndSubtypeEnabler(String imiId) {
try {
- mService.showInputMethodAndSubtypeEnablerFromClient(mClient, imiId);
+ final Completable.Void value = Completable.createVoid();
+ mService.showInputMethodAndSubtypeEnablerFromClient(
+ mClient, imiId, ResultCallbacks.of(value));
+ Completable.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3132,7 +3141,10 @@
matrixValues = new float[9];
matrix.getValues(matrixValues);
}
- mService.reportActivityView(mClient, childDisplayId, matrixValues);
+ final Completable.Void value = Completable.createVoid();
+ mService.reportActivityView(
+ mClient, childDisplayId, matrixValues, ResultCallbacks.of(value));
+ Completable.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/view/textservice/OWNERS b/core/java/android/view/textservice/OWNERS
index 582be8d..0471e29 100644
--- a/core/java/android/view/textservice/OWNERS
+++ b/core/java/android/view/textservice/OWNERS
@@ -1,3 +1,3 @@
-# Bug component: 34867
+# Bug component: 816455
-include ../inputmethod/OWNERS
+include /services/core/java/com/android/server/textservices/OWNERS
diff --git a/core/java/android/view/textservice/SuggestionsInfo.java b/core/java/android/view/textservice/SuggestionsInfo.java
index 1301c49..775a6bd 100644
--- a/core/java/android/view/textservice/SuggestionsInfo.java
+++ b/core/java/android/view/textservice/SuggestionsInfo.java
@@ -16,11 +16,15 @@
package android.view.textservice;
+import android.annotation.IntDef;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.util.ArrayUtils;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* This class contains a metadata of suggestions from the text service
*/
@@ -28,6 +32,22 @@
private static final String[] EMPTY = ArrayUtils.emptyArray(String.class);
/**
+ * An internal annotation to indicate that one ore more combinations of
+ * <code>RESULT_ATTR_</code> flags are expected.
+ *
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = { "RESULT_ATTR_" }, value = {
+ RESULT_ATTR_IN_THE_DICTIONARY,
+ RESULT_ATTR_LOOKS_LIKE_TYPO,
+ RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS,
+ RESULT_ATTR_LOOKS_LIKE_GRAMMAR_ERROR,
+ RESULT_ATTR_DONT_SHOW_UI_FOR_SUGGESTIONS,
+ })
+ public @interface ResultAttrs {}
+
+ /**
* Flag of the attributes of the suggestions that can be obtained by
* {@link #getSuggestionsAttributes}: this tells that the requested word was found
* in the dictionary in the text service.
@@ -63,7 +83,7 @@
*/
public static final int RESULT_ATTR_DONT_SHOW_UI_FOR_SUGGESTIONS = 0x0010;
- private final int mSuggestionsAttributes;
+ private final @ResultAttrs int mSuggestionsAttributes;
private final String[] mSuggestions;
private final boolean mSuggestionsAvailable;
private int mCookie;
@@ -85,8 +105,8 @@
* @param cookie the cookie of the input TextInfo
* @param sequence the cookie of the input TextInfo
*/
- public SuggestionsInfo(
- int suggestionsAttributes, String[] suggestions, int cookie, int sequence) {
+ public SuggestionsInfo(@ResultAttrs int suggestionsAttributes, String[] suggestions, int cookie,
+ int sequence) {
if (suggestions == null) {
mSuggestions = EMPTY;
mSuggestionsAvailable = false;
@@ -152,7 +172,7 @@
* in its dictionary or not and whether the spell checker has confident suggestions for the
* word or not.
*/
- public int getSuggestionsAttributes() {
+ public @ResultAttrs int getSuggestionsAttributes() {
return mSuggestionsAttributes;
}
diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java
index 578ed8c..0a1aea3 100644
--- a/core/java/android/view/textservice/TextServicesManager.java
+++ b/core/java/android/view/textservice/TextServicesManager.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.annotation.SystemService;
import android.annotation.UserIdInt;
import android.compat.annotation.UnsupportedAppUsage;
@@ -139,21 +140,58 @@
}
/**
- * Get a spell checker session for the specified spell checker
- * @param locale the locale for the spell checker. If {@code locale} is null and
- * referToSpellCheckerLanguageSettings is true, the locale specified in Settings will be
- * returned. If {@code locale} is not null and referToSpellCheckerLanguageSettings is true,
- * the locale specified in Settings will be returned only when it is same as {@code locale}.
- * Exceptionally, when referToSpellCheckerLanguageSettings is true and {@code locale} is
- * only language (e.g. "en"), the specified locale in Settings (e.g. "en_US") will be
- * selected.
- * @param listener a spell checker session lister for getting results from a spell checker.
- * @param referToSpellCheckerLanguageSettings if true, the session for one of enabled
- * languages in settings will be returned.
- * @return the spell checker session of the spell checker
+ * Get a spell checker session from the spell checker.
+ *
+ * <p>{@link SuggestionsInfo#RESULT_ATTR_IN_THE_DICTIONARY},
+ * {@link SuggestionsInfo#RESULT_ATTR_LOOKS_LIKE_TYPO}, and
+ * {@link SuggestionsInfo#RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS} will be passed to the spell
+ * checker as supported attributes.
+ *
+ * @see #newSpellCheckerSession(Bundle, Locale, SpellCheckerSessionListener, boolean, int)
+ * @param bundle A bundle to pass to the spell checker.
+ * @param locale The locale for the spell checker.
+ * @param listener A spell checker session lister for getting results from the spell checker.
+ * @param referToSpellCheckerLanguageSettings If true, the session for one of enabled
+ * languages in settings will be used.
+ * @return A spell checker session from the spell checker.
*/
- public SpellCheckerSession newSpellCheckerSession(Bundle bundle, Locale locale,
- SpellCheckerSessionListener listener, boolean referToSpellCheckerLanguageSettings) {
+ @Nullable
+ public SpellCheckerSession newSpellCheckerSession(@Nullable Bundle bundle,
+ @Nullable Locale locale,
+ @NonNull SpellCheckerSessionListener listener,
+ boolean referToSpellCheckerLanguageSettings) {
+ return newSpellCheckerSession(bundle, locale, listener, referToSpellCheckerLanguageSettings,
+ SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY
+ | SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO
+ | SuggestionsInfo.RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS);
+ }
+
+ /**
+ * Get a spell checker session from the spell checker.
+ *
+ * <p>If {@code locale} is null and {@code referToSpellCheckerLanguageSettings} is true, the
+ * locale specified in Settings will be used. If {@code locale} is not null and
+ * {@code referToSpellCheckerLanguageSettings} is true, the locale specified in Settings will be
+ * returned only when it is same as {@code locale}.
+ * Exceptionally, when {@code referToSpellCheckerLanguageSettings} is true and {@code locale} is
+ * language only (e.g. "en"), the specified locale in Settings (e.g. "en_US") will be
+ * selected.
+ *
+ * @param bundle A bundle to pass to the spell checker.
+ * @param locale The locale for the spell checker.
+ * @param listener A spell checker session lister for getting results from a spell checker.
+ * @param referToSpellCheckerLanguageSettings If true, the session for one of enabled
+ * languages in settings will be used.
+ * @param supportedAttributes A union of {@link SuggestionsInfo} attributes that the spell
+ * checker can set in the spell checking results.
+ * @return The spell checker session of the spell checker.
+ */
+ @Nullable
+ public SpellCheckerSession newSpellCheckerSession(@Nullable Bundle bundle,
+ @SuppressLint("UseIcu") @Nullable Locale locale,
+ @NonNull SpellCheckerSessionListener listener,
+ @SuppressLint("ListenerLast") boolean referToSpellCheckerLanguageSettings,
+ @SuppressLint("ListenerLast") @SuggestionsInfo.ResultAttrs int supportedAttributes) {
if (listener == null) {
throw new NullPointerException();
}
@@ -210,7 +248,7 @@
try {
mService.getSpellCheckerService(mUserId, sci.getId(), subtypeInUse.getLocale(),
session.getTextServicesSessionListener(),
- session.getSpellCheckerSessionListener(), bundle);
+ session.getSpellCheckerSessionListener(), bundle, supportedAttributes);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index b06fa1a..97d98fd 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -129,7 +129,11 @@
mSpellCheckerSession = mTextServicesManager.newSpellCheckerSession(
null /* Bundle not currently used by the textServicesManager */,
mCurrentLocale, this,
- false /* means any available languages from current spell checker */);
+ false /* means any available languages from current spell checker */,
+ SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY
+ | SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO
+ | SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_GRAMMAR_ERROR
+ | SuggestionsInfo.RESULT_ATTR_DONT_SHOW_UI_FOR_SUGGESTIONS);
mIsSentenceSpellCheckSupported = true;
}
diff --git a/core/java/com/android/internal/inputmethod/CallbackUtils.java b/core/java/com/android/internal/inputmethod/CallbackUtils.java
index e9e39db..2113173 100644
--- a/core/java/com/android/internal/inputmethod/CallbackUtils.java
+++ b/core/java/com/android/internal/inputmethod/CallbackUtils.java
@@ -205,14 +205,14 @@
* A utility method using given {@link IVoidResultCallback} to callback the result.
*
* @param callback {@link IVoidResultCallback} to be called back.
- * @param resultSupplier the supplier from which the result is provided.
+ * @param runnable to execute the given method
*/
public static void onResult(@NonNull IVoidResultCallback callback,
- @NonNull Supplier<Void> resultSupplier) {
+ @NonNull Runnable runnable) {
Throwable exception = null;
try {
- resultSupplier.get();
+ runnable.run();
} catch (Throwable throwable) {
exception = throwable;
}
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index 9e59e50..4a24358 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -339,8 +339,9 @@
}
mPowerCalculators.add(new WifiPowerCalculator(mPowerProfile));
mPowerCalculators.add(new BluetoothPowerCalculator(mPowerProfile));
- mPowerCalculators.add(new SensorPowerCalculator(mPowerProfile,
+ mPowerCalculators.add(new SensorPowerCalculator(
mContext.getSystemService(SensorManager.class)));
+ mPowerCalculators.add(new GnssPowerCalculator(mPowerProfile));
mPowerCalculators.add(new CameraPowerCalculator(mPowerProfile));
mPowerCalculators.add(new FlashlightPowerCalculator(mPowerProfile));
mPowerCalculators.add(new MediaPowerCalculator(mPowerProfile));
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index f105320..ee3c12c 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -860,14 +860,11 @@
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
protected int mScreenState = Display.STATE_UNKNOWN;
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- protected StopwatchTimer mScreenOnTimer;
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- protected StopwatchTimer mScreenDozeTimer;
+ StopwatchTimer mScreenOnTimer;
+ StopwatchTimer mScreenDozeTimer;
int mScreenBrightnessBin = -1;
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- protected final StopwatchTimer[] mScreenBrightnessTimer =
+ final StopwatchTimer[] mScreenBrightnessTimer =
new StopwatchTimer[NUM_SCREEN_BRIGHTNESS_BINS];
boolean mPretendScreenOff;
@@ -912,8 +909,7 @@
int mUsbDataState = USB_DATA_UNKNOWN;
int mGpsSignalQualityBin = -1;
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- protected final StopwatchTimer[] mGpsSignalQualityTimer =
+ final StopwatchTimer[] mGpsSignalQualityTimer =
new StopwatchTimer[GnssSignalQuality.NUM_GNSS_SIGNAL_QUALITY_LEVELS];
int mPhoneSignalStrengthBin = -1;
@@ -929,6 +925,7 @@
final LongSamplingCounter[] mNetworkByteActivityCounters =
new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
+
final LongSamplingCounter[] mNetworkPacketActivityCounters =
new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
@@ -948,8 +945,7 @@
/**
* The Bluetooth controller activity (time in tx, rx, idle, and power consumed) for the device.
*/
- @VisibleForTesting
- protected ControllerActivityCounterImpl mBluetoothActivity;
+ ControllerActivityCounterImpl mBluetoothActivity;
/**
* The Modem controller activity (time in tx, rx, idle, and power consumed) for the device.
@@ -993,8 +989,7 @@
StopwatchTimer mWifiActiveTimer;
int mBluetoothScanNesting;
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- protected StopwatchTimer mBluetoothScanTimer;
+ StopwatchTimer mBluetoothScanTimer;
int mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
long mMobileRadioActiveStartTimeMs;
@@ -10718,6 +10713,31 @@
mHandler = new MyHandler(handler.getLooper());
mConstants = new Constants(mHandler);
mStartCount++;
+ initTimersAndCounters();
+ mOnBattery = mOnBatteryInternal = false;
+ long uptimeUs = mClocks.uptimeMillis() * 1000;
+ long realtimeUs = mClocks.elapsedRealtime() * 1000;
+ initTimes(uptimeUs, realtimeUs);
+ mStartPlatformVersion = mEndPlatformVersion = Build.ID;
+ mDischargeStartLevel = 0;
+ mDischargeUnplugLevel = 0;
+ mDischargePlugLevel = -1;
+ mDischargeCurrentLevel = 0;
+ mCurrentBatteryLevel = 0;
+ initDischarge(realtimeUs);
+ clearHistoryLocked();
+ updateDailyDeadlineLocked();
+ mPlatformIdleStateCallback = cb;
+ mMeasuredEnergyRetriever = energyStatsCb;
+ mUserInfoProvider = userInfoProvider;
+
+ // Notify statsd that the system is initially not in doze.
+ mDeviceIdleMode = DEVICE_IDLE_MODE_OFF;
+ FrameworkStatsLog.write(FrameworkStatsLog.DEVICE_IDLE_MODE_STATE_CHANGED, mDeviceIdleMode);
+ }
+
+ @VisibleForTesting
+ protected void initTimersAndCounters() {
mScreenOnTimer = new StopwatchTimer(mClocks, null, -1, null, mOnBatteryTimeBase);
mScreenDozeTimer = new StopwatchTimer(mClocks, null, -1, null, mOnBatteryTimeBase);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
@@ -10789,26 +10809,6 @@
mDischargeLightDozeCounter = new LongSamplingCounter(mOnBatteryTimeBase);
mDischargeDeepDozeCounter = new LongSamplingCounter(mOnBatteryTimeBase);
mDischargeCounter = new LongSamplingCounter(mOnBatteryTimeBase);
- mOnBattery = mOnBatteryInternal = false;
- long uptimeUs = mClocks.uptimeMillis() * 1000;
- long realtimeUs = mClocks.elapsedRealtime() * 1000;
- initTimes(uptimeUs, realtimeUs);
- mStartPlatformVersion = mEndPlatformVersion = Build.ID;
- mDischargeStartLevel = 0;
- mDischargeUnplugLevel = 0;
- mDischargePlugLevel = -1;
- mDischargeCurrentLevel = 0;
- mCurrentBatteryLevel = 0;
- initDischarge(realtimeUs);
- clearHistoryLocked();
- updateDailyDeadlineLocked();
- mPlatformIdleStateCallback = cb;
- mMeasuredEnergyRetriever = energyStatsCb;
- mUserInfoProvider = userInfoProvider;
-
- // Notify statsd that the system is initially not in doze.
- mDeviceIdleMode = DEVICE_IDLE_MODE_OFF;
- FrameworkStatsLog.write(FrameworkStatsLog.DEVICE_IDLE_MODE_STATE_CHANGED, mDeviceIdleMode);
}
@UnsupportedAppUsage
@@ -11623,7 +11623,8 @@
@GuardedBy("mModemNetworkLock")
private NetworkStats mLastModemNetworkStats = new NetworkStats(0, -1);
- private NetworkStats readNetworkStatsLocked(String[] ifaces) {
+ @VisibleForTesting
+ protected NetworkStats readNetworkStatsLocked(String[] ifaces) {
try {
if (!ArrayUtils.isEmpty(ifaces)) {
INetworkStatsService statsService = INetworkStatsService.Stub.asInterface(
@@ -11922,7 +11923,7 @@
/**
* Distribute Cell radio energy info and network traffic to apps.
*/
- public void updateMobileRadioState(@Nullable final ModemActivityInfo activityInfo,
+ public void noteModemControllerActivity(@Nullable final ModemActivityInfo activityInfo,
long elapsedRealtimeMs, long uptimeMs) {
if (DEBUG_ENERGY) {
Slog.d(TAG, "Updating mobile radio stats with " + activityInfo);
diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
index e5d64a0..b8c066d 100644
--- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
+++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
@@ -62,8 +62,9 @@
}
mPowerCalculators.add(new WifiPowerCalculator(mPowerProfile));
mPowerCalculators.add(new BluetoothPowerCalculator(mPowerProfile));
- mPowerCalculators.add(new SensorPowerCalculator(mPowerProfile,
+ mPowerCalculators.add(new SensorPowerCalculator(
mContext.getSystemService(SensorManager.class)));
+ mPowerCalculators.add(new GnssPowerCalculator(mPowerProfile));
mPowerCalculators.add(new CameraPowerCalculator(mPowerProfile));
mPowerCalculators.add(new FlashlightPowerCalculator(mPowerProfile));
mPowerCalculators.add(new AudioPowerCalculator(mPowerProfile));
diff --git a/core/java/com/android/internal/os/GnssPowerCalculator.java b/core/java/com/android/internal/os/GnssPowerCalculator.java
new file mode 100644
index 0000000..9ea934a
--- /dev/null
+++ b/core/java/com/android/internal/os/GnssPowerCalculator.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.os;
+
+import android.location.GnssSignalQuality;
+import android.os.BatteryConsumer;
+import android.os.BatteryStats;
+import android.os.BatteryUsageStats;
+import android.os.BatteryUsageStatsQuery;
+import android.os.UidBatteryConsumer;
+import android.os.UserHandle;
+import android.util.SparseArray;
+
+import java.util.List;
+
+/**
+ * Estimates the amount of power consumed by the GNSS (e.g. GPS).
+ */
+public class GnssPowerCalculator extends PowerCalculator {
+ private final double mAveragePowerGnssOn;
+ private final double[] mAveragePowerPerSignalQuality;
+
+ public GnssPowerCalculator(PowerProfile profile) {
+ mAveragePowerGnssOn = profile.getAveragePowerOrDefault(PowerProfile.POWER_GPS_ON, -1);
+ mAveragePowerPerSignalQuality =
+ new double[GnssSignalQuality.NUM_GNSS_SIGNAL_QUALITY_LEVELS];
+ for (int i = 0; i < GnssSignalQuality.NUM_GNSS_SIGNAL_QUALITY_LEVELS; i++) {
+ mAveragePowerPerSignalQuality[i] = profile.getAveragePower(
+ PowerProfile.POWER_GPS_SIGNAL_QUALITY_BASED, i);
+ }
+ }
+
+ @Override
+ public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
+ long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query,
+ SparseArray<UserHandle> asUsers) {
+ final double averageGnssPowerMa = getAverageGnssPower(batteryStats, rawRealtimeUs,
+ BatteryStats.STATS_SINCE_CHARGED);
+ final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders =
+ builder.getUidBatteryConsumerBuilders();
+ for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
+ final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
+ calculateApp(app, app.getBatteryStatsUid(), rawRealtimeUs, rawUptimeUs, query,
+ averageGnssPowerMa);
+ }
+ }
+
+ private void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
+ long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query,
+ double averageGnssPowerMa) {
+ final long durationMs = computeDuration(u, rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED);
+ double powerMah = computePower(durationMs, averageGnssPowerMa);
+ app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_GNSS, durationMs)
+ .setConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS, powerMah);
+ }
+
+ @Override
+ public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
+ long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
+ double averageGnssPowerMa = getAverageGnssPower(batteryStats, rawRealtimeUs, statsType);
+ for (int i = sippers.size() - 1; i >= 0; i--) {
+ final BatterySipper app = sippers.get(i);
+ if (app.drainType == BatterySipper.DrainType.APP) {
+ calculateApp(app, app.uidObj, rawRealtimeUs, statsType, averageGnssPowerMa);
+ }
+ }
+ }
+
+ protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
+ int statsType, double averageGnssPowerMa) {
+ final long durationMs = computeDuration(u, rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED);
+ double powerMah = computePower(durationMs, averageGnssPowerMa);
+
+ app.gpsTimeMs = durationMs;
+ app.gpsPowerMah = powerMah;
+ }
+
+ private long computeDuration(BatteryStats.Uid u, long rawRealtimeUs, int statsType) {
+ final SparseArray<? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats();
+ final BatteryStats.Uid.Sensor sensor = sensorStats.get(BatteryStats.Uid.Sensor.GPS);
+ if (sensor == null) {
+ return 0;
+ }
+
+ final BatteryStats.Timer timer = sensor.getSensorTime();
+ return timer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000;
+ }
+
+ private double computePower(long sensorTime, double averageGnssPowerMa) {
+ return (sensorTime * averageGnssPowerMa) / (1000 * 60 * 60);
+ }
+
+ private double getAverageGnssPower(BatteryStats stats, long rawRealtimeUs, int statsType) {
+ double averagePower = mAveragePowerGnssOn;
+ if (averagePower != -1) {
+ return averagePower;
+ }
+ averagePower = 0;
+ long totalTime = 0;
+ double totalPower = 0;
+ for (int i = 0; i < GnssSignalQuality.NUM_GNSS_SIGNAL_QUALITY_LEVELS; i++) {
+ long timePerLevel = stats.getGpsSignalQualityTime(i, rawRealtimeUs, statsType);
+ totalTime += timePerLevel;
+ totalPower += mAveragePowerPerSignalQuality[i] * timePerLevel;
+ }
+ if (totalTime != 0) {
+ averagePower = totalPower / totalTime;
+ }
+ return averagePower;
+ }
+}
diff --git a/core/java/com/android/internal/os/MobileRadioPowerCalculator.java b/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
index 790d2e5..e3bd64d 100644
--- a/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
+++ b/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
@@ -15,7 +15,12 @@
*/
package com.android.internal.os;
+import android.os.BatteryConsumer;
import android.os.BatteryStats;
+import android.os.BatteryUsageStats;
+import android.os.BatteryUsageStatsQuery;
+import android.os.SystemBatteryConsumer;
+import android.os.UidBatteryConsumer;
import android.os.UserHandle;
import android.telephony.CellSignalStrength;
import android.util.Log;
@@ -26,103 +31,146 @@
public class MobileRadioPowerCalculator extends PowerCalculator {
private static final String TAG = "MobRadioPowerCalculator";
private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
- private final double mPowerRadioOn;
- private final double[] mPowerBins = new double[CellSignalStrength.getNumSignalStrengthLevels()];
- private final double mPowerScan;
- private BatteryStats mStats;
- private long mTotalAppMobileActiveMs = 0;
- /**
- * Return estimated power (in mAs) of sending or receiving a packet with the mobile radio.
- */
- private double getMobilePowerPerPacket(long rawRealtimeUs, int statsType) {
- final long MOBILE_BPS = 200000; // TODO: Extract average bit rates from system
- final double MOBILE_POWER = mPowerRadioOn / 3600;
+ private static final int NUM_SIGNAL_STRENGTH_LEVELS =
+ CellSignalStrength.getNumSignalStrengthLevels();
- final long mobileRx = mStats.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_RX_DATA,
- statsType);
- final long mobileTx = mStats.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_TX_DATA,
- statsType);
- final long mobileData = mobileRx + mobileTx;
+ private final UsageBasedPowerEstimator mActivePowerEstimator;
+ private final UsageBasedPowerEstimator[] mIdlePowerEstimators =
+ new UsageBasedPowerEstimator[NUM_SIGNAL_STRENGTH_LEVELS];
+ private final UsageBasedPowerEstimator mScanPowerEstimator;
- final long radioDataUptimeMs =
- mStats.getMobileRadioActiveTime(rawRealtimeUs, statsType) / 1000;
- final double mobilePps = (mobileData != 0 && radioDataUptimeMs != 0)
- ? (mobileData / (double) radioDataUptimeMs)
- : (((double) MOBILE_BPS) / 8 / 2048);
- return (MOBILE_POWER / mobilePps) / (60 * 60);
+ private static class PowerAndDuration {
+ public long durationMs;
+ public double powerMah;
+ public long totalAppDurationMs;
+ public long signalDurationMs;
+ public long noCoverageDurationMs;
}
public MobileRadioPowerCalculator(PowerProfile profile) {
- double temp =
+ // Power consumption when radio is active
+ double powerRadioActiveMa =
profile.getAveragePowerOrDefault(PowerProfile.POWER_RADIO_ACTIVE, -1);
- if (temp != -1) {
- mPowerRadioOn = temp;
- } else {
+ if (powerRadioActiveMa == -1) {
double sum = 0;
sum += profile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_RX);
- for (int i = 0; i < mPowerBins.length; i++) {
+ for (int i = 0; i < NUM_SIGNAL_STRENGTH_LEVELS; i++) {
sum += profile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_TX, i);
}
- mPowerRadioOn = sum / (mPowerBins.length + 1);
+ powerRadioActiveMa = sum / (NUM_SIGNAL_STRENGTH_LEVELS + 1);
}
- temp = profile.getAveragePowerOrDefault(PowerProfile.POWER_RADIO_ON, -1);
- if (temp != -1) {
- for (int i = 0; i < mPowerBins.length; i++) {
- mPowerBins[i] = profile.getAveragePower(PowerProfile.POWER_RADIO_ON, i);
+ mActivePowerEstimator = new UsageBasedPowerEstimator(powerRadioActiveMa);
+
+ // Power consumption when radio is on, but idle
+ if (profile.getAveragePowerOrDefault(PowerProfile.POWER_RADIO_ON, -1) != -1) {
+ for (int i = 0; i < NUM_SIGNAL_STRENGTH_LEVELS; i++) {
+ mIdlePowerEstimators[i] = new UsageBasedPowerEstimator(
+ profile.getAveragePower(PowerProfile.POWER_RADIO_ON, i));
}
} else {
double idle = profile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_IDLE);
- mPowerBins[0] = idle * 25 / 180;
- for (int i = 1; i < mPowerBins.length; i++) {
- mPowerBins[i] = Math.max(1, idle / 256);
+
+ // Magical calculations preserved for historical compatibility
+ mIdlePowerEstimators[0] = new UsageBasedPowerEstimator(idle * 25 / 180);
+ for (int i = 1; i < NUM_SIGNAL_STRENGTH_LEVELS; i++) {
+ mIdlePowerEstimators[i] = new UsageBasedPowerEstimator(Math.max(1, idle / 256));
}
}
- mPowerScan = profile.getAveragePowerOrDefault(PowerProfile.POWER_RADIO_SCANNING, 0);
+ mScanPowerEstimator = new UsageBasedPowerEstimator(
+ profile.getAveragePowerOrDefault(PowerProfile.POWER_RADIO_SCANNING, 0));
+ }
+
+ @Override
+ public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
+ long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query,
+ SparseArray<UserHandle> asUsers) {
+
+ PowerAndDuration total = new PowerAndDuration();
+
+ final double powerPerPacketMah = getMobilePowerPerPacket(batteryStats, rawRealtimeUs,
+ BatteryStats.STATS_SINCE_CHARGED);
+ final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders =
+ builder.getUidBatteryConsumerBuilders();
+ for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
+ final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
+ final BatteryStats.Uid uid = app.getBatteryStatsUid();
+ calculateApp(app, uid, powerPerPacketMah, total);
+ }
+
+ calculateRemaining(total, batteryStats, rawRealtimeUs);
+
+ if (total.powerMah != 0) {
+ builder.getOrCreateSystemBatteryConsumerBuilder(
+ SystemBatteryConsumer.DRAIN_TYPE_MOBILE_RADIO)
+ .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_MOBILE_RADIO,
+ total.durationMs)
+ .setConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO, total.powerMah);
+ }
+ }
+
+ private void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
+ double powerPerPacketMah, PowerAndDuration total) {
+ final long radioActiveDurationMs = calculateDuration(u, BatteryStats.STATS_SINCE_CHARGED);
+ total.totalAppDurationMs += radioActiveDurationMs;
+
+ final double powerMah = calculatePower(u, powerPerPacketMah, radioActiveDurationMs);
+
+ app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_MOBILE_RADIO,
+ radioActiveDurationMs)
+ .setConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO, powerMah);
}
@Override
public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
- mStats = batteryStats;
- super.calculate(sippers, batteryStats, rawRealtimeUs, rawUptimeUs, statsType, asUsers);
+ final double mobilePowerPerPacket = getMobilePowerPerPacket(batteryStats, rawRealtimeUs,
+ statsType);
+ PowerAndDuration total = new PowerAndDuration();
+ for (int i = sippers.size() - 1; i >= 0; i--) {
+ final BatterySipper app = sippers.get(i);
+ if (app.drainType == BatterySipper.DrainType.APP) {
+ final BatteryStats.Uid u = app.uidObj;
+ calculateApp(app, u, statsType, mobilePowerPerPacket, total);
+ }
+ }
BatterySipper radio = new BatterySipper(BatterySipper.DrainType.CELL, null, 0);
- calculateRemaining(radio, mStats, rawRealtimeUs, rawUptimeUs, statsType);
- radio.sumPower();
+ calculateRemaining(total, batteryStats, rawRealtimeUs);
+ if (total.powerMah != 0) {
+ if (total.signalDurationMs != 0) {
+ radio.noCoveragePercent =
+ total.noCoverageDurationMs * 100.0 / total.signalDurationMs;
+ }
+ radio.mobileActive = total.durationMs;
+ radio.mobileActiveCount = batteryStats.getMobileRadioActiveUnknownCount(statsType);
+ radio.mobileRadioPowerMah = total.powerMah;
+ radio.sumPower();
+ }
if (radio.totalPowerMah > 0) {
sippers.add(radio);
}
}
- @Override
- protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
- long rawUptimeUs, int statsType) {
+ private void calculateApp(BatterySipper app, BatteryStats.Uid u, int statsType,
+ double powerPerPacketMah, PowerAndDuration total) {
+ app.mobileActive = calculateDuration(u, statsType);
+ app.mobileRadioPowerMah = calculatePower(u, powerPerPacketMah, app.mobileActive);
+ total.totalAppDurationMs += app.mobileActive;
+
// Add cost of mobile traffic.
app.mobileRxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_RX_DATA,
statsType);
app.mobileTxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_TX_DATA,
statsType);
- app.mobileActive = u.getMobileRadioActiveTime(statsType) / 1000;
app.mobileActiveCount = u.getMobileRadioActiveCount(statsType);
app.mobileRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_RX_DATA,
statsType);
app.mobileTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_TX_DATA,
statsType);
- if (app.mobileActive > 0) {
- // We are tracking when the radio is up, so can use the active time to
- // determine power use.
- mTotalAppMobileActiveMs += app.mobileActive;
- app.mobileRadioPowerMah = (app.mobileActive * mPowerRadioOn) / (1000 * 60 * 60);
- } else {
- // We are not tracking when the radio is up, so must approximate power use
- // based on the number of packets.
- app.mobileRadioPowerMah = (app.mobileRxPackets + app.mobileTxPackets)
- * getMobilePowerPerPacket(rawRealtimeUs, statsType);
- }
if (DEBUG && app.mobileRadioPowerMah != 0) {
Log.d(TAG, "UID " + u.getUid() + ": mobile packets "
+ (app.mobileRxPackets + app.mobileTxPackets)
@@ -131,52 +179,80 @@
}
}
- private void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
- long rawUptimeUs, int statsType) {
- double power = 0;
+ private long calculateDuration(BatteryStats.Uid u, int statsType) {
+ return u.getMobileRadioActiveTime(statsType) / 1000;
+ }
+
+ private double calculatePower(BatteryStats.Uid u, double powerPerPacketMah,
+ long radioActiveDurationMs) {
+ if (radioActiveDurationMs > 0) {
+ // We are tracking when the radio is up, so can use the active time to
+ // determine power use.
+ return mActivePowerEstimator.calculatePower(radioActiveDurationMs);
+ } else {
+ // We are not tracking when the radio is up, so must approximate power use
+ // based on the number of packets.
+ final long mobileRxPackets = u.getNetworkActivityPackets(
+ BatteryStats.NETWORK_MOBILE_RX_DATA,
+ BatteryStats.STATS_SINCE_CHARGED);
+ final long mobileTxPackets = u.getNetworkActivityPackets(
+ BatteryStats.NETWORK_MOBILE_TX_DATA,
+ BatteryStats.STATS_SINCE_CHARGED);
+ return (mobileRxPackets + mobileTxPackets) * powerPerPacketMah;
+ }
+ }
+
+ private void calculateRemaining(MobileRadioPowerCalculator.PowerAndDuration total,
+ BatteryStats batteryStats, long rawRealtimeUs) {
long signalTimeMs = 0;
- long noCoverageTimeMs = 0;
- for (int i = 0; i < mPowerBins.length; i++) {
- long strengthTimeMs = stats.getPhoneSignalStrengthTime(i, rawRealtimeUs, statsType)
- / 1000;
- final double p = (strengthTimeMs * mPowerBins[i]) / (60 * 60 * 1000);
+ double powerMah = 0;
+ for (int i = 0; i < NUM_SIGNAL_STRENGTH_LEVELS; i++) {
+ long strengthTimeMs = batteryStats.getPhoneSignalStrengthTime(i, rawRealtimeUs,
+ BatteryStats.STATS_SINCE_CHARGED) / 1000;
+ final double p = mIdlePowerEstimators[i].calculatePower(strengthTimeMs);
if (DEBUG && p != 0) {
Log.d(TAG, "Cell strength #" + i + ": time=" + strengthTimeMs + " power="
+ formatCharge(p));
}
- power += p;
+ powerMah += p;
signalTimeMs += strengthTimeMs;
if (i == 0) {
- noCoverageTimeMs = strengthTimeMs;
+ total.noCoverageDurationMs = strengthTimeMs;
}
}
- final long scanningTimeMs = stats.getPhoneSignalScanningTime(rawRealtimeUs, statsType)
- / 1000;
- final double p = (scanningTimeMs * mPowerScan) / (60 * 60 * 1000);
+ final long scanningTimeMs = batteryStats.getPhoneSignalScanningTime(rawRealtimeUs,
+ BatteryStats.STATS_SINCE_CHARGED) / 1000;
+ final double p = mScanPowerEstimator.calculatePower(scanningTimeMs);
if (DEBUG && p != 0) {
Log.d(TAG, "Cell radio scanning: time=" + scanningTimeMs + " power=" + formatCharge(p));
}
- power += p;
- long radioActiveTimeMs = mStats.getMobileRadioActiveTime(rawRealtimeUs, statsType) / 1000;
- long remainingActiveTimeMs = radioActiveTimeMs - mTotalAppMobileActiveMs;
+ powerMah += p;
+ long radioActiveTimeMs = batteryStats.getMobileRadioActiveTime(rawRealtimeUs,
+ BatteryStats.STATS_SINCE_CHARGED) / 1000;
+ long remainingActiveTimeMs = radioActiveTimeMs - total.totalAppDurationMs;
if (remainingActiveTimeMs > 0) {
- power += (mPowerRadioOn * remainingActiveTimeMs) / (1000 * 60 * 60);
+ powerMah += mActivePowerEstimator.calculatePower(remainingActiveTimeMs);
}
-
- if (power != 0) {
- if (signalTimeMs != 0) {
- app.noCoveragePercent = noCoverageTimeMs * 100.0 / signalTimeMs;
- }
- app.mobileActive = remainingActiveTimeMs;
- app.mobileActiveCount = stats.getMobileRadioActiveUnknownCount(statsType);
- app.mobileRadioPowerMah = power;
- }
+ total.durationMs = radioActiveTimeMs;
+ total.powerMah = powerMah;
+ total.signalDurationMs = signalTimeMs;
}
- @Override
- public void reset() {
- mTotalAppMobileActiveMs = 0;
- mStats = null;
+ /**
+ * Return estimated power (in mAh) of sending or receiving a packet with the mobile radio.
+ */
+ private double getMobilePowerPerPacket(BatteryStats stats, long rawRealtimeUs, int statsType) {
+ final long radioDataUptimeMs =
+ stats.getMobileRadioActiveTime(rawRealtimeUs, statsType) / 1000;
+ final double mobilePower = mActivePowerEstimator.calculatePower(radioDataUptimeMs);
+
+ final long mobileRx = stats.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_RX_DATA,
+ statsType);
+ final long mobileTx = stats.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_TX_DATA,
+ statsType);
+ final long mobilePackets = mobileRx + mobileTx;
+
+ return mobilePackets != 0 ? mobilePower / mobilePackets : 0;
}
}
diff --git a/core/java/com/android/internal/os/SensorPowerCalculator.java b/core/java/com/android/internal/os/SensorPowerCalculator.java
index 9c8aafb..78c4fe2 100644
--- a/core/java/com/android/internal/os/SensorPowerCalculator.java
+++ b/core/java/com/android/internal/os/SensorPowerCalculator.java
@@ -17,81 +17,79 @@
import android.hardware.Sensor;
import android.hardware.SensorManager;
-import android.location.GnssSignalQuality;
+import android.os.BatteryConsumer;
import android.os.BatteryStats;
-import android.os.UserHandle;
+import android.os.BatteryUsageStatsQuery;
+import android.os.UidBatteryConsumer;
import android.util.SparseArray;
import java.util.List;
public class SensorPowerCalculator extends PowerCalculator {
- private final PowerProfile mPowerProfile;
- private final List<Sensor> mSensors;
- private double mGpsPower;
+ private final SparseArray<Sensor> mSensors;
- public SensorPowerCalculator(PowerProfile profile, SensorManager sensorManager) {
- mPowerProfile = profile;
- mSensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
+ public SensorPowerCalculator(SensorManager sensorManager) {
+ List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
+ mSensors = new SparseArray<>(sensors.size());
+ for (int i = 0; i < sensors.size(); i++) {
+ Sensor sensor = sensors.get(i);
+ mSensors.put(sensor.getHandle(), sensor);
+ }
}
@Override
- public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
- long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
- mGpsPower = getAverageGpsPower(batteryStats, rawRealtimeUs, statsType);
- super.calculate(sippers, batteryStats, rawRealtimeUs, rawUptimeUs, statsType, asUsers);
+ protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
+ long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
+ app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SENSORS,
+ calculateDuration(u, rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED))
+ .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SENSORS,
+ calculatePowerMah(u, rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED));
}
@Override
protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
long rawUptimeUs, int statsType) {
- // Process Sensor usage
+ app.sensorPowerMah = calculatePowerMah(u, rawRealtimeUs, statsType);
+ }
+
+ private long calculateDuration(BatteryStats.Uid u, long rawRealtimeUs, int statsType) {
+ long durationMs = 0;
final SparseArray<? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats();
final int NSE = sensorStats.size();
for (int ise = 0; ise < NSE; ise++) {
- final BatteryStats.Uid.Sensor sensor = sensorStats.valueAt(ise);
final int sensorHandle = sensorStats.keyAt(ise);
- final BatteryStats.Timer timer = sensor.getSensorTime();
- final long sensorTime = timer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000;
-
- switch (sensorHandle) {
- case BatteryStats.Uid.Sensor.GPS:
- app.gpsTimeMs = sensorTime;
- app.gpsPowerMah = (app.gpsTimeMs * mGpsPower) / (1000 * 60 * 60);
- break;
- default:
- final int sensorsCount = mSensors.size();
- for (int i = 0; i < sensorsCount; i++) {
- final Sensor s = mSensors.get(i);
- if (s.getHandle() == sensorHandle) {
- app.sensorPowerMah += (sensorTime * s.getPower()) / (1000 * 60 * 60);
- break;
- }
- }
- break;
+ if (sensorHandle == BatteryStats.Uid.Sensor.GPS) {
+ continue;
}
+
+ final BatteryStats.Uid.Sensor sensor = sensorStats.valueAt(ise);
+ final BatteryStats.Timer timer = sensor.getSensorTime();
+ durationMs += timer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000;
}
+ return durationMs;
}
- private double getAverageGpsPower(BatteryStats stats, long rawRealtimeUs,
- int statsType) {
- double averagePower =
- mPowerProfile.getAveragePowerOrDefault(PowerProfile.POWER_GPS_ON, -1);
- if (averagePower != -1) {
- return averagePower;
+ private double calculatePowerMah(BatteryStats.Uid u, long rawRealtimeUs, int statsType) {
+ double powerMah = 0;
+ final SparseArray<? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats();
+ final int count = sensorStats.size();
+ for (int ise = 0; ise < count; ise++) {
+ final int sensorHandle = sensorStats.keyAt(ise);
+ // TODO(b/178127364): remove BatteryStats.Uid.Sensor.GPS and references to it.
+ if (sensorHandle == BatteryStats.Uid.Sensor.GPS) {
+ continue;
+ }
+
+ final BatteryStats.Uid.Sensor sensor = sensorStats.valueAt(ise);
+ final BatteryStats.Timer timer = sensor.getSensorTime();
+ final long sensorTime = timer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000;
+ if (sensorTime != 0) {
+ Sensor s = mSensors.get(sensorHandle);
+ if (s != null) {
+ powerMah += (sensorTime * s.getPower()) / (1000 * 60 * 60);
+ }
+ }
}
- averagePower = 0;
- long totalTime = 0;
- double totalPower = 0;
- for (int i = 0; i < GnssSignalQuality.NUM_GNSS_SIGNAL_QUALITY_LEVELS; i++) {
- long timePerLevel = stats.getGpsSignalQualityTime(i, rawRealtimeUs, statsType);
- totalTime += timePerLevel;
- totalPower +=
- mPowerProfile.getAveragePower(PowerProfile.POWER_GPS_SIGNAL_QUALITY_BASED, i)
- * timePerLevel;
- }
- if (totalTime != 0) {
- averagePower = totalPower / totalTime;
- }
- return averagePower;
+ return powerMah;
}
}
diff --git a/core/java/com/android/internal/policy/IKeyguardService.aidl b/core/java/com/android/internal/policy/IKeyguardService.aidl
index 54f31f9..b01e4a8 100644
--- a/core/java/com/android/internal/policy/IKeyguardService.aidl
+++ b/core/java/com/android/internal/policy/IKeyguardService.aidl
@@ -42,26 +42,29 @@
/**
* Called when the device has started going to sleep.
*
- * @param why {@link #OFF_BECAUSE_OF_USER}, {@link #OFF_BECAUSE_OF_ADMIN},
- * or {@link #OFF_BECAUSE_OF_TIMEOUT}.
+ * @param pmSleepReason One of PowerManager.GO_TO_SLEEP_REASON_*, detailing the specific reason
+ * we're going to sleep, such as GO_TO_SLEEP_REASON_POWER_BUTTON or GO_TO_SLEEP_REASON_TIMEOUT.
*/
- void onStartedGoingToSleep(int reason);
+ void onStartedGoingToSleep(int pmSleepReason);
/**
* Called when the device has finished going to sleep.
*
- * @param why {@link #OFF_BECAUSE_OF_USER}, {@link #OFF_BECAUSE_OF_ADMIN},
- * or {@link #OFF_BECAUSE_OF_TIMEOUT}.
+ * @param pmSleepReason One of PowerManager.GO_TO_SLEEP_REASON_*, detailing the specific reason
+ * we're going to sleep, such as GO_TO_SLEEP_REASON_POWER_BUTTON or GO_TO_SLEEP_REASON_TIMEOUT.
* @param cameraGestureTriggered whether the camera gesture was triggered between
* {@link #onStartedGoingToSleep} and this method; if it's been
* triggered, we shouldn't lock the device.
*/
- void onFinishedGoingToSleep(int reason, boolean cameraGestureTriggered);
+ void onFinishedGoingToSleep(int pmSleepReason, boolean cameraGestureTriggered);
/**
* Called when the device has started waking up.
+
+ * @param pmWakeReason One of PowerManager.WAKE_REASON_*, detailing the reason we're waking up,
+ * such as WAKE_REASON_POWER_BUTTON or WAKE_REASON_GESTURE.
*/
- void onStartedWakingUp();
+ void onStartedWakingUp(int pmWakeReason);
/**
* Called when the device has finished waking up.
diff --git a/core/java/com/android/internal/textservice/ISpellCheckerService.aidl b/core/java/com/android/internal/textservice/ISpellCheckerService.aidl
index 6a25964..295107b 100644
--- a/core/java/com/android/internal/textservice/ISpellCheckerService.aidl
+++ b/core/java/com/android/internal/textservice/ISpellCheckerService.aidl
@@ -39,9 +39,11 @@
* {@link android.service.textservice.SpellCheckerService.Session#onGetSuggestionsMultiple(TextInfo[], int, boolean)} and
* {@link android.service.textservice.SpellCheckerService.Session#onGetSuggestions(TextInfo, int)}
* @param bundle bundle to be returned from {@link android.service.textservice.SpellCheckerService.Session#getBundle()}
+ * @param supportedAttributes supported attributes to be returned from {@link android.service.textservice.SpellCheckerService.Session#getSupportedAttributes()}
* @param callback IPC channel to return the result to the caller in an asynchronous manner
*/
void getISpellCheckerSession(
String locale, ISpellCheckerSessionListener listener, in Bundle bundle,
+ int supportedAttributes,
ISpellCheckerServiceCallback callback);
}
diff --git a/core/java/com/android/internal/textservice/ITextServicesManager.aidl b/core/java/com/android/internal/textservice/ITextServicesManager.aidl
index 8022949..dce67e7 100644
--- a/core/java/com/android/internal/textservice/ITextServicesManager.aidl
+++ b/core/java/com/android/internal/textservice/ITextServicesManager.aidl
@@ -34,7 +34,7 @@
boolean allowImplicitlySelectedSubtype);
oneway void getSpellCheckerService(int userId, String sciId, in String locale,
in ITextServicesSessionListener tsListener,
- in ISpellCheckerSessionListener scListener, in Bundle bundle);
+ in ISpellCheckerSessionListener scListener, in Bundle bundle, int supportedAttributes);
oneway void finishSpellCheckerService(int userId, in ISpellCheckerSessionListener listener);
boolean isSpellCheckerEnabled(int userId);
SpellCheckerInfo[] getEnabledSpellCheckers(int userId);
diff --git a/core/java/com/android/internal/textservice/OWNERS b/core/java/com/android/internal/textservice/OWNERS
new file mode 100644
index 0000000..0471e29
--- /dev/null
+++ b/core/java/com/android/internal/textservice/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 816455
+
+include /services/core/java/com/android/server/textservices/OWNERS
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 1fadfc5..b42404f 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -30,6 +30,7 @@
import com.android.internal.inputmethod.IInputMethodSubtypeResultCallback;
import com.android.internal.inputmethod.IInputMethodSubtypeListResultCallback;
import com.android.internal.inputmethod.IIntResultCallback;
+import com.android.internal.inputmethod.IVoidResultCallback;
/**
* Public interface to the global input method manager, used by all client
@@ -66,10 +67,11 @@
in IInputBindResultResultCallback inputBindResult);
void showInputMethodPickerFromClient(in IInputMethodClient client,
- int auxiliarySubtypeMode);
+ int auxiliarySubtypeMode, in IVoidResultCallback resultCallback);
void showInputMethodPickerFromSystem(in IInputMethodClient client, int auxiliarySubtypeMode,
- int displayId);
- void showInputMethodAndSubtypeEnablerFromClient(in IInputMethodClient client, String topId);
+ int displayId, in IVoidResultCallback resultCallback);
+ void showInputMethodAndSubtypeEnablerFromClient(in IInputMethodClient client, String topId,
+ in IVoidResultCallback resultCallback);
void isInputMethodPickerShownForTest(in IBooleanResultCallback resultCallback);
void getCurrentInputMethodSubtype(in IInputMethodSubtypeResultCallback resultCallback);
void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes);
@@ -78,7 +80,7 @@
void getInputMethodWindowVisibleHeight(IIntResultCallback resultCallback);
void reportActivityView(in IInputMethodClient parentClient, int childDisplayId,
- in float[] matrixValues);
+ in float[] matrixValues, in IVoidResultCallback resultCallback);
oneway void reportPerceptible(in IBinder windowToken, boolean perceptible);
/** Remove the IME surface. Requires INTERNAL_SYSTEM_WINDOW permission. */
diff --git a/core/jni/android_graphics_BLASTBufferQueue.cpp b/core/jni/android_graphics_BLASTBufferQueue.cpp
index 8d3faf4..b790056 100644
--- a/core/jni/android_graphics_BLASTBufferQueue.cpp
+++ b/core/jni/android_graphics_BLASTBufferQueue.cpp
@@ -68,7 +68,7 @@
};
static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring jName, jlong surfaceControl,
- jlong width, jlong height, jboolean enableTripleBuffering) {
+ jlong width, jlong height, jint format, jboolean enableTripleBuffering) {
String8 str8;
if (jName) {
const jchar* str16 = env->GetStringCritical(jName, nullptr);
@@ -81,7 +81,7 @@
std::string name = str8.string();
sp<BLASTBufferQueue> queue =
new BLASTBufferQueue(name, reinterpret_cast<SurfaceControl*>(surfaceControl), width,
- height, enableTripleBuffering);
+ height, format, enableTripleBuffering);
queue->incStrong((void*)nativeCreate);
return reinterpret_cast<jlong>(queue.get());
}
@@ -104,9 +104,10 @@
queue->setNextTransaction(transaction);
}
-static void nativeUpdate(JNIEnv*env, jclass clazz, jlong ptr, jlong surfaceControl, jlong width, jlong height) {
+static void nativeUpdate(JNIEnv* env, jclass clazz, jlong ptr, jlong surfaceControl, jlong width,
+ jlong height, jint format) {
sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
- queue->update(reinterpret_cast<SurfaceControl*>(surfaceControl), width, height);
+ queue->update(reinterpret_cast<SurfaceControl*>(surfaceControl), width, height, format);
}
static void nativeFlushShadowQueue(JNIEnv* env, jclass clazz, jlong ptr) {
@@ -139,11 +140,11 @@
static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
// clang-format off
- {"nativeCreate", "(Ljava/lang/String;JJJZ)J", (void*)nativeCreate},
+ {"nativeCreate", "(Ljava/lang/String;JJJIZ)J", (void*)nativeCreate},
{"nativeGetSurface", "(JZ)Landroid/view/Surface;", (void*)nativeGetSurface},
{"nativeDestroy", "(J)V", (void*)nativeDestroy},
{"nativeSetNextTransaction", "(JJ)V", (void*)nativeSetNextTransaction},
- {"nativeUpdate", "(JJJJ)V", (void*)nativeUpdate},
+ {"nativeUpdate", "(JJJJI)V", (void*)nativeUpdate},
{"nativeFlushShadowQueue", "(J)V", (void*)nativeFlushShadowQueue},
{"nativeMergeWithNextTransaction", "(JJJ)V", (void*)nativeMergeWithNextTransaction},
{"nativeSetTransactionCompleteCallback",
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 8dc56ed..94bd28a 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -1023,7 +1023,9 @@
audio_channel_mask_t nMask;
jint jMask;
- int gainIndex = nAudioPortConfig->gain.index;
+ int gainIndex = (nAudioPortConfig->config_mask & AUDIO_PORT_CONFIG_GAIN)
+ ? nAudioPortConfig->gain.index
+ : -1;
if (gainIndex >= 0) {
ALOGV("convertAudioPortConfigFromNative gain found with index %d mode %x",
gainIndex, nAudioPortConfig->gain.mode);
@@ -1120,7 +1122,9 @@
goto exit;
}
}
- nMask = nAudioPortConfig->channel_mask;
+ nMask = (nAudioPortConfig->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK)
+ ? nAudioPortConfig->channel_mask
+ : AUDIO_CONFIG_BASE_INITIALIZER.channel_mask;
if (useInMask) {
jMask = inChannelMaskFromNative(nMask);
ALOGV("convertAudioPortConfigFromNative IN mask java %x native %x", jMask, nMask);
@@ -1129,12 +1133,17 @@
ALOGV("convertAudioPortConfigFromNative OUT mask java %x native %x", jMask, nMask);
}
- *jAudioPortConfig = env->NewObject(clazz, methodID,
- jAudioPort,
- nAudioPortConfig->sample_rate,
- jMask,
- audioFormatFromNative(nAudioPortConfig->format),
- jAudioGainConfig);
+ *jAudioPortConfig =
+ env->NewObject(clazz, methodID, jAudioPort,
+ (nAudioPortConfig->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE)
+ ? nAudioPortConfig->sample_rate
+ : AUDIO_CONFIG_BASE_INITIALIZER.sample_rate,
+ jMask,
+ audioFormatFromNative(
+ (nAudioPortConfig->config_mask & AUDIO_PORT_CONFIG_FORMAT)
+ ? nAudioPortConfig->format
+ : AUDIO_CONFIG_BASE_INITIALIZER.format),
+ jAudioGainConfig);
if (*jAudioPortConfig == NULL) {
ALOGV("convertAudioPortConfigFromNative could not create new port config");
jStatus = (jint)AUDIO_JAVA_ERROR;
@@ -1936,6 +1945,7 @@
nAudioMix->mCbFlags = env->GetIntField(jAudioMix, gAudioMixFields.mCallbackFlags);
jobject jFormat = env->GetObjectField(jAudioMix, gAudioMixFields.mFormat);
+ nAudioMix->mFormat = AUDIO_CONFIG_INITIALIZER;
nAudioMix->mFormat.sample_rate = env->GetIntField(jFormat,
gAudioFormatFields.mSampleRate);
nAudioMix->mFormat.channel_mask = outChannelMaskToNative(env->GetIntField(jFormat,
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index b8e1807..7c670e1 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -1593,7 +1593,9 @@
}
static void nativeSetFocusedWindow(JNIEnv* env, jclass clazz, jlong transactionObj,
- jobject toTokenObj, jobject focusedTokenObj, jint displayId) {
+ jobject toTokenObj, jstring windowNameJstr,
+ jobject focusedTokenObj, jstring focusedWindowNameJstr,
+ jint displayId) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
if (toTokenObj == NULL) return;
@@ -1602,8 +1604,22 @@
if (focusedTokenObj != NULL) {
focusedToken = ibinderForJavaObject(env, focusedTokenObj);
}
- transaction->setFocusedWindow(toToken, focusedToken, systemTime(SYSTEM_TIME_MONOTONIC),
- displayId);
+
+ FocusRequest request;
+ request.token = toToken;
+ if (windowNameJstr != NULL) {
+ ScopedUtfChars windowName(env, windowNameJstr);
+ request.windowName = windowName.c_str();
+ }
+
+ request.focusedToken = focusedToken;
+ if (focusedWindowNameJstr != NULL) {
+ ScopedUtfChars focusedWindowName(env, focusedWindowNameJstr);
+ request.focusedWindowName = focusedWindowName.c_str();
+ }
+ request.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
+ request.displayId = displayId;
+ transaction->setFocusedWindow(request);
}
static void nativeSetFrameTimelineVsync(JNIEnv* env, jclass clazz, jlong transactionObj,
@@ -1865,7 +1881,7 @@
(void*)nativeGetHandle },
{"nativeSetFixedTransformHint", "(JJI)V",
(void*)nativeSetFixedTransformHint},
- {"nativeSetFocusedWindow", "(JLandroid/os/IBinder;Landroid/os/IBinder;I)V",
+ {"nativeSetFocusedWindow", "(JLandroid/os/IBinder;Ljava/lang/String;Landroid/os/IBinder;Ljava/lang/String;I)V",
(void*)nativeSetFocusedWindow},
{"nativeSetFrameTimelineVsync", "(JJ)V",
(void*)nativeSetFrameTimelineVsync },
diff --git a/core/proto/android/server/biometrics.proto b/core/proto/android/server/biometrics.proto
index 14b5c52..900235e 100644
--- a/core/proto/android/server/biometrics.proto
+++ b/core/proto/android/server/biometrics.proto
@@ -120,8 +120,8 @@
optional Modality modality = 2;
- // State of the sensor's scheduler. True if currently handling an operation, false if idle.
- optional bool is_busy = 3;
+ // State of the sensor's scheduler.
+ optional BiometricSchedulerProto scheduler = 3;
// User states for this sensor.
repeated UserStateProto user_states = 4;
@@ -136,4 +136,39 @@
// Number of fingerprints enrolled
optional int32 num_enrolled = 2;
+}
+
+// BiometricScheduler dump
+message BiometricSchedulerProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ // Operation currently being handled by the BiometricScheduler
+ optional ClientMonitorEnum current_operation = 1;
+
+ // Total number of operations that have been handled, not including the current one if one
+ // exists. Kept in FIFO order (most recent at the end of the array)
+ optional int32 total_operations = 2;
+
+ // A list of recent past operations in the order which they were handled
+ repeated ClientMonitorEnum recent_operations = 3;
+}
+
+// BaseClientMonitor subtypes
+enum ClientMonitorEnum {
+ CM_NONE = 0;
+ CM_UPDATE_ACTIVE_USER = 1;
+ CM_ENROLL = 2;
+ CM_AUTHENTICATE = 3;
+ CM_REMOVE = 4;
+ CM_GET_AUTHENTICATOR_ID = 5;
+ CM_ENUMERATE = 6;
+ CM_INTERNAL_CLEANUP = 7;
+ CM_SET_FEATURE = 8;
+ CM_GET_FEATURE = 9;
+ CM_GENERATE_CHALLENGE = 10;
+ CM_REVOKE_CHALLENGE = 11;
+ CM_RESET_LOCKOUT = 12;
+ CM_DETECT_INTERACTION = 13;
+ CM_INVALIDATION_REQUESTER = 14;
+ CM_INVALIDATE = 15;
}
\ No newline at end of file
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e1cd81c..f543373 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -321,6 +321,9 @@
<protected-broadcast android:name="android.net.nsd.STATE_CHANGED" />
+ <!-- For OMAPI -->
+ <protected-broadcast android:name="android.se.omapi.action.SECURE_ELEMENT_STATE_CHANGED" />
+
<protected-broadcast android:name="android.nfc.action.ADAPTER_STATE_CHANGED" />
<protected-broadcast android:name="android.nfc.action.ALWAYS_ON_STATE_CHANGED" />
<protected-broadcast android:name="android.nfc.action.PREFERRED_PAYMENT_CHANGED" />
@@ -686,6 +689,10 @@
<!-- Made protected in S (was added in R) -->
<protected-broadcast android:name="com.android.internal.intent.action.BUGREPORT_REQUESTED" />
+ <!-- Added in S -->
+ <protected-broadcast android:name="android.app.action.MANAGED_PROFILE_CREATED" />
+ <protected-broadcast android:name="android.app.action.PROVISIONED_MANAGED_DEVICE" />
+
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
<!-- ====================================================================== -->
@@ -1695,7 +1702,7 @@
<permission android:name="android.permission.MANAGE_IPSEC_TUNNELS"
android:protectionLevel="signature|appop" />
- <!-- @hide Allows apps to create and manage Test Networks.
+ <!-- @SystemApi @hide Allows apps to create and manage Test Networks.
<p>Granted only to shell. CTS tests will use
UiAutomation.AdoptShellPermissionIdentity() to gain access.
-->
@@ -3109,6 +3116,12 @@
<permission android:name="android.permission.RECOVERY"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi Allows an application to do certain operations needed for
+ resume on reboot feature.
+ @hide -->
+ <permission android:name="android.permission.BIND_RESUME_ON_REBOOT_SERVICE"
+ android:protectionLevel="signature" />
+
<!-- @SystemApi Allows an application to read system update info.
@hide -->
<permission android:name="android.permission.READ_SYSTEM_UPDATE_INFO"
@@ -4336,7 +4349,7 @@
<p>Not for use by third-party applications.
-->
<permission android:name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS"
- android:protectionLevel="signature|recents" />
+ android:protectionLevel="signature|privileged|recents" />
<uses-permission android:name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS" />
<!-- Allows an application to broadcast a notification that an application
@@ -5387,6 +5400,9 @@
on-device data -->
<attribution android:tag="OfflineLocationTimeZoneProviderService"
android:label="@string/offline_location_time_zone_detection_service_attribution"/>
+ <!-- Attribution for Gnss Time Update service. -->
+ <attribution android:tag="GnssTimeUpdateService"
+ android:label="@string/gnss_time_update_service"/>
<application android:process="system"
android:persistent="true"
diff --git a/packages/SystemUI/res/drawable/ic_camera_blocked.xml b/core/res/res/drawable/ic_camera_blocked.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_camera_blocked.xml
rename to core/res/res/drawable/ic_camera_blocked.xml
diff --git a/packages/SystemUI/res/drawable/ic_mic_blocked.xml b/core/res/res/drawable/ic_mic_blocked.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_mic_blocked.xml
rename to core/res/res/drawable/ic_mic_blocked.xml
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index bd017fd..eb45a6a 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Inkomender beller-ID"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Versteek uitgaande beller-ID"</string>
<string name="ColpMmi" msgid="4736462893284419302">"ID van gekoppelde lyn"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Beperking op ID van gekoppelde lyn"</string>
<string name="CfMmi" msgid="8390012691099787178">"Oproepaanstuur"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Sensorkennisgewingdiens"</string>
<string name="twilight_service" msgid="8964898045693187224">"Skemerdiens"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Tydsonebespeurder (geen konnektiwiteit nie)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Jou toestel sal uitgevee word"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Die administrasieprogram kan nie gebruik word nie. Jou toestel sal nou uitgevee word.\n\nKontak jou organisasie se administrateur as jy vrae het."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Druk is gedeaktiveer deur <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Jy kan nou jou hele skerm of \'n deel daarvan vergroot"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Skakel aan in Instellings"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Maak toe"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 4955e47..60157bd 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"የገቢ ደዋይID"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"የወጪ የደዋይ መታወቂያውን ደብቅ"</string>
<string name="ColpMmi" msgid="4736462893284419302">"የተገናኘ መስመር መታወቂያ"</string>
<string name="ColrMmi" msgid="5889782479745764278">"የተገናኘ መስመር መታወቂያ ገደብ"</string>
<string name="CfMmi" msgid="8390012691099787178">"ጥሪ ማስተላለፍ"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"የዳሳሽ ማሳወቂያ አገልግሎት"</string>
<string name="twilight_service" msgid="8964898045693187224">"የውጋገን አገልግሎት"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"የሰዓት ሰቅ አንባቢ (ግንኙነት የለም)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"የእርስዎ መሣሪያ ይደመሰሳል"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"የአስተዳዳሪ መተግበሪያ ስራ ላይ ሊውል አይችልም። የእርስዎን መሣሪያ አሁን ይደመሰሳል።\n\nጥያቄዎች ካለዎት የድርጅትዎን አስተዳዳሪ ያነጋግሩ።"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"ማተም በ<xliff:g id="OWNER_APP">%s</xliff:g> ተሰናክሏል።"</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"አሁን የተወሰነ ወይም ሁሉንም ማያ ገጽዎን ማጉላት ይችላሉ"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"በቅንብሮች ውስጥ ያብሩ"</string>
<string name="dismiss_action" msgid="1728820550388704784">"አሰናብት"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 770c304..4469117 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -61,8 +61,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"معرف المتصل الوارد"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"إخفاء إظهار رقم المتّصل للمكالمات الصادرة"</string>
<string name="ColpMmi" msgid="4736462893284419302">"معرّف الخط المتصل"</string>
<string name="ColrMmi" msgid="5889782479745764278">"تقييد معرّف الخط المتصل"</string>
<string name="CfMmi" msgid="8390012691099787178">"إعادة توجيه المكالمة"</string>
@@ -212,6 +211,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"خدمة إشعارات جهاز الاستشعار"</string>
<string name="twilight_service" msgid="8964898045693187224">"خدمة الغسق"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"أداة التعرّف على المنطقة الزمنية (ليس هناك حاجة للاتصال بالشبكة)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"سيتم محو بيانات جهازك."</string>
<string name="factory_reset_message" msgid="2657049595153992213">"تعذّر استخدام تطبيق المشرف. سيتم محو بيانات جهازك الآن.\n\nإذا كانت لديك أسئلة، اتصل بمشرف مؤسستك."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"تم إيقاف الطباعة بواسطة <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2340,4 +2341,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"يمكنك الآن تكبير الشاشة كلها أو جزء منها."</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"التفعيل من خلال \"الإعدادات\""</string>
<string name="dismiss_action" msgid="1728820550388704784">"إغلاق"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 2e23ee4..c413c33 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"অন্তৰ্গামী কলাৰ আইডি"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"বহিৰ্গামী কলাৰ আইডি লুকুৱাওক"</string>
<string name="ColpMmi" msgid="4736462893284419302">"সংযোজিত লাইন আইডি"</string>
<string name="ColrMmi" msgid="5889782479745764278">"সংযোজিত লাইন আইডিৰ সীমাবদ্ধতা"</string>
<string name="CfMmi" msgid="8390012691099787178">"কল ফৰৱাৰ্ডিং"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"ছেন্সৰ জাননী সেৱা"</string>
<string name="twilight_service" msgid="8964898045693187224">"Twilight সেৱা"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"সময় মণ্ডল চিনাক্তকাৰী (সংযোগ নাই)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"আপোনাৰ ডিভাইচৰ ডেটা মচা হ\'ব"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"এই প্ৰশাসক এপটো ব্যৱহাৰ কৰিব নোৱাৰি। এতিয়া আপোনাৰ ডিভাইচটোৰ ডেটা মচা হ\'ব।\n\nআপোনাৰ কিবা প্ৰশ্ন থাকিলে আপোনাৰ প্ৰতিষ্ঠানৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক।"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"প্ৰিণ্ট কৰা কাৰ্য <xliff:g id="OWNER_APP">%s</xliff:g>এ অক্ষম কৰি ৰাখিছে।"</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"আপুনি সকলো অথবা কেইখনমান স্ক্ৰীন বিবৰ্ধন কৰিব পাৰে"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"ছেটিঙত অন কৰক"</string>
<string name="dismiss_action" msgid="1728820550388704784">"অগ্ৰাহ্য কৰক"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 475fa7d..f7e4169 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Gələn çağrı kimliyi"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Gedən Zəng edən ID-sini gizlədin"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Qoşulmuş Xətt ID"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Qoşulmuş Xətt ID Məhdudluğu"</string>
<string name="CfMmi" msgid="8390012691099787178">"Zəng yönləndirmə"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Sensor Bildiriş Xidməti"</string>
<string name="twilight_service" msgid="8964898045693187224">"Alaqaranlıq Xidməti"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Saat Qurşağı Aşkarlayıcısı (Bağlantı yoxdur)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Cihazınız təmizlənəcəkdir"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Admin tətbiqini istifadə etmək mümkün deyil. Cihaz indi təmizlənəcək.\n\nSualınız varsa, təşkilatın admini ilə əlaqə saxlayın."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Çap <xliff:g id="OWNER_APP">%s</xliff:g> tərəfindən deaktiv edildi."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"İndi ekranı qismən və ya tam şəkildə böyüdə bilərsiniz"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Ayarlarda aktiv edin"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Qapadın"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 6378045..76a278a 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -58,8 +58,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Dolazni ID pozivaoca"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Sakrijte ID odlaznog pozivaoca"</string>
<string name="ColpMmi" msgid="4736462893284419302">"ID povezane linije"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Ograničenje ID-a povezane linije"</string>
<string name="CfMmi" msgid="8390012691099787178">"Preusmeravanje poziva"</string>
@@ -206,6 +205,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Usluga obaveštenja senzora"</string>
<string name="twilight_service" msgid="8964898045693187224">"Usluga Sumrak"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Detektor vremenske zone (nema internet veze)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Uređaj će biti obrisan"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Ne možete da koristite ovu aplikaciju za administratore. Uređaj će sada biti obrisan.\n\nAko imate pitanja, kontaktirajte administratora organizacije."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Štampanje je onemogućila aplikacija <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2238,4 +2239,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Možete da uvećate deo ekrana ili ceo ekran"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Uključite u Podešavanjima"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Odbaci"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 80c071c..deb9218 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -59,8 +59,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Ідэнтыфікатар АВН"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Схаваць ідэнтыфікатар абанента выходнага выкліку"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Ідэнтыфікатар падлучанай лініі"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Абмежаванне ідэнтыфікатара падлучанай лініі"</string>
<string name="CfMmi" msgid="8390012691099787178">"Пераадрасацыя выкліку"</string>
@@ -208,6 +207,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Служба апавяшчэнняў датчыка"</string>
<string name="twilight_service" msgid="8964898045693187224">"Служба Twilight"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Дэтэктар часавога пояса (няма падключэння)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Даныя вашай прылады будуць сцерты"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Немагчыма выкарыстоўваць праграму адміністравання. Звесткі на вашай прыладзе будуць выдалены.\n\nКалі ў вас ёсць пытанні, звярніцеся да адміністратара арганізацыі."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Друк адключаны ўладальнікам праграмы <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2272,4 +2273,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Цяпер можна павялічваць увесь экран ці яго частку."</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Уключыць у Наладах"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Адхіліць"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 6dd7b6a6..9ee0d99 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Идентификация на вх. обаждания"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Скриване на изходящия идентификатор на обаждащия се"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Идентификация на свързаната линия"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Ограничение за идентификацията на свързаната линия"</string>
<string name="CfMmi" msgid="8390012691099787178">"Пренасочване на повиквания"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Услуга за известия за сензорите"</string>
<string name="twilight_service" msgid="8964898045693187224">"Услуга Twilight"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Инструмент за установяване на часовата зона (няма връзка)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Данните на устройството ви ще бъдат изтрити"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Приложението за администриране не може да се използва. Сега данните на устройството ви ще бъдат изтрити.\n\nАко имате въпроси, свържете се с администратора на организацията си."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Отпечатването е деактивиранo от <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Можете да увеличите целия екран или част от него"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Включете от настройките"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Отхвърляне"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index ff9b003..3ce96c7 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"আগত কলার আইডি"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"আউটগোয়িং কলার আইডি আড়াল করুন"</string>
<string name="ColpMmi" msgid="4736462893284419302">"সংযুক্ত লাইন ID"</string>
<string name="ColrMmi" msgid="5889782479745764278">"সংযুক্ত লাইন ID-র বিধিনিষেধ"</string>
<string name="CfMmi" msgid="8390012691099787178">"কল ফরওয়ার্ড করা"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"সেন্সর বিজ্ঞপ্তি পরিষেবা"</string>
<string name="twilight_service" msgid="8964898045693187224">"গোধূলি পরিষেবা"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"টাইম জোন ডিটেক্টর (কানেকশন নেই)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"আপনার ডিভাইসটি মুছে ফেলা হবে"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"অ্যাডমিন অ্যাপটি ব্যবহার করা যাবে না। আপনার ডিভাইসে থাকা সবকিছু এখন মুছে ফেলা হবে।\n\nকোনও প্রশ্ন থাকলে আপনার প্রতিষ্ঠানের অ্যাডমিনের সাথে যোগাযোগ করুন।"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> প্রিন্টিং বন্ধ রেখেছে।"</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"এখন আপনি কিছু বা সবকটি স্ক্রিন বড় করে দেখতে পারেন"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"সেটিংস থেকে চালু করুন"</string>
<string name="dismiss_action" msgid="1728820550388704784">"বাতিল করুন"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index d2a4f7d..51ca3da 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -58,8 +58,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"ID dolaznog poziva"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Sakrij odlazni ID pozivaoca"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Identifikacija povezane linije"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Ograničenje identifikacije povezane linije"</string>
<string name="CfMmi" msgid="8390012691099787178">"Prosljeđivanje poziva"</string>
@@ -206,6 +205,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Usluga obavještavanja putem senzora"</string>
<string name="twilight_service" msgid="8964898045693187224">"Usluga Twilight"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Detektor vremenske zone (nije povezan)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Uređaj će biti izbrisan"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Nije moguće koristiti aplikaciju administratora. Potpuno će se izbrisati podaci na vašem uređaju.\n\nAko imate pitanja, obratite se administratoru svoje organizacije."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Štampanje je onemogućila aplikacija <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2238,4 +2239,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Sada možete uvećati dio ekrana ili cijeli ekran"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Uključite u Postavkama"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Odbaci"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 47be220..6d81104 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Identificador de trucada (trucada entrant)"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Amaga l\'identificador de trucada sortint"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Identificador de la línia connectada"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Restricció de l\'identificador de la línia connectada"</string>
<string name="CfMmi" msgid="8390012691099787178">"Desviació de trucades"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Servei de notificacions de sensor"</string>
<string name="twilight_service" msgid="8964898045693187224">"Servei Twilight"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Detector de zona horària (sense connectivitat)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"El contingut del dispositiu s\'esborrarà"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"No es pot utilitzar l\'aplicació d\'administració. S\'esborraran les dades del dispositiu.\n\nSi tens cap dubte, contacta amb l\'administrador de la teva organització."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ha desactivat la impressió."</string>
@@ -971,7 +972,7 @@
<string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="573341025292489065">"Permet que l\'aplicació modifiqui l\'historial del navegador o els marcadors de la tauleta. Això pot permetre que l\'aplicació esborri o modifiqui les dades del navegador. Nota: És possible que aquest permís no s\'apliqui a navegadors de tercers o a altres aplicacions amb capacitats de navegació web."</string>
<string name="permdesc_writeHistoryBookmarks" product="tv" msgid="88642768580408561">"Permet que l\'aplicació modifiqui l\'historial o les adreces d\'interès que hagis desat al dispositiu Android TV. D\'aquesta manera, l\'aplicació pot esborrar o modificar les dades del navegador. Nota: és possible que aquest permís no s\'apliqui a navegadors de tercers ni a altres aplicacions amb funcions de navegació web."</string>
<string name="permdesc_writeHistoryBookmarks" product="default" msgid="2245203087160913652">"Permet que l\'aplicació modifiqui l\'historial del navegador o els marcadors del telèfon. Això pot permetre que l\'aplicació esborri o modifiqui les dades del navegador. Nota: És possible que aquest permís no s\'apliqui a navegadors de tercers o a altres aplicacions amb capacitats de navegació web."</string>
- <string name="permlab_setAlarm" msgid="1158001610254173567">"configuració d\'una alarma"</string>
+ <string name="permlab_setAlarm" msgid="1158001610254173567">"configurar una alarma"</string>
<string name="permdesc_setAlarm" msgid="2185033720060109640">"Permet que l\'aplicació defineixi una alarma en una aplicació de despertador instal·lada. És possible que algunes aplicacions de despertador no incorporin aquesta funció."</string>
<string name="permlab_addVoicemail" msgid="4770245808840814471">"afegeix bústia de veu"</string>
<string name="permdesc_addVoicemail" msgid="5470312139820074324">"Permet que l\'aplicació afegeixi missatges a la safata d\'entrada de la bústia de veu."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Ara pots ampliar la pantalla completa o una part"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Activa a Configuració"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Ignora"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index e7e4cc9..00b607c 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -59,8 +59,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Příchozí ID volajícího"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Skrýt ID volajícího u odchozího hovoru"</string>
<string name="ColpMmi" msgid="4736462893284419302">"ID připojené linky"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Omezení ID připojené linky"</string>
<string name="CfMmi" msgid="8390012691099787178">"Přesměrování hovorů"</string>
@@ -208,6 +207,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Služba oznámení ze senzoru"</string>
<string name="twilight_service" msgid="8964898045693187224">"Služba detekce soumraku"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Detektor časového pásma (bez připojení)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Zařízení bude vymazáno"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Aplikaci pro správu nelze použít. Zařízení teď bude vymazáno.\n\nV případě dotazů vám pomůže administrátor organizace."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Aplikace <xliff:g id="OWNER_APP">%s</xliff:g> tisk zakazuje."</string>
@@ -2272,4 +2273,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Nyní můžete zvětšit celou obrazovku nebo její část"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Zapnout v Nastavení"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Zavřít"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 47416cf..6e9a7e7 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI-nummer"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Indgående opkalds-id"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Skjul Vis nummer (udgående opkald)"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Id for opkaldsmodtager"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Id for opkaldsmodtager er skjult"</string>
<string name="CfMmi" msgid="8390012691099787178">"Viderestilling af opkald"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Tjenesten Sensor Notification"</string>
<string name="twilight_service" msgid="8964898045693187224">"Tjenesten Twilight"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Tidszoneregistrering (ingen forbindelse)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Enheden slettes"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Administrationsappen kan ikke bruges. Enheden vil nu blive ryddet. \n\nKontakt din organisations administrator, hvis du har spørgsmål."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Udskrivning er deaktiveret af <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2206,4 +2207,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Du kan nu forstørre dele af eller hele skærmen"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Aktivér i Indstillinger"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Luk"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 54e9dfd..82123d8 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -149,8 +149,7 @@
<string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Nur WLAN"</string>
<!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
<skip />
- <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
- <skip />
+ <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> SIM-übergreifende Anrufe"</string>
<string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nicht weitergeleitet"</string>
<string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
<string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g><xliff:g id="DIALING_NUMBER">{1}</xliff:g> nach <xliff:g id="TIME_DELAY">{2}</xliff:g> Sekunden."</string>
@@ -205,6 +204,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Sensor Notification Service"</string>
<string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Zeitzonen-Erkennung (keine Verbindung)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Die Daten auf deinem Gerät werden gelöscht."</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Die Admin-App kann nicht verwendet werden. Die Daten auf deinem Gerät werden nun gelöscht.\n\nBitte wende dich bei Fragen an den Administrator deiner Organisation."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Drucken wurde von <xliff:g id="OWNER_APP">%s</xliff:g> deaktiviert."</string>
@@ -2205,4 +2206,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Du kannst das Display teilweise oder ganz vergrößern"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"In den Einstellungen aktivieren"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Schließen"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index b759be6..614fc95 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Εισερχόμενη αναγνώριση κλήσης"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Απόκρυψη εξερχόμενης αναγνώρισης κλήσης"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Αναγνωριστικό συνδεδεμένης γραμμής"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Περιορισμός αναγνωριστικού συνδεδεμένης πρόσβασης"</string>
<string name="CfMmi" msgid="8390012691099787178">"Προώθηση κλήσεων"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Υπηρεσία ειδοποίησης αισθητήρα"</string>
<string name="twilight_service" msgid="8964898045693187224">"Υπηρεσία Twilight"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Εντοπισμός ζώνης ώρας (χωρίς συνδεσιμότητα)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Η συσκευή σας θα διαγραφεί"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Δεν είναι δυνατή η χρήση της εφαρμογής διαχειριστή. Η συσκευή σας θα διαγραφεί.\n\nΕάν έχετε ερωτήσεις, επικοινωνήστε με τον διαχειριστή του οργανισμού σας."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Η εκτύπωση απενεργοποιήθηκε από τον χρήστη <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Μεγεθύνετε μέρος ή ολόκληρη την οθόνη σας"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Ενεργοποίηση στις Ρυθμίσεις"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Παράβλεψη"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 7c7c178..10ec8d0 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Incoming Caller ID"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Hide outgoing caller ID"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Connected Line ID"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Connected Line ID Restriction"</string>
<string name="CfMmi" msgid="8390012691099787178">"Call forwarding"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Sensor Notification Service"</string>
<string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Time zone detector (no connectivity)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organisation\'s admin."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"You can now magnify some or all of your screen"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Turn on in settings"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Dismiss"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 0cbbb01..bb7cd12 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Incoming Caller ID"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Hide outgoing caller ID"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Connected Line ID"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Connected Line ID Restriction"</string>
<string name="CfMmi" msgid="8390012691099787178">"Call forwarding"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Sensor Notification Service"</string>
<string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Time zone detector (no connectivity)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organisation\'s admin."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"You can now magnify some or all of your screen"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Turn on in settings"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Dismiss"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index e923d65..14c0a32 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Incoming Caller ID"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Hide outgoing caller ID"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Connected Line ID"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Connected Line ID Restriction"</string>
<string name="CfMmi" msgid="8390012691099787178">"Call forwarding"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Sensor Notification Service"</string>
<string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Time zone detector (no connectivity)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organisation\'s admin."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"You can now magnify some or all of your screen"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Turn on in settings"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Dismiss"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 6e17242..5b6be71 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Incoming Caller ID"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Hide outgoing caller ID"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Connected Line ID"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Connected Line ID Restriction"</string>
<string name="CfMmi" msgid="8390012691099787178">"Call forwarding"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Sensor Notification Service"</string>
<string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Time zone detector (no connectivity)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organisation\'s admin."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"You can now magnify some or all of your screen"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Turn on in settings"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Dismiss"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 759fe01..b39bf9c 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Incoming Caller ID"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Hide Outgoing Caller ID"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Connected Line ID"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Connected Line ID Restriction"</string>
<string name="CfMmi" msgid="8390012691099787178">"Call forwarding"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Sensor Notification Service"</string>
<string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Time Zone Detector (No connectivity)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organization\'s admin."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"You can now magnify some or all of your screen"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Turn on in Settings"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Dismiss"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 64bc3d1..d47430e 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Identificador de llamadas entrantes"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Ocultar identificador de llamadas salientes"</string>
<string name="ColpMmi" msgid="4736462893284419302">"ID de línea conectada"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Restricción de ID de línea conectada"</string>
<string name="CfMmi" msgid="8390012691099787178">"Desvío de llamadas"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Servicio de notificaciones del sensor"</string>
<string name="twilight_service" msgid="8964898045693187224">"Servicio de Twilight"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Detector de zona horaria (sin conexión)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Se borrarán los datos del dispositivo"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"No se puede usar la app de administrador. Ahora se borrará tu dispositivo.\n\nSi tienes preguntas, comunícate con el administrador de tu organización."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> inhabilitó la impresión."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Puedes ampliar toda tu pantalla o parte de ella"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Activar en Configuración"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Descartar"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 08555e8..e84fd00 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"ID de emisor de llamada entrante"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Ocultar ID de las llamadas salientes"</string>
<string name="ColpMmi" msgid="4736462893284419302">"ID de línea conectada"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Restricción de ID de línea conectada"</string>
<string name="CfMmi" msgid="8390012691099787178">"Desvío de llamadas"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Servicio de notificación de sensor"</string>
<string name="twilight_service" msgid="8964898045693187224">"Servicio de Twilight"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Detector de zona horaria (sin conexión)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Tu dispositivo se borrará"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"No se puede utilizar la aplicación de administración. Se borrarán todos los datos del dispositivo.\n\nSi tienes alguna pregunta, ponte en contacto con el administrador de tu organización."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ha inhabilitado la impresión."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Ahora puedes ampliar toda la pantalla o una parte"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Activar en Ajustes"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Cerrar"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 4818589..f7d053d 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Sissetuleva kõne helistaja ID"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Väljamineva helistaja ID peitmine"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Ühendatud liini ID"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Ühendatud liini ID piiramine"</string>
<string name="CfMmi" msgid="8390012691099787178">"Kõnede suunamine"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Anduri märguande teenus"</string>
<string name="twilight_service" msgid="8964898045693187224">"Teenus Twilight"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Ajavööndi tuvastaja (ühenduvus puudub)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Seade kustutatakse"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Administraatori rakendust ei saa kasutada. Teie seade tühjendatakse nüüd.\n\nKui teil on küsimusi, võtke ühendust organisatsiooni administraatoriga."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Rakendus <xliff:g id="OWNER_APP">%s</xliff:g> on printimise keelanud."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Nüüd saab suurendada kogu ekraanikuva või osa sellest"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Lülitage sisse menüüs Seaded"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Loobu"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 39fc77c..b22a777 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI zk."</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Sarrerako deien identifikazio-zerbitzua"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Ezkutatu irteerako deitzailearen IDa"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Konektatutako linearen IDa"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Konektatutako linearen ID murriztapena"</string>
<string name="CfMmi" msgid="8390012691099787178">"Dei-desbideratzea"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Sentsorearen jakinarazpen-zerbitzua"</string>
<string name="twilight_service" msgid="8964898045693187224">"Ilunabarreko zerbitzua"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Ordu-zonaren hautemailea (ez zaude konektatuta sarera)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Gailuko datuak ezabatu egingo dira"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Ezin da erabili administratzeko aplikazioa. Ezabatu egingo da gailuko eduki guztia.\n\nZalantzarik baduzu, jarri erakundeko administratzailearekin harremanetan."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> aplikazioak desgaitu egin du inprimatzeko aukera."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Orain, pantaila osoa edo haren zati bat handi dezakezu"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Aktibatu ezarpenetan"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Baztertu"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 935d679..084250e 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"شناسه تماسگیرنده ورودی"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"پنهان کردن شناسه تماسگیرنده خروجی"</string>
<string name="ColpMmi" msgid="4736462893284419302">"شناسه خط متصل"</string>
<string name="ColrMmi" msgid="5889782479745764278">"محدودیت شناسه خط متصل"</string>
<string name="CfMmi" msgid="8390012691099787178">"هدایت تماس"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"سرویس اعلان حسگر"</string>
<string name="twilight_service" msgid="8964898045693187224">"سرویس Twilight"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"شناساگر منطقه زمانی (بدون اتصال)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"دستگاهتان پاک خواهد شد"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"برنامه سرپرست سیستم را نمیتوان استفاده کرد. دستگاه شما در این لحظه پاک میشود.\n\nاگر سؤالی دارید، با سرپرست سیستم سازمانتان تماس بگیرید."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> چاپ کردن را غیرفعال کرده است."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"اکنون میتوانید بخشی از صفحه یا کل آن را درشت کنید"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"روشن کردن در «تنظیمات»"</string>
<string name="dismiss_action" msgid="1728820550388704784">"رد شدن"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 09f289a..159e1b4 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI-koodi"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Soittajan tunnus"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Piilota soittajan tunnus (lähtevät puhelut)"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Yhteyslinjan tunnus"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Yhteyslinjan tunnuksen rajoitus"</string>
<string name="CfMmi" msgid="8390012691099787178">"Soitonsiirto"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Anturin ilmoituspalvelu"</string>
<string name="twilight_service" msgid="8964898045693187224">"Twilight-palvelu"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Aikavyöhykkeen tunnistin (ei yhteyttä)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Laitteen tiedot poistetaan"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Hallintasovellusta ei voi käyttää. Laitteen tiedot pyyhitään.\n\nPyydä ohjeita järjestelmänvalvojaltasi."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> on poistanut tulostuksen käytöstä."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Voit nyt suurentaa näytön osittain tai kokonaan"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Laita päälle asetuksista"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Hylkää"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 6bedfca..fded10d 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"Code IIEM"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Numéro de l\'appelant (entrant)"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Masquer l\'identifiant de l\'appelant sortant"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Identifiant de la ligne connectée"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Restriction d\'identifiant de la ligne connectée"</string>
<string name="CfMmi" msgid="8390012691099787178">"Transfert d\'appel"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Service de notification de capteur"</string>
<string name="twilight_service" msgid="8964898045693187224">"Service de crépuscule"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Détecteur de fuseau horaire (aucune connectivité)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Le contenu de votre appareil sera effacé"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Impossible d\'utiliser l\'application d\'administration. Les données de votre appareil vont maintenant être effacées.\n\nSi vous avez des questions, communiquez avec l\'administrateur de votre organisation."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Impression désactivée par <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Vous pouvez agrandir une partie ou la totalité de votre écran"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Activer dans les paramètres"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Fermer"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index d8edc5d..b6eade2 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"Code IMEI"</string>
<string name="meid" msgid="3291227361605924674">"Code MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Numéro de l\'appelant (entrant)"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Masquer le numéro de l\'appelant (appels sortants)"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Identifiant de la ligne connectée"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Restriction d\'identifiant de la ligne connectée"</string>
<string name="CfMmi" msgid="8390012691099787178">"Transfert d\'appel"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Service de notification du capteur"</string>
<string name="twilight_service" msgid="8964898045693187224">"Service Twilight"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Outil de détection du fuseau horaire (aucune connectivité)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Les données de votre appareil vont être effacées"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Impossible d\'utiliser l\'application d\'administration. Les données de votre appareil vont maintenant être effacées.\n\nSi vous avez des questions, contactez l\'administrateur de votre organisation."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Impression désactivée par <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Vous pouvez agrandir tout ou partie de l\'écran"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Activer dans les paramètres"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Fermer"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 76ab6ab..04b4236 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Identificador de chamada entrante"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Ocultar identificador de chamada saínte"</string>
<string name="ColpMmi" msgid="4736462893284419302">"ID de liña conectada"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Restrición de ID de liña conectada"</string>
<string name="CfMmi" msgid="8390012691099787178">"Desvío de chamadas"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Servizo de notificacións dos sensores"</string>
<string name="twilight_service" msgid="8964898045693187224">"Servizo Twilight"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Detector de fuso horario (non require conexión)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Borrarase o teu dispositivo"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Non se pode utilizar a aplicación de administración. Borrarase o teu dispositivo.\n\nSe tes preguntas, contacta co administrador da organización."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> desactivou a impresión."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Agora podes ampliar toda a pantalla ou parte dela"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Activar en Configuración"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Ignorar"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index a591d31..7bab2ad 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"આવનાર કૉલર ID"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"આઉટગોઇંગ કૉલર ID છુપાવો"</string>
<string name="ColpMmi" msgid="4736462893284419302">"કનેક્ટ કરેલ લાઇન ID"</string>
<string name="ColrMmi" msgid="5889782479745764278">"કનેક્ટ કરેલ લાઇન ID પ્રતિબંધ"</string>
<string name="CfMmi" msgid="8390012691099787178">"કૉલ ફોર્વર્ડિંગ"</string>
@@ -149,8 +148,7 @@
<string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"ફક્ત વાઇ-ફાઇ"</string>
<!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
<skip />
- <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
- <skip />
+ <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> ક્રૉસ સિમ કૉલિંગ"</string>
<string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ફોરવર્ડ કર્યો નથી"</string>
<string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
<string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="TIME_DELAY">{2}</xliff:g> સેકન્ડ પછી <xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
@@ -205,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"સેન્સર નોટિફિકેશન સેવા"</string>
<string name="twilight_service" msgid="8964898045693187224">"ટ્વાઇલાઇટ સેવા"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"સમય ઝોન શોધવાની સુવિધા (કનેક્ટિવિટી જરૂરી નથી)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"તમારું ઉપકરણ કાઢી નાખવામાં આવશે"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"વ્યવસ્થાપક ઍપનો ઉપયોગ કરી શકાશે નહીં. તમારું ઉપકરણ હવે કાઢી નાખવામાં આવશે.\n\nજો તમને પ્રશ્નો હોય, તો તમારી સંસ્થાના વ્યવસ્થાપકનો સંપર્ક કરો."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> દ્વારા પ્રિન્ટ કરવાનું બંધ કરાયું છે."</string>
@@ -2205,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"હવે તમે તમારી કેટલીક કે આખી સ્ક્રીનને મોટી કરી શકો છો"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"સેટિંગમાં ચાલુ કરો"</string>
<string name="dismiss_action" msgid="1728820550388704784">"છોડી દો"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index a094117..dbdfd4a 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"आईएमईआई"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"इनकमिंग कॉलर आईडी"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"आउटगोइंग कॉल करने पर अपना कॉलर आईडी छिपाएं"</string>
<string name="ColpMmi" msgid="4736462893284419302">"कनेक्ट किया गया लाइन आईडी"</string>
<string name="ColrMmi" msgid="5889782479745764278">"कनेक्ट किया गया लाइन आईडी प्रतिबंध"</string>
<string name="CfMmi" msgid="8390012691099787178">"कॉल आगे भेजना"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"सेंसर से जुड़ी सूचना सेवा"</string>
<string name="twilight_service" msgid="8964898045693187224">"ट्वाइलाइट समय बताने वाली सेवा"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"समय क्षेत्र का पता लगाने वाली सुविधा (ऑफ़लाइन होने पर)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"आपके डिवाइस को मिटा दिया जाएगा"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"एडमिन ऐप्लिकेशन का इस्तेमाल नहीं किया जा सकता. आपके डिवाइस पर मौजूद डेटा अब मिटा दिया जाएगा.\n\nअगर आप कुछ पूछना चाहते हैं तो, अपने संगठन के एडमिन से संपर्क करें."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ने प्रिंटिंग सुविधा बंद कर दी है."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"अब अपनी पूरी स्क्रीन या कुछ हिस्से को ज़ूम करके देख सकते हैं"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"सेटिंग में जाकर, इस सुविधा को चालू करें"</string>
<string name="dismiss_action" msgid="1728820550388704784">"खारिज करें"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index aebab8c..56f3978 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -58,8 +58,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"ID dolaznog pozivatelja"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Sakrivanje ID-ja pozivatelja za odlazne pozive"</string>
<string name="ColpMmi" msgid="4736462893284419302">"ID povezane linije"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Ograničenje ID-a povezane linije"</string>
<string name="CfMmi" msgid="8390012691099787178">"Preusmjeravanje poziva"</string>
@@ -206,6 +205,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Usluga Obavijesti senzora"</string>
<string name="twilight_service" msgid="8964898045693187224">"Usluga Sumrak"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Detektor vremenske zone (nije povezan)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Uređaj će se izbrisati"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Administratorska aplikacija ne može se upotrebljavati. Uređaj će se izbrisati.\n\nAko imate pitanja, obratite se administratoru organizacije."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Ispis je onemogućila aplikacija <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2238,4 +2239,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Sad možete povećati dio zaslona ili cijeli zaslon"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Uključite u Postavkama"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Odbaci"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index efdf842..96997c0 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Beérkező hívóazonosító"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Kimenő hívásazonosító elrejtve"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Összekapcsolt sorazonosító"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Összekapcsolt sorazonosító korlátozása"</string>
<string name="CfMmi" msgid="8390012691099787178">"Hívásátirányítás"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Szenzoros értesítési szolgáltatás"</string>
<string name="twilight_service" msgid="8964898045693187224">"Twilight szolgáltatás"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Időzóna-felismerő (Offline)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"A rendszer törölni fogja eszközét"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"A rendszergazdai alkalmazás nem használható. A rendszer most törli az eszközt.\n\nKérdéseivel forduljon szervezete rendszergazdájához."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"A(z) <xliff:g id="OWNER_APP">%s</xliff:g> letiltotta a nyomtatást."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Ezután nagyíthatja a képernyőt vagy egy részét"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Bekapcsolás a Beállításokban"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Elvetés"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 29803b8..996454a 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Մուտքային զանգողի ID"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Թաքցնե՞լ զանգողի ID-ն"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Կապված տողի ID"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Կապված տողի ID-ի սահմանափակում"</string>
<string name="CfMmi" msgid="8390012691099787178">"Զանգի վերահասցեավորում"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Տվիչների ծանուցումների մշակման ծառայություն"</string>
<string name="twilight_service" msgid="8964898045693187224">"Մթնշաղի սկիզբը որոշող ծառայություն"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Ժամային գոտու դետեկտոր (աշխատում է առանց ինտերնետի)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Ձեր սարքը ջնջվելու է"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Հնարավոր չէ օգտագործել ադմինիստրատորի հավելվածը։ Ձեր սարքից բոլոր տվյալները կջնջվեն։\n\nՀարցեր ունենալու դեպքում դիմեք ձեր կազմակերպության ադմինիստրատորին։"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Տպումն անջատված է <xliff:g id="OWNER_APP">%s</xliff:g> հավելվածի կողմից։"</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Այժմ կարող եք խոշորացնել ամբողջ էկրանը կամ դրա մի մասը"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Միացնել կարգավորումներում"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Փակել"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 510621b..bb91a6c 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Nomor Penelepon Masuk"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Menyembunyikan ID Penelepon untuk Panggilan Keluar"</string>
<string name="ColpMmi" msgid="4736462893284419302">"ID Saluran yang Tersambung"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Batasan ID Saluran yang Tersambung"</string>
<string name="CfMmi" msgid="8390012691099787178">"Penerusan panggilan"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Layanan Notifikasi Sensor"</string>
<string name="twilight_service" msgid="8964898045693187224">"Layanan Twilight"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Pendeteksi Zona Waktu (Tidak ada konektivitas)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Perangkat akan dihapus"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Aplikasi admin tidak dapat digunakan. Perangkat Anda kini akan dihapus.\n\nJika ada pertanyaan, hubungi admin organisasi."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Fitur pencetakan dinonaktifkan oleh <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Anda bisa memperbesar sebagian atau seluruh layar"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Aktifkan di Setelan"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Tutup"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 802feeeb..ec11ad2 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Númerabirting innhringinga"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Fela númerabirtingu úthringinga"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Auðkenni tengdrar línu"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Auðkennistakmörkun tengdrar línu"</string>
<string name="CfMmi" msgid="8390012691099787178">"Símtalsflutningur"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Tilkynningaþjónusta nema"</string>
<string name="twilight_service" msgid="8964898045693187224">"Ljósaskiptaþjónusta"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Tímabeltisgreinir (engin tenging)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Tækið verður hreinsað"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Ekki er hægt að nota stjórnunarforritið. Tækinu verður eytt.\n\nEf spurningar vakna skaltu hafa samband við kerfisstjóra fyrirtækisins."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> lokaði á prentun."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Nú geturðu stækkað allan skjáinn eða hluta hans"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Kveikja á í stillingum"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Hunsa"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 2c01776..df35881 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"ID chiamante in entrata"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Nascondi ID chiamante in uscita"</string>
<string name="ColpMmi" msgid="4736462893284419302">"ID linea connessa"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Limitazione ID linea connessa"</string>
<string name="CfMmi" msgid="8390012691099787178">"Deviazione chiamate"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Servizio di notifica dei sensori"</string>
<string name="twilight_service" msgid="8964898045693187224">"Servizio Twilight"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Rilevatore di fuso orario (connessione a Internet non necessaria)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Il dispositivo verrà resettato"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Impossibile usare l\'app di amministrazione. Il dispositivo verrà resettato.\n\nPer eventuali domande, contatta l\'amministratore della tua organizzazione."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Stampa disattivata da <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Puoi ingrandire lo schermo in parte o per intero"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Attiva nelle Impostazioni"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Ignora"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 2bdabc8..f80750a 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -59,8 +59,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"זיהוי מתקשר של שיחה נכנסת"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"הסתרת זיהוי מתקשר בשיחה יוצאת"</string>
<string name="ColpMmi" msgid="4736462893284419302">"מזהה של קו מחובר"</string>
<string name="ColrMmi" msgid="5889782479745764278">"הגבלה של מזהה קו מחובר"</string>
<string name="CfMmi" msgid="8390012691099787178">"העברת שיחות"</string>
@@ -151,8 +150,7 @@
<string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Wi-Fi בלבד"</string>
<!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
<skip />
- <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
- <skip />
+ <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"העברת שיחות בין כרטיסי SIM של <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ללא העברה"</string>
<string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
<string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> כעבור <xliff:g id="TIME_DELAY">{2}</xliff:g> שניות"</string>
@@ -209,6 +207,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"שירות להתראות מחיישנים"</string>
<string name="twilight_service" msgid="8964898045693187224">"שירות דמדומים"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"מזהה אזור זמן (ללא צורך בקישוריות)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"תתבצע מחיקה של המכשיר"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"לא ניתן להשתמש באפליקציה של מנהל המערכת.\n\nאם יש לך שאלות, יש ליצור קשר עם מנהל המערכת של הארגון."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"ההדפסה הושבתה על ידי <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2273,4 +2273,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"עכשיו אפשר להגדיל את המסך או חלקים ממנו"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"הפעלה בהגדרות"</string>
<string name="dismiss_action" msgid="1728820550388704784">"סגירה"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index cf493c0..04a0058 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"着信時の発信者番号"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"発信者番号を非通知にする"</string>
<string name="ColpMmi" msgid="4736462893284419302">"接続回線ID"</string>
<string name="ColrMmi" msgid="5889782479745764278">"接続回線IDの制限"</string>
<string name="CfMmi" msgid="8390012691099787178">"着信転送"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"センサー通知サービス"</string>
<string name="twilight_service" msgid="8964898045693187224">"トワイライト サービス"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Time Zone Detector(未接続)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"デバイスのデータが消去されます"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"管理アプリを使用できません。デバイスのデータはこれから消去されます。\n\nご不明な点がある場合は、組織の管理者にお問い合わせください。"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"「<xliff:g id="OWNER_APP">%s</xliff:g>」により印刷は無効にされています。"</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"画面の一部または全体を拡大できるようになりました"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"[設定] で ON にする"</string>
<string name="dismiss_action" msgid="1728820550388704784">"閉じる"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 9de08bc..6a128ab 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"შემომავალი ზარის აბონენტის ID"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"გამავალი აბონენტის ID-ის დამალვა"</string>
<string name="ColpMmi" msgid="4736462893284419302">"დაუკავშირდა Line ID-ს"</string>
<string name="ColrMmi" msgid="5889782479745764278">"დაუკავშირდა Line ID Restriction-ს"</string>
<string name="CfMmi" msgid="8390012691099787178">"ზარის გადამისამართება"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"სენსორის შეტყობინების სერვისი"</string>
<string name="twilight_service" msgid="8964898045693187224">"Twilight სერვისი"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"სასაათო სარტყლის დეტექტორი (კავშირის გარეშე)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"თქვენი მოწყობილობა წაიშლება"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"ადმინისტრატორის აპის გამოყენება ვერ მოხერხდება. თქვენი მოწყობილობა ახლა ამოიშლება.\n\nთუ შეკითხვები გაქვთ, დაუკავშირდით თქვენი ორგანიზაციის ადმინისტრატორს."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"ბეჭდვა გათიშულია <xliff:g id="OWNER_APP">%s</xliff:g>-ის მიერ."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"ახლა შეგიძლიათ, გაადიდოთ ეკრანი ან მისი ნაწილი"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"ჩართვა პარამეტრებში"</string>
<string name="dismiss_action" msgid="1728820550388704784">"უარყოფა"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index f38be01..8000fc4 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI (Халықаралық мобильдік құрылғы анықтағышы)"</string>
<string name="meid" msgid="3291227361605924674">"MEID (ұялы құрылғы анықтағыш)"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Келген қоңырау шалушының жеке анықтағышы"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Шығыс қоңыраулары үшін қоңырау шалушының идентификаторын жасыру"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Қосылған желі идентификаторы"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Қосылған желі идентификаторын шектеу"</string>
<string name="CfMmi" msgid="8390012691099787178">"Қоңырауды басқа нөмірге бағыттау"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Датчик хабарландыруы қызметі"</string>
<string name="twilight_service" msgid="8964898045693187224">"Twilight қызметі"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Уақыт белдеуін анықтағыш (қосылу мүмкіндігі жоқ)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Құрылғыңыздағы деректер өшіріледі"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Әкімші қолданбасын пайдалану мүмкін емес. Қазір құрылғыдағы деректер өшіріледі\n\nСұрақтарыңыз болса, ұйым әкімшісіне хабарласыңыз."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Басып шығаруды <xliff:g id="OWNER_APP">%s</xliff:g> өшірді."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Енді экранның бір бөлігін не барлығын ұлғайта аласыз."</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Параметрлер бөлімінен қосу"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Қабылдамау"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 2a70449..e6a2fc6 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"លេខសម្គាល់អ្នកហៅចូល"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"លាក់អត្តសញ្ញាណអ្នកហៅទូរសព្ទចេញ"</string>
<string name="ColpMmi" msgid="4736462893284419302">"បានភ្ជាប់លេខសម្គាល់បន្ទាត់"</string>
<string name="ColrMmi" msgid="5889782479745764278">"បានភ្ជាប់ការដាក់កម្រិតលេខសម្គាល់បន្ទាត់"</string>
<string name="CfMmi" msgid="8390012691099787178">"បញ្ជូនការហៅបន្ត"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"សេវាកម្មជូនដំណឹងឧបករណ៍ចាប់សញ្ញា"</string>
<string name="twilight_service" msgid="8964898045693187224">"សេវាកម្មព្រលប់"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"ឧបករណ៍សម្គាល់ល្វែងម៉ោង (គ្មានការតភ្ជាប់ទេ)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"ឧបករណ៍របស់អ្នកនឹងត្រូវបានលុប"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"មិនអាចប្រើកម្មវិធីអ្នកគ្រប់គ្រងបានទេ។ ឧបករណ៍របស់អ្នកនឹងលុបឥឡូវនេះ។\n\nប្រសិនបើអ្នកមានសំណួរផ្សេងៗ សូមទាក់ទងទៅអ្នកគ្រប់គ្រងស្ថាប័នរបស់អ្នក។"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"ការបោះពុម្ពត្រូវបានបិទដោយ <xliff:g id="OWNER_APP">%s</xliff:g> ។"</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"ឥឡូវនេះ អ្នកអាចពង្រីកផ្នែកខ្លះ ឬទាំងអស់នៃអេក្រង់របស់អ្នក"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"បើកនៅក្នុងការកំណត់"</string>
<string name="dismiss_action" msgid="1728820550388704784">"ច្រានចោល"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 9fc9f36..f2d91f2 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"ಒಳಬರುವ ಕರೆಮಾಡುವವರ ID"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"ಹೊರಹೋಗುವ ಕರೆಮಾಡುವವರ ID ಅನ್ನು ಮರೆಮಾಡಿ"</string>
<string name="ColpMmi" msgid="4736462893284419302">"ಲೈನ್ ID ಗೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ"</string>
<string name="ColrMmi" msgid="5889782479745764278">"ಲೈನ್ ID ನಿರ್ಬಂಧನೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ"</string>
<string name="CfMmi" msgid="8390012691099787178">"ಕರೆಯ ರವಾನೆ"</string>
@@ -149,8 +148,7 @@
<string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"ವೈ-ಫೈ ಮಾತ್ರ"</string>
<!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
<skip />
- <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
- <skip />
+ <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> ಕ್ರಾಸ್-ಸಿಮ್ ಕರೆ ಮಾಡುವಿಕೆ"</string>
<string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ಫಾರ್ವರ್ಡ್ ಮಾಡಲಾಗಿಲ್ಲ"</string>
<string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
<string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="TIME_DELAY">{2}</xliff:g> ಸೆಕೆಂಡುಗಳ ನಂತರ <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
@@ -205,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"ಸೆನ್ಸರ್ ಅಧಿಸೂಚನೆ ಸೇವೆ"</string>
<string name="twilight_service" msgid="8964898045693187224">"ಟ್ವಿಲೈಟ್ ಸೇವೆ"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"ಸಮಯವಲಯ ಡಿಟೆಕ್ಟರ್ (ಯಾವುದೇ ಸಂಪರ್ಕ ಕಲ್ಪಿಸುವಿಕೆ ಇಲ್ಲ)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"ನಿಮ್ಮ ಸಾಧನವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"ನಿರ್ವಹಣೆ ಅಪ್ಲಿಕೇಶನ್ ಬಳಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ನಿಮ್ಮ ಸಾಧನವನ್ನು ಇದೀಗ ಅಳಿಸಲಾಗುತ್ತದೆ.\n\nನಿಮ್ಮಲ್ಲಿ ಪ್ರಶ್ನೆಗಳಿದ್ದರೆ, ನಿಮ್ಮ ಸಂಸ್ಥೆಯ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ಮೂಲಕ ಪ್ರಿಂಟಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string>
@@ -2205,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"ಈಗ ಕೆಲವು ಅಥವಾ ಎಲ್ಲಾ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಹಿಗ್ಗಿಸಬಹುದು"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"ಸೆಟ್ಟಿಂಗ್ಗಳಲ್ಲಿ ಆನ್ ಮಾಡಿ"</string>
<string name="dismiss_action" msgid="1728820550388704784">"ವಜಾಗೊಳಿಸಿ"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index fd81606b..ea5de596 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"발신자 번호"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"발신 번호 숨김"</string>
<string name="ColpMmi" msgid="4736462893284419302">"환승편 ID"</string>
<string name="ColrMmi" msgid="5889782479745764278">"환승편 ID 제한"</string>
<string name="CfMmi" msgid="8390012691099787178">"착신전환"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"센서 알림 서비스"</string>
<string name="twilight_service" msgid="8964898045693187224">"새벽 서비스"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"시간대 감지(연결되지 않음)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"기기가 삭제됩니다."</string>
<string name="factory_reset_message" msgid="2657049595153992213">"관리자 앱을 사용할 수 없습니다. 곧 기기가 삭제됩니다.\n\n궁금한 점이 있으면 조직의 관리자에게 문의하세요."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g>에 의해 사용 중지되었습니다."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"이제 화면 일부 또는 전체를 확대할 수 있습니다."</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"설정에서 사용 설정"</string>
<string name="dismiss_action" msgid="1728820550388704784">"닫기"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 612193c..5137a22 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Кирүүчү номурду аныктоо"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Чыгуучу чалууларда чалуучунун идентификаторун жашыруу"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Туташкан линия ID-си"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Туташкан линия ID-син Чектөө"</string>
<string name="CfMmi" msgid="8390012691099787178">"Башка номерге багыттоо"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Сенсордун билдирмелеринин кызматы"</string>
<string name="twilight_service" msgid="8964898045693187224">"Twilight кызматы"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Убакыт алкагын аныктагыч (байланыш жок)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Түзмөгүңүз тазаланат"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Түзмөктү башкаруучу колдонмо жараксыз. Түзмөгүңүз азыр тазаланат.\n\nСуроолоруңуз болсо, ишканаңыздын администраторуна кайрылыңыз."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Басып чыгаруу <xliff:g id="OWNER_APP">%s</xliff:g> тарабынан өчүрүлдү."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Эми толук экранды же анын бөлүгүн чоңойто аласыз"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Жөндөөлөрдөн күйгүзүү"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Жабуу"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 760d920..7de2a91 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"ໝາຍເລກຜູ່ໂທເຂົ້າ"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"ເຊື່ອງໝາຍເລກຜູ້ໂທສຳລັບການໂທອອກ"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Line ID ທີ່ເຊື່ອມໂຍງ"</string>
<string name="ColrMmi" msgid="5889782479745764278">"ຂໍ້ຈຳກັດ Line ID ທີ່ເຊື່ອມໂຍງ"</string>
<string name="CfMmi" msgid="8390012691099787178">"ການໂອນສາຍ"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"ບໍລິການການແຈ້ງເຕືອນເຊັນເຊີ"</string>
<string name="twilight_service" msgid="8964898045693187224">"ບໍລິການ Twilight"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"ຕົວກວດຫາເຂດເວລາ (ບໍ່ມີການເຊື່ອມຕໍ່)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"ອຸປະກອນຂອງທ່ານຈະຖືກລຶບ"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"ບໍ່ສາມາດໃຊ້ແອັບຜູ້ເບິ່ງແຍງລະບົບໄດ້. ອຸປະກອນຂອງທ່ານຈະຖືກລຶບຂໍ້ມູນໃນຕອນນີ້.\n\nຫາກທ່ານມີຄຳຖາມ, ໃຫ້ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບອົງກອນຂອງທ່ານ."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"ການພິມຖືກປິດໄວ້ໂດຍ <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"ຕອນນີ້ທ່ານສາມາດຂະຫຍາຍບາງສ່ວນ ຫຼື ທັງໝົດຂອງໜ້າຈໍໄດ້"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"ເປີດໃຊ້ໃນການຕັ້ງຄ່າ"</string>
<string name="dismiss_action" msgid="1728820550388704784">"ປິດໄວ້"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index da18b18..155d4cfb 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -59,8 +59,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Įeinančio skambintojo ID"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Slėpti siunčiamojo skambučio skambintojo ID"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Prijungtos eilutės ID"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Prijungtos eilutės ID apribojimas"</string>
<string name="CfMmi" msgid="8390012691099787178">"Skambučio peradresavimas"</string>
@@ -208,6 +207,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Jutiklių pranešimų paslauga"</string>
<string name="twilight_service" msgid="8964898045693187224">"Paslauga „Twilight“"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Laiko juostos aptikimo priemonė (nėra ryšio)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Įrenginys bus ištrintas"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Administratoriaus programos negalima naudoti. Dabar įrenginio duomenys bus ištrinti.\n\nJei turite klausimų, susisiekite su organizacijos administratoriumi."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Neleidžiama spausdinti (<xliff:g id="OWNER_APP">%s</xliff:g>)."</string>
@@ -2272,4 +2273,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Dabar galite padidinti dalį ekrano ar jį visą"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Įjungti nustatymuose"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Atmesti"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 4fdd570f..cd88997 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -58,8 +58,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Ienākošā zvana zvanītāja ID"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Zvanītāja ID slēpšana izejošajiem zvaniem"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Saistītās līnijas ID"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Saistītās līnijas ID ierobežojums"</string>
<string name="CfMmi" msgid="8390012691099787178">"Zvanu pāradresācija"</string>
@@ -206,6 +205,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Sensoru paziņojumu pakalpojums"</string>
<string name="twilight_service" msgid="8964898045693187224">"Krēslas noteikšanas pakalpojums"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Laika joslas noteikšanas rīks (nav savienojuma)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Jūsu ierīces dati tiks dzēsti"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Administratora lietotni nevar izmantot. Ierīcē saglabātie dati tiks dzēsti.\n\nJa jums ir kādi jautājumi, sazinieties ar savas organizācijas administratoru."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Drukāšanu atspējoja <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2238,4 +2239,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Tagad varat palielināt ekrāna daļu vai visu ekrānu"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Ieslēgt sadaļā Iestatījumi"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Nerādīt"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index b18ce23..d8ecc54 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"ID на дојдовен повикувач"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Сокривање излезен ID на повикувач"</string>
<string name="ColpMmi" msgid="4736462893284419302">"ID на поврзана линија"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Забрана на ID на поврзана линија"</string>
<string name="CfMmi" msgid="8390012691099787178">"Проследување повик"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Услуга за известување од сензорот"</string>
<string name="twilight_service" msgid="8964898045693187224">"Услуга за самрак"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Откривач на временска зона (не може да се поврзе)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Уредот ќе се избрише"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Апликацијата на администраторот не може да се користи. Уредот ќе се избрише сега.\n\nАко имате прашања, контактирајте со администраторот на организацијата."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Печатењето е оневозможено од <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Сега може се зголеми целиот екран или само дел"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Вклучи во „Поставки“"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Отфрли"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index d21ab5a..f7a3161 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"ഇൻകമിംഗ് വിളിച്ച നമ്പർ"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"ഔട്ട്ഗോയിംഗ് കോളർ ഐഡി മറയ്ക്കുക"</string>
<string name="ColpMmi" msgid="4736462893284419302">"കണക്റ്റുചെയ്തിരിക്കുന്ന ലൈൻ ഐഡി"</string>
<string name="ColrMmi" msgid="5889782479745764278">"കണക്റ്റുചെയ്തിരിക്കുന്ന ലൈൻ ഐഡി നിയന്ത്രണം"</string>
<string name="CfMmi" msgid="8390012691099787178">"കോൾ ഫോർവേഡിംഗ്"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"സെൻസർ അറിയിപ്പ് സേവനം"</string>
<string name="twilight_service" msgid="8964898045693187224">"സന്ധ്യാസമയത്തെ സേവനം"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"സമയമേഖല കണ്ടെത്താനുള്ള സംവിധാനം (കണക്റ്റിവിറ്റി ഇല്ല)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"നിങ്ങളുടെ ഉപകരണം മായ്ക്കും"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"അഡ്മിൻ ആപ്പ് ഉപയോഗിക്കാനാകില്ല. നിങ്ങളുടെ ഉപകരണം ഇപ്പോൾ മായ്ക്കപ്പെടും.\n\nനിങ്ങൾക്ക് ചോദ്യങ്ങൾ ഉണ്ടെങ്കിൽ, നിങ്ങളുടെ സ്ഥാപനത്തിന്റെ അഡ്മിനെ ബന്ധപ്പെടുക."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> പ്രിന്റിംഗ് പ്രവർത്തനരഹിതമാക്കി."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"സ്ക്രീനിന്റെ ഭാഗങ്ങളോ മുഴുവനുമോ മാഗ്നിഫൈ ചെയ്യാം"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"ക്രമീകരണത്തിൽ ഓണാക്കുക"</string>
<string name="dismiss_action" msgid="1728820550388704784">"ഡിസ്മിസ് ചെയ്യുക"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 778a15b..cb3f00d 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Дуудлага хийгчийн ID"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Залгасан дуудлага хийгчийн ID-г нуух"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Холбогдсон шугамын ID"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Холбогдсон шугамын ID Хязгаарлалт"</string>
<string name="CfMmi" msgid="8390012691099787178">"Дуудлага дамжуулах"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Мэдрэгчийн мэдэгдлийн үйлчилгээ"</string>
<string name="twilight_service" msgid="8964898045693187224">"Twilight үйлчилгээ"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Цагийн бүс илрүүлэгч (Холболт байхгүй)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Таны төхөөрөмж устах болно."</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Админ аппыг ашиглах боломжгүй. Таны төхөөрөмжийг одоо устгана.\n\nХэрэв танд асуулт байгаа бол байгууллагынхаа админтай холбогдоно уу."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> хэвлэх үйлдлийг идэвхгүй болгосон."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Та одоо зарим эсвэл бүх дэлгэцээ томруулж болно"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Тохиргоонд асаана уу"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Үл хэрэгсэх"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index dc5175b..4921f25 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -149,8 +149,7 @@
<string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"केवळ वाय-फाय"</string>
<!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
<skip />
- <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
- <skip />
+ <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> क्रॉस सिम कॉलिंग"</string>
<string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: अग्रेषित केला नाही"</string>
<string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
<string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="TIME_DELAY">{2}</xliff:g> सेकंदांनंतर <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
@@ -205,6 +204,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"सेन्सर सूचना सेवा"</string>
<string name="twilight_service" msgid="8964898045693187224">"ट्वायलाइट सेवा"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"टाइम झोन डिटेक्टर (कनेक्टिव्हिटी नाही)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"तुमचे डिव्हाइस मिटविले जाईल"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"प्रशासक अॅप वापरता येणार नाही. तुमचे डिव्हाइस आता साफ केले जाईल.\n\nतुम्हाला कुठलेही प्रश्न असल्यास, तुमच्या संस्थेच्या प्रशासकाशी संपर्क साधा."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> नी प्रिंट करणे बंद केले आहे."</string>
@@ -2205,4 +2206,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"आता स्क्रीन अंशतः किंवा पूर्ण मॅग्निफाय करू शकता"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"सेटिंग्ज मध्ये सुरू करा"</string>
<string name="dismiss_action" msgid="1728820550388704784">"डिसमिस करा"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index a14ea62..557d64d 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"ID Pemanggil Masuk"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Sembunyikan ID Pemanggil Keluar"</string>
<string name="ColpMmi" msgid="4736462893284419302">"ID Laluan yang disambungkan"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Sekatan ID Laluan yang disambungkan"</string>
<string name="CfMmi" msgid="8390012691099787178">"Pemajuan panggilan"</string>
@@ -149,8 +148,7 @@
<string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Wi-Fi sahaja"</string>
<!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
<skip />
- <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
- <skip />
+ <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> Panggilan Silang Sim"</string>
<string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Tidak dimajukan"</string>
<string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
<string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> selepas <xliff:g id="TIME_DELAY">{2}</xliff:g> saat"</string>
@@ -205,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Perkhidmatan Pemberitahuan Penderia"</string>
<string name="twilight_service" msgid="8964898045693187224">"Perkhidmatan Twilight"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Pengesan Zon Waktu (Tiada kesambungan)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Peranti anda akan dipadam"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Apl pentadbir tidak dapat digunakan. Peranti anda akan dipadamkan sekarang.\n\nJika anda ingin mengemukakan soalan, hubungi pentadbir organisasi anda."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Pencetakan dilumpuhkan oleh <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2205,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Besarkan sebahagian atau keseluruhan skrin anda"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Hidupkan dalam Tetapan"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Tolak"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index f768d17..49387d8 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEIDနံပါတ်"</string>
<string name="ClipMmi" msgid="4110549342447630629">"အဝင်ခေါ်ဆိုမှုID"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"အထွက် ခေါ်ဆိုသူ ID ကို ဝှက်ရန်"</string>
<string name="ColpMmi" msgid="4736462893284419302">"လိုင်း ID ချိတ်ဆက်သည်"</string>
<string name="ColrMmi" msgid="5889782479745764278">"လိုင်း ID ချိတ်ဆက်မှု ကန့်သတ်ချက်များ"</string>
<string name="CfMmi" msgid="8390012691099787178">"အဝင်ခေါ်ဆိုမှုအား ထပ်ဆင့်ပို့ခြင်း"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"အာရုံခံကိရိယာ အကြောင်းကြားချက် ဝန်ဆောင်မှု"</string>
<string name="twilight_service" msgid="8964898045693187224">"နေဝင်ဆည်းဆာ ဝန်ဆောင်မှု"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"ဒေသစံတော်ချိန် ရှာဖွေစနစ် (ချိတ်ဆက်နိုင်မှု မလိုပါ)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"သင့်ကိရိယာအား ပယ်ဖျက်လိမ့်မည်"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"စီမံခန့်ခွဲမှု အက်ပ်ကို သုံး၍မရပါ။ သင်၏ စက်ပစ္စည်းအတွင်းရှိ အရာများကို ဖျက်လိုက်ပါမည်\n\nမေးစရာများရှိပါက သင့်အဖွဲ့အစည်း၏ စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ။"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> က ပုံနှိပ်ထုတ်ယူခြင်းကို ပိတ်ထားသည်။"</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"ဖန်သားပြင် တစ်စိတ်တစ်ပိုင်း (သို့) တစ်ခုလုံး ချဲ့နိုင်ပါပြီ"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"\'ဆက်တင်များ\' တွင် ဖွင့်ရန်"</string>
<string name="dismiss_action" msgid="1728820550388704784">"ပယ်ရန်"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index c6831a8..2be1dab 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Inngående nummervisning"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Skjul Utgående anrops-ID"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Tilkoblet linje-ID"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Begrensning for tilkoblet linje-ID"</string>
<string name="CfMmi" msgid="8390012691099787178">"Viderekobling"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Sensor Notification Service"</string>
<string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Tidssoneoppdagelse (ingen tilkobling)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Enheten blir slettet"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Administratorappen kan ikke brukes. Enheten din blir nå tømt.\n\nTa kontakt med administratoren for organisasjonen din hvis du har spørsmål."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> har slått av utskrift."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Nå kan du forstørre deler av eller hele skjermen"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Slå på i innstillingene"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Avvis"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index ff0b00e..fac6dbc 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"आगमन कलर ID"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"बहिर्गमन कल गर्ने व्यक्तिको ID लुकाउनुहोस्"</string>
<string name="ColpMmi" msgid="4736462893284419302">"लाइन ID जोडियो"</string>
<string name="ColrMmi" msgid="5889782479745764278">"जोडिएको लाइन ID प्रतिबन्ध"</string>
<string name="CfMmi" msgid="8390012691099787178">"कल अगाडि बढाउँदै"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"सेन्सरको सूचनासम्बन्धी सेवा"</string>
<string name="twilight_service" msgid="8964898045693187224">"ट्वाइलाइट सेवा"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"समय क्षेत्र पत्ता लगाउने सुविधा (नेटवर्क कनेक्सन नहुँदा)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"तपाईंको यन्त्र मेटिनेछ"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"प्रशासकको एप प्रयोग गर्न मिल्दैन। तपाईंको यन्त्रको डेटा अब मेटाइने छ।\n\nतपाईंसँग प्रश्नहरू भएका खण्डमा आफ्नो संगठनका प्रशासकसँग सम्पर्क गर्नुहोस्।"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ले छाप्ने कार्यलाई असक्षम पार्यो।"</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"तपाईं अब स्क्रिनको केही वा सबै भाग जुम इन गर्न सक्नुहुन्छ"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"सेटिङमा गई यो सुविधा अन गर्नुहोस्"</string>
<string name="dismiss_action" msgid="1728820550388704784">"हटाउनुहोस्"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 4ada7a2..c8621a1 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Inkomende beller-ID"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Uitgaande beller-ID verbergen"</string>
<string name="ColpMmi" msgid="4736462893284419302">"ID van verbonden lijn"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Beperking voor ID van verbonden lijn"</string>
<string name="CfMmi" msgid="8390012691099787178">"Gesprek doorschakelen"</string>
@@ -149,7 +148,7 @@
<string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Alleen wifi"</string>
<!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
<skip />
- <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"Cross-sim-bellen van <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"Bellen met meerdere simkaarten van <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: niet doorgeschakeld"</string>
<string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
<string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> na <xliff:g id="TIME_DELAY">{2}</xliff:g> seconden"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Service voor sensormeldingen"</string>
<string name="twilight_service" msgid="8964898045693187224">"Service voor schemering"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Tijdzonedetector (Geen verbinding)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Je apparaat wordt gewist"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"De beheer-app kan niet worden gebruikt. Je apparaat wordt nu gewist.\n\nNeem contact op met de beheerder van je organisatie als je vragen hebt."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Afdrukken uitgeschakeld door <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Je kunt je scherm nu (gedeeltelijk) vergroten"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Inschakelen in Instellingen"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Sluiten"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 54e064d..6e07d75 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"ଇନକମିଙ୍ଗ କଲର୍ ଆଇଡି"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"ଆଉଟଗୋଇଂ କଲର୍ IDକୁ ଲୁଚାନ୍ତୁ"</string>
<string name="ColpMmi" msgid="4736462893284419302">"ସଂଯୁକ୍ତ ଲାଇନ୍ ID"</string>
<string name="ColrMmi" msgid="5889782479745764278">"ସଂଯୁକ୍ତ ଲାଇନ୍ ID କଟକଣା"</string>
<string name="CfMmi" msgid="8390012691099787178">"କଲ୍ ଫରୱାର୍ଡିଂ"</string>
@@ -149,8 +148,7 @@
<string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"କେବଳ ୱାଇ-ଫାଇ"</string>
<!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
<skip />
- <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
- <skip />
+ <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> କ୍ରସ୍ SIM କଲିଂ"</string>
<string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ଫରୱାର୍ଡ କରାଯାଇନାହିଁ"</string>
<string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
<string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> ସେକେଣ୍ଡ ପରେ"</string>
@@ -205,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"ସେନ୍ସର୍ ନୋଟିଫିକେସନ୍ ସର୍ଭିସ୍"</string>
<string name="twilight_service" msgid="8964898045693187224">"ଟ୍ୱିଲାଇଟ୍ ସର୍ଭିସ୍"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"ଟାଇମ୍ ଜୋନ୍ ଡିଟେକ୍ଟର୍ (କୌଣସି ସଂଯୋଗ ନାହିଁ)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"ଆପଣଙ୍କ ଡିଭାଇସ୍ ବର୍ତ୍ତମାନ ଲିଭାଯିବ"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"ଆଡମିନ୍ ଆପ୍ ବ୍ୟବହାର କରାଯାଇପାରିବ ନାହିଁ। ଆପଣଙ୍କ ଡିଭାଇସ୍ର ସମସ୍ତ ଡାଟାକୁ ବର୍ତ୍ତମାନ ଲିଭାଇଦିଆଯିବ। \n\nଯଦି ଆପଣଙ୍କର କୌଣସି ପ୍ରଶ୍ନ ରହିଥାଏ, ଆପଣଙ୍କ ସଂସ୍ଥାର ଆଡମିନ୍ଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ଦ୍ଵାରା ପ୍ରିଣ୍ଟିଙ୍ଗ ଅକ୍ଷମ କରାଯାଇଛି"</string>
@@ -2205,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"ଆପଣ ଏବେ ଆଂଶିକ ବା ସମ୍ପୂର୍ଣ୍ଣ ସ୍କ୍ରିନ୍ ବଡ଼ କରିପାରିବେ"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"ସେଟିଂସରେ ଚାଲୁ କରନ୍ତୁ"</string>
<string name="dismiss_action" msgid="1728820550388704784">"ଖାରଜ କରନ୍ତୁ"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 804b77d..52e124c 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -149,8 +149,7 @@
<string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"ਸਿਰਫ਼ ਵਾਈ-ਫਾਈ"</string>
<!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
<skip />
- <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
- <skip />
+ <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> ਕ੍ਰਾਸ-ਸਿਮ ਕਾਲਿੰਗ"</string>
<string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ਅੱਗੇ ਨਹੀਂ ਭੇਜਿਆ ਗਿਆ"</string>
<string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
<string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> ਸਕਿੰਟਾਂ ਬਾਅਦ"</string>
@@ -205,6 +204,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"ਸੈਂਸਰ ਸੂਚਨਾ ਸੇਵਾ"</string>
<string name="twilight_service" msgid="8964898045693187224">"ਟਵੀਲਾਈਟ ਸੇਵਾ"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"ਸਮਾਂ ਖੇਤਰ ਦਾ ਪਤਾ ਲਗਾਉਣ ਦੀ ਸੁਵਿਧਾ (ਕੋਈ ਕਨੈਕਟੀਵਿਟੀ ਨਹੀਂ)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"ਤੁਹਾਡਾ ਡੀਵਾਈਸ ਮਿਟਾਇਆ ਜਾਏਗਾ"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"ਪ੍ਰਸ਼ਾਸਕ ਐਪ ਵਰਤੀ ਨਹੀਂ ਜਾ ਸਕਦੀ। ਹੁਣ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦਾ ਡਾਟਾ ਮਿਟਾਇਆ ਜਾਵੇਗਾ।\n\nਜੇਕਰ ਤੁਹਾਡੇ ਕੋਲ ਕੋਈ ਸਵਾਲ ਹਨ, ਤਾਂ ਆਪਣੀ ਸੰਸਥਾ ਦੇ ਪ੍ਰਸ਼ਾਸਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ਵੱਲੋਂ ਪ੍ਰਿੰਟ ਕਰਨਾ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string>
@@ -2205,4 +2206,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"ਹੁਣ ਤੁਸੀਂ ਕੁਝ ਜਾਂ ਪੂਰੀ ਸਕ੍ਰੀਨ ਵੱਡਦਰਸ਼ੀ ਕਰ ਸਕਦੇ ਹੋ"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਚਾਲੂ ਕਰੋ"</string>
<string name="dismiss_action" msgid="1728820550388704784">"ਖਾਰਜ ਕਰੋ"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 8d669c4..3711cb7 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -59,8 +59,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"ID rozmówcy przy połączeniach przychodzących"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Ukryj ID rozmówcy przy rozmowie wychodzącej"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Identyfikator połączonej linii"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Ograniczenie identyfikatora połączonej linii"</string>
<string name="CfMmi" msgid="8390012691099787178">"Przekierowanie połączeń"</string>
@@ -208,6 +207,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Usługa powiadomień czujnika"</string>
<string name="twilight_service" msgid="8964898045693187224">"Usługa Zmierzch"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Wykrywanie strefy czasowej (brak połączenia)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Twoje urządzenie zostanie wyczyszczone"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Nie można użyć aplikacji administratora. Dane z urządzenia zostaną wykasowane.\n\nJeśli masz pytania, skontaktuj się z administratorem organizacji."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Drukowanie wyłączone przez: <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2272,4 +2273,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Możesz teraz powiększyć część lub całość ekranu"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Włącz w Ustawieniach"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Odrzuć"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 9837b88..e9364c4 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Identificador de chamadas recebidas"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Ocultar identificador de chamadas realizadas"</string>
<string name="ColpMmi" msgid="4736462893284419302">"ID de linha conectada"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Restrição de ID de linha conectada"</string>
<string name="CfMmi" msgid="8390012691099787178">"Encaminhamento de chamada"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Serviço de notificações do sensor"</string>
<string name="twilight_service" msgid="8964898045693187224">"Serviço de crepúsculo"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Detector de fuso horário (sem conectividade)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Seu dispositivo será limpo"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Não é possível usar o aplicativo para administrador. Seu dispositivo passará por uma limpeza agora.\n\nEm caso de dúvidas, entre em contato com o administrador da sua organização."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Impressão desativada por <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Agora você pode ampliar uma ou todas as suas telas"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Ativar nas Configurações"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Dispensar"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index ef7ee98..374ab95 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"ID do Autor da Chamada"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Ocultar identificação do autor da chamada efetuada"</string>
<string name="ColpMmi" msgid="4736462893284419302">"ID de linha ligada"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Restrição de ID de linha ligada"</string>
<string name="CfMmi" msgid="8390012691099787178">"Encaminhamento de chamadas"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Serviço de notificações do sensor"</string>
<string name="twilight_service" msgid="8964898045693187224">"Serviço de crepúsculo"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Detetor do fuso horário (sem conetividade)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"O seu dispositivo será apagado"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Não é possível utilizar a app de administrador. O seu dispositivo será agora apagado.\n\nSe tiver questões, contacte o administrador da entidade."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Impressão desativada por <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Já pode ampliar o ecrã parcial ou totalmente."</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Ativar nas Definições"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Ignorar"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 9837b88..e9364c4 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Identificador de chamadas recebidas"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Ocultar identificador de chamadas realizadas"</string>
<string name="ColpMmi" msgid="4736462893284419302">"ID de linha conectada"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Restrição de ID de linha conectada"</string>
<string name="CfMmi" msgid="8390012691099787178">"Encaminhamento de chamada"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Serviço de notificações do sensor"</string>
<string name="twilight_service" msgid="8964898045693187224">"Serviço de crepúsculo"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Detector de fuso horário (sem conectividade)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Seu dispositivo será limpo"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Não é possível usar o aplicativo para administrador. Seu dispositivo passará por uma limpeza agora.\n\nEm caso de dúvidas, entre em contato com o administrador da sua organização."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Impressão desativada por <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Agora você pode ampliar uma ou todas as suas telas"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Ativar nas Configurações"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Dispensar"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 68dad1c..38f9854 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -58,8 +58,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"ID apelant de primire"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Ascundeți ID-ul apelantului"</string>
<string name="ColpMmi" msgid="4736462893284419302">"ID-ul liniei conectate"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Restricționarea ID-ului liniei conectate"</string>
<string name="CfMmi" msgid="8390012691099787178">"Redirecționarea apelurilor"</string>
@@ -206,6 +205,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Serviciu pentru notificări de la senzori"</string>
<string name="twilight_service" msgid="8964898045693187224">"Serviciul Twilight"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Detector de fus orar (fără conexiune)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Datele de pe dispozitiv vor fi șterse"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Aplicația de administrare nu poate fi utilizată. Dispozitivul va fi șters.\n\nDacă aveți întrebări, contactați administratorul organizației dvs."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Printare dezactivată de <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2238,4 +2239,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Acum puteți mări o parte sau tot ecranul"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Activați din Setări"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Respingeți"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 03383f9..6408cce 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -59,8 +59,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Идентификация вызывающего абонента"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Идентификация звонящего абонента"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Идентификатор подключенной линии"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Ограничение идентификатора подключенной линии"</string>
<string name="CfMmi" msgid="8390012691099787178">"Переадресация вызовов"</string>
@@ -208,6 +207,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Сервис для обработки уведомлений от датчиков"</string>
<string name="twilight_service" msgid="8964898045693187224">"Сервис для определения наступления сумерек"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Определитель часового пояса (работает без Интернета)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Все данные с устройства будут удалены"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Невозможно использовать приложение для администрирования. С устройства будут удалены все данные.\n\nЕсли у вас возникли вопросы, обратитесь к администратору."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Функция печати отключена приложением \"<xliff:g id="OWNER_APP">%s</xliff:g>\""</string>
@@ -2272,4 +2273,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Теперь можно увеличивать весь экран или его часть."</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Включить в настройках"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Закрыть"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index cfa9bf1..a6d54f4 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"පැමිණෙන අමතන්නාගේ ID"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"යන ඇමතුම්කරු ID සඟවන්න"</string>
<string name="ColpMmi" msgid="4736462893284419302">"සම්බන්ධ කළ Line ID"</string>
<string name="ColrMmi" msgid="5889782479745764278">"සම්බන්ධ කළ Line ID සීමා කිරීම්"</string>
<string name="CfMmi" msgid="8390012691099787178">"ඇමතුම ඉදිරියට යැවීම"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"සංවේදක දැනුම් දීමේ සේවාව"</string>
<string name="twilight_service" msgid="8964898045693187224">"ඇඳිරි සේවාව"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"වේලා කලාප අනාවරකය (සම්බන්ධතාවක් නොමැත)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"ඔබගේ උපාංගය මකා දැමෙනු ඇත"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"පරිපාලක යෙදුම භාවිතා කළ නොහැකිය. ඔබේ උපාංගය දැන් මකා දමනු ඇත.\n\nඔබට ප්රශ්න තිබේ නම්, ඔබේ සංවිධානයේ පරිපාලකට අමතන්න."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> විසින් මුද්රණය කිරීම අබල කර ඇත."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"ඔබට දැන් තිරයේ සමහර හෝ සියලු දේ විශාලනය කළ හැකිය"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"සැකසීම් තුළ ක්රියාත්මක කරන්න"</string>
<string name="dismiss_action" msgid="1728820550388704784">"ඉවත ලන්න"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index f8dfc26..a478083 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -59,8 +59,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Prichádzajúca identifikácia volajúceho"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Skryť identifikáciu volajúcich pri odchádzajúcich hovoroch"</string>
<string name="ColpMmi" msgid="4736462893284419302">"ID pripojenej linky"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Obmedzenie ID pripojenej linky"</string>
<string name="CfMmi" msgid="8390012691099787178">"Presmerovanie hovorov"</string>
@@ -208,6 +207,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Služba upozornení senzora"</string>
<string name="twilight_service" msgid="8964898045693187224">"Služba stmievania"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Detektor časového pásma (bez pripojenia)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Vaše zariadenie bude vymazané"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Daná aplikácia na správu sa nedá použiť. Vaše zariadenie bude vymazané.\n\nV prípade otázok kontaktujte správcu organizácie."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Tlač zakázala aplikácia <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2272,4 +2273,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Teraz môžete zväčšiť celú obrazovku alebo jej časť"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Zapnúť v Nastaveniach"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Zavrieť"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 4a5c5da..b353f45 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -59,8 +59,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"ID dohodnega klicatelja"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Skrivanje ID-ja odhodnega klicatelja"</string>
<string name="ColpMmi" msgid="4736462893284419302">"ID povezane linije"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Omejitev ID-ja povezane linije"</string>
<string name="CfMmi" msgid="8390012691099787178">"Preusmerjanje klicev"</string>
@@ -208,6 +207,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Storitev obvestil tipal"</string>
<string name="twilight_service" msgid="8964898045693187224">"Storitev Somrak"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Zaznavanje časovnega pasu (brez povezave)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Podatki v napravi bodo izbrisani"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Skrbniške aplikacije ni mogoče uporabljati. Podatki v napravi bodo izbrisani.\n\nČe imate vprašanja, se obrnite na skrbnika organizacije."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Tiskanje je onemogočil pravilnik <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2272,4 +2273,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Zdaj lahko povečate del zaslona ali celotni zaslon"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Vklopite v nastavitvah"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Opusti"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 5ee9031..86f191f 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"ID-ja e telefonuesit hyrës"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Fshih ID-në e telefonuesit në dalje"</string>
<string name="ColpMmi" msgid="4736462893284419302">"ID-ja e linjës së lidhur"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Kufizimi i ID-së së linjës së lidhur"</string>
<string name="CfMmi" msgid="8390012691099787178">"Transferimi i telefonatave"</string>
@@ -149,8 +148,7 @@
<string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Vetëm Wi-Fi"</string>
<!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
<skip />
- <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
- <skip />
+ <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"Telefonatat e kryqëzuara të kartës SIM nga <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nuk u transferua"</string>
<string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
<string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> pas <xliff:g id="TIME_DELAY">{2}</xliff:g> sekondash"</string>
@@ -205,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Shërbimi i njoftimeve të sensorit"</string>
<string name="twilight_service" msgid="8964898045693187224">"Shërbimi i muzgut"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Zbuluesi i brezit orar (nuk nevojitet lidhja)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Pajisja do të spastrohet"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Aplikacioni i administratorit nuk mund të përdoret. Pajisja jote tani do të fshihet.\n\nNëse ke pyetje, kontakto me administratorin e organizatës."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Printimi është çaktivizuar nga <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2205,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Tani mund t\'i zmadhosh një pjesë apo të gjithë ekranin tënd"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Aktivizo te \"Cilësimet\""</string>
<string name="dismiss_action" msgid="1728820550388704784">"Hiq"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index a430d56..594a2ee 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -58,8 +58,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Долазни ИД позиваоца"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Сакријте ИД одлазног позиваоца"</string>
<string name="ColpMmi" msgid="4736462893284419302">"ИД повезане линије"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Ограничење ИД-а повезане линије"</string>
<string name="CfMmi" msgid="8390012691099787178">"Преусмеравање позива"</string>
@@ -206,6 +205,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Услуга обавештења сензора"</string>
<string name="twilight_service" msgid="8964898045693187224">"Услуга Сумрак"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Детектор временске зоне (нема интернет везе)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Уређај ће бити обрисан"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Не можете да користите ову апликацију за администраторе. Уређај ће сада бити обрисан.\n\nАко имате питања, контактирајте администратора организације."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Штампање је онемогућила апликација <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2238,4 +2239,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Можете да увећате део екрана или цео екран"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Укључите у Подешавањима"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Одбаци"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 186a78a..d87ae37 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI-kod"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Nummerpresentatör för inkommande samtal"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Dölj nummerpresentatör för utgående samtal"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Visning av uppkopplat nummer"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Blockera visning av uppkopplat nummer"</string>
<string name="CfMmi" msgid="8390012691099787178">"Vidarekoppla samtal"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Sensor Notification Service"</string>
<string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Tidszondetektering (ingen anslutning)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Enheten kommer att rensas"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Det går inte att använda administratörsappen. Enheten rensas.\n\nKontakta organisationens administratör om du har några frågor."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Utskrift har inaktiverats av <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Nu kan du förstora delar av eller hela skärmen"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Aktivera i inställningarna"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Stäng"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index cf9496d..93f0ed9 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Kitambulisho cha Mpigaji wa Simu Inayoingia"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Ficha Kitambulisho Chako Unapopiga Simu"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Kitambulisho cha Mstari Uliounganishwa"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Kizuizi cha Kitambulisho cha Mstari Uliounganishwa"</string>
<string name="CfMmi" msgid="8390012691099787178">"Kusambaza simu"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Huduma ya Arifa ya Kitambuzi"</string>
<string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Kitambua Saa za Eneo (Hakuna muunganisho)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Data iliyomo kwenye kifaa chako itafutwa"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Huwezi kutumia programu ya msimamizi. Sasa data iliyo kwenye kifaa chako itafutwa.\n\nIkiwa una maswali yoyote, wasiliana na msimamizi wa shirika lako."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Kipengele cha kuchapisha kimezimwa na <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Sasa unaweza kukuza sehemu ya au skrini yako yote"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Washa katika Mipangilio"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Ondoa"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index f3e5f91..53052d7 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"உள்வரும் அழைப்பாளர் ஐடி"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"வெளிச்செல்லும் அழைப்பாளர் ஐடியை மறைத்தல்"</string>
<string name="ColpMmi" msgid="4736462893284419302">"இணைக்கப்பட்ட லைன் ஐடி"</string>
<string name="ColrMmi" msgid="5889782479745764278">"இணைக்கப்பட்ட லைன் ஐடியை வரம்பிடல்"</string>
<string name="CfMmi" msgid="8390012691099787178">"அழைப்பு திருப்பிவிடுதல்"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"சென்சார் அறிவிப்புச் சேவை"</string>
<string name="twilight_service" msgid="8964898045693187224">"Twilight சேவை"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"நேர மண்டல டிடெக்டர் (இணைப்பு இல்லை)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"சாதனத் தரவு அழிக்கப்படும்"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"நிர்வாகி ஆப்ஸை உபயோகிக்க முடியாது. இப்போது, உங்கள் சாதனம் ஆரம்ப நிலைக்கு மீட்டமைக்கப்படும்.\n\nஏதேனும் கேள்விகள் இருப்பின், உங்கள் நிறுவனத்தின் நிர்வாகியைத் தொடர்புகொள்ளவும்."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"பிரிண்ட் செய்வதை <xliff:g id="OWNER_APP">%s</xliff:g> தடுத்துள்ளது."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"திரை முழுவதையுமோ ஒரு பகுதியையோ பெரிதாக்கலாம்"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"அமைப்புகளில் ஆன் செய்க"</string>
<string name="dismiss_action" msgid="1728820550388704784">"மூடுக"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 2687aa1..2de91ba 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"ఇన్కమింగ్ కాలర్ ID"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"అవుట్గోయింగ్ కాలర్ IDని దాచండి"</string>
<string name="ColpMmi" msgid="4736462893284419302">"కనెక్ట్ చేయబడిన పంక్తి ID"</string>
<string name="ColrMmi" msgid="5889782479745764278">"కనెక్ట్ చేయబడిన పంక్తి ID నియంత్రణ"</string>
<string name="CfMmi" msgid="8390012691099787178">"కాల్ ఫార్వర్డింగ్"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"సెన్సార్ నోటిఫికేషన్ సర్వీస్"</string>
<string name="twilight_service" msgid="8964898045693187224">"ట్విలైట్ సర్వీస్"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"టైమ్ జోన్ డిటెక్టర్ (కనెక్టివిటీ లేదు)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"మీ పరికరంలోని డేటా తొలగించబడుతుంది"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"నిర్వాహక యాప్ ఉపయోగించడం సాధ్యపడదు. మీ పరికరంలోని డేటా ఇప్పుడు తొలగించబడుతుంది.\n\nమీకు ప్రశ్నలు ఉంటే, మీ సంస్థ యొక్క నిర్వాహకులను సంప్రదించండి."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"ముద్రణ <xliff:g id="OWNER_APP">%s</xliff:g> ద్వారా నిలిపివేయబడింది."</string>
@@ -236,9 +237,9 @@
<string name="shutdown_confirm" product="default" msgid="136816458966692315">"మీ ఫోన్ షట్డౌన్ చేయబడుతుంది."</string>
<string name="shutdown_confirm_question" msgid="796151167261608447">"మీరు షట్ డౌన్ చేయాలనుకుంటున్నారా?"</string>
<string name="reboot_safemode_title" msgid="5853949122655346734">"సురక్షిత మోడ్కు రీబూట్ చేయండి"</string>
- <string name="reboot_safemode_confirm" msgid="1658357874737219624">"మీరు సురక్షిత మోడ్లోకి రీబూట్ చేయాలనుకుంటున్నారా? దీని వలన మీరు ఇన్స్టాల్ చేసిన అన్ని మూడవ పక్షం అనువర్తనాలు నిలిపివేయబడతాయి. ఇవి మీరు మళ్లీ రీబూట్ చేసినప్పుడు పునరుద్ధరించబడతాయి."</string>
+ <string name="reboot_safemode_confirm" msgid="1658357874737219624">"మీరు సురక్షిత మోడ్లోకి రీబూట్ చేయాలనుకుంటున్నారా? దీని వలన మీరు ఇన్స్టాల్ చేసిన అన్ని మూడవ పక్షం యాప్లు నిలిపివేయబడతాయి. ఇవి మీరు మళ్లీ రీబూట్ చేసినప్పుడు పునరుద్ధరించబడతాయి."</string>
<string name="recent_tasks_title" msgid="8183172372995396653">"ఇటీవలివి"</string>
- <string name="no_recent_tasks" msgid="9063946524312275906">"ఇటీవలి అనువర్తనాలు ఏవీ లేవు."</string>
+ <string name="no_recent_tasks" msgid="9063946524312275906">"ఇటీవలి యాప్లు ఏవీ లేవు."</string>
<string name="global_actions" product="tablet" msgid="4412132498517933867">"టాబ్లెట్ ఎంపికలు"</string>
<string name="global_actions" product="tv" msgid="3871763739487450369">"Android TV ఎంపికలు"</string>
<string name="global_actions" product="default" msgid="6410072189971495460">"ఫోన్ ఎంపికలు"</string>
@@ -344,13 +345,13 @@
<string name="permlab_expandStatusBar" msgid="1184232794782141698">"స్థితి పట్టీని విస్తరింపజేయడం/కుదించడం"</string>
<string name="permdesc_expandStatusBar" msgid="7180756900448498536">"స్థితి బార్ను విస్తరింపజేయడానికి లేదా కుదించడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_install_shortcut" msgid="7451554307502256221">"షార్ట్కట్లను ఇన్స్టాల్ చేయడం"</string>
- <string name="permdesc_install_shortcut" msgid="4476328467240212503">"వినియోగదారు ప్రమేయం లేకుండానే హోమ్స్క్రీన్ సత్వరమార్గాలను జోడించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permdesc_install_shortcut" msgid="4476328467240212503">"వినియోగదారు ప్రమేయం లేకుండానే హోమ్స్క్రీన్ సత్వరమార్గాలను జోడించడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_uninstall_shortcut" msgid="295263654781900390">"సత్వరమార్గాలను అన్ఇన్స్టాల్ చేయడం"</string>
- <string name="permdesc_uninstall_shortcut" msgid="1924735350988629188">"వినియోగదారు ప్రమేయం లేకుండానే హోమ్స్క్రీన్ సత్వరమార్గాలను తీసివేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permdesc_uninstall_shortcut" msgid="1924735350988629188">"వినియోగదారు ప్రమేయం లేకుండానే హోమ్స్క్రీన్ సత్వరమార్గాలను తీసివేయడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_processOutgoingCalls" msgid="4075056020714266558">"అవుట్గోయింగ్ కాల్లను దారి మళ్లించడం"</string>
- <string name="permdesc_processOutgoingCalls" msgid="7833149750590606334">"కాల్ను వేరే నంబర్కు దారి మళ్లించే లేదా మొత్తంగా కాల్ను ఆపివేసే ఎంపిక సహాయంతో అవుట్గోయింగ్ కాల్ సమయంలో డయల్ చేయబడుతున్న నంబర్ను చూడటానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="7833149750590606334">"కాల్ను వేరే నంబర్కు దారి మళ్లించే లేదా మొత్తంగా కాల్ను ఆపివేసే ఎంపిక సహాయంతో అవుట్గోయింగ్ కాల్ సమయంలో డయల్ చేయబడుతున్న నంబర్ను చూడటానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_answerPhoneCalls" msgid="4131324833663725855">"ఫోన్ కాల్లకు సమాధానమివ్వు"</string>
- <string name="permdesc_answerPhoneCalls" msgid="894386681983116838">"ఇన్కమింగ్ ఫోన్ కాల్లకు సమాధానమివ్వడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permdesc_answerPhoneCalls" msgid="894386681983116838">"ఇన్కమింగ్ ఫోన్ కాల్లకు సమాధానమివ్వడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_receiveSms" msgid="505961632050451881">"వచన సందేశాలను (SMS) స్వీకరించడం"</string>
<string name="permdesc_receiveSms" msgid="1797345626687832285">"SMS సందేశాలను స్వీకరించడానికి మరియు ప్రాసెస్ చేయడానికి యాప్ను అనుమతిస్తుంది. యాప్ మీ డివైజ్కు పంపబడిన సందేశాలను మీకు చూపకుండానే పర్యవేక్షించగలదని లేదా తొలగించగలదని దీని అర్థం."</string>
<string name="permlab_receiveMms" msgid="4000650116674380275">"వచన సందేశాలను (MMS) స్వీకరించడం"</string>
@@ -396,7 +397,7 @@
<string name="permlab_getPackageSize" msgid="375391550792886641">"యాప్ నిల్వ స్థలాన్ని అంచనా వేయడం"</string>
<string name="permdesc_getPackageSize" msgid="742743530909966782">"యాప్ కోడ్, డేటా మరియు కాష్ పరిమాణాలను తిరిగి పొందడానికి దాన్ని అనుమతిస్తుంది"</string>
<string name="permlab_writeSettings" msgid="8057285063719277394">"సిస్టమ్ సెట్టింగ్లను మార్చడం"</string>
- <string name="permdesc_writeSettings" msgid="8293047411196067188">"సిస్టమ్ యొక్క సెట్టింగ్ల డేటాను సవరించడానికి అనువర్తనాన్ని అనుమతిస్తుంది. హానికరమైన యాప్లు మీ సిస్టమ్ యొక్క కాన్ఫిగరేషన్ను నాశనం చేయవచ్చు."</string>
+ <string name="permdesc_writeSettings" msgid="8293047411196067188">"సిస్టమ్ యొక్క సెట్టింగ్ల డేటాను సవరించడానికి యాప్ను అనుమతిస్తుంది. హానికరమైన యాప్లు మీ సిస్టమ్ యొక్క కాన్ఫిగరేషన్ను నాశనం చేయవచ్చు."</string>
<string name="permlab_receiveBootCompleted" msgid="6643339400247325379">"ప్రారంభంలో అమలు చేయడం"</string>
<string name="permdesc_receiveBootCompleted" product="tablet" msgid="5565659082718177484">"సిస్టమ్ బూటింగ్ను పూర్తి చేసిన వెంటనే దానికదే ప్రారంభించబడటానికి యాప్ను అనుమతిస్తుంది. ఇది టాబ్లెట్ను ప్రారంభించడానికి ఎక్కువ సమయం పట్టేలా చేయవచ్చు మరియు ఎల్లప్పుడూ అమలు చేయడం ద్వారా మొత్తం టాబ్లెట్ను నెమ్మదిగా పని చేయడానికి యాప్ను అనుమతించేలా చేయవచ్చు."</string>
<string name="permdesc_receiveBootCompleted" product="tv" msgid="4900842256047614307">"సిస్టమ్ బూటింగ్ను పూర్తి చేసిన వెంటనే యాప్ దానికదే ప్రారంభం కావడానికి అనుమతిస్తుంది. ఇది మీ Android TV పరికరం ప్రారంభం కావడానికి ఎక్కువ సమయం పట్టేలా చేయవచ్చు మరియు ఎల్లప్పుడూ అమలు కావడం ద్వారా మొత్తం పరికరం పనితీరును నెమ్మది చేయడానికి యాప్ను అనుమతించవచ్చు."</string>
@@ -444,7 +445,7 @@
<string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"బ్యాక్గ్రౌండ్లో ఆడియోను రికార్డ్ చేయగలదు"</string>
<string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"మైక్రోఫోన్ను ఉపయోగించి ఈ యాప్ ఎప్పుడైనా ఆడియోను రికార్డ్ చేయగలదు."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"SIMకి ఆదేశాలను పంపడం"</string>
- <string name="permdesc_sim_communication" msgid="4179799296415957960">"సిమ్కు ఆదేశాలను పంపడానికి అనువర్తనాన్ని అనుమతిస్తుంది. ఇది చాలా ప్రమాదకరం."</string>
+ <string name="permdesc_sim_communication" msgid="4179799296415957960">"సిమ్కు ఆదేశాలను పంపడానికి యాప్ను అనుమతిస్తుంది. ఇది చాలా ప్రమాదకరం."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"భౌతిక కార్యాకలాపాన్ని గుర్తించండి"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"ఈ యాప్ మీ భౌతిక కార్యాకలాపాన్ని గుర్తించగలదు."</string>
<string name="permlab_camera" msgid="6320282492904119413">"చిత్రాలు మరియు వీడియోలు తీయడం"</string>
@@ -461,11 +462,11 @@
<string name="permlab_callPhone" msgid="1798582257194643320">"నేరుగా కాల్ చేసే ఫోన్ నంబర్లు"</string>
<string name="permdesc_callPhone" msgid="5439809516131609109">"మీ ప్రమేయం లేకుండా ఫోన్ నంబర్లకు కాల్ చేయడానికి యాప్ను అనుమతిస్తుంది. దీని వలన అనుకోని ఛార్జీలు విధించబడవచ్చు లేదా కాల్లు రావచ్చు. ఇది అత్యవసర నంబర్లకు కాల్ చేయడానికి యాప్ను అనుమతించదని గుర్తుంచుకోండి. హానికరమైన యాప్లు మీ నిర్ధారణ లేకుండానే కాల్లు చేయడం ద్వారా మీకు డబ్బు ఖర్చయ్యేలా చేయవచ్చు."</string>
<string name="permlab_accessImsCallService" msgid="442192920714863782">"IMS కాల్ సేవ యాక్సెస్ అనుమతి"</string>
- <string name="permdesc_accessImsCallService" msgid="6328551241649687162">"మీ ప్రమేయం లేకుండా కాల్లు చేయడం కోసం IMS సేవను ఉపయోగించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permdesc_accessImsCallService" msgid="6328551241649687162">"మీ ప్రమేయం లేకుండా కాల్లు చేయడం కోసం IMS సేవను ఉపయోగించడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_readPhoneState" msgid="8138526903259297969">"ఫోన్ స్థితి మరియు గుర్తింపుని చదవడం"</string>
<string name="permdesc_readPhoneState" msgid="7229063553502788058">"పరికరం యొక్క ఫోన్ ఫీచర్లను యాక్సెస్ చేయడానికి యాప్ను అనుమతిస్తుంది. ఈ అనుమతి ఫోన్ నంబర్ మరియు పరికరం IDలను, కాల్ సక్రియంగా ఉందా లేదా అనే విషయాన్ని మరియు కాల్ ద్వారా కనెక్ట్ చేయబడిన రిమోట్ నంబర్ను కనుగొనడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_manageOwnCalls" msgid="9033349060307561370">"కాల్లను సిస్టమ్ ద్వారా వెళ్లేలా చేయి"</string>
- <string name="permdesc_manageOwnCalls" msgid="4431178362202142574">"కాలింగ్ అనుభవాన్ని మెరుగుపరచడం కోసం తన కాల్లను సిస్టమ్ ద్వారా వెళ్లేలా చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permdesc_manageOwnCalls" msgid="4431178362202142574">"కాలింగ్ అనుభవాన్ని మెరుగుపరచడం కోసం తన కాల్లను సిస్టమ్ ద్వారా వెళ్లేలా చేయడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_callCompanionApp" msgid="3654373653014126884">"సిస్టమ్ ద్వారా కాల్లను చూసి, నియంత్రించండి."</string>
<string name="permdesc_callCompanionApp" msgid="8474168926184156261">"పరికరంలో కొనసాగుతున్న కాల్లను చూడడానికి మరియు నియంత్రించడానికి యాప్ను అనుమతిస్తుంది. ఇందులో కాల్ కోసం కాల్ల నంబర్లు మరియు రాష్ట్ర కాల్ వంటి సమాచారం ఉంటుంది."</string>
<string name="permlab_exemptFromAudioRecordRestrictions" msgid="1164725468350759486">"ఆడియో రికార్డ్ పరిమితుల నుండి మినహాయింపు"</string>
@@ -483,9 +484,9 @@
<string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"మీ Android TV పరికరం స్లీప్ మోడ్లోకి వెళ్లకుండా నివారించడానికి యాప్ని అనుమతిస్తుంది."</string>
<string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"నిద్రావస్థకి వెళ్లకుండా ఫోన్ను నిరోధించడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_transmitIr" msgid="8077196086358004010">"ఇన్ఫ్రారెడ్ ప్రసరణ"</string>
- <string name="permdesc_transmitIr" product="tablet" msgid="5884738958581810253">"టాబ్లెట్ యొక్క ఇన్ఫ్రారెడ్ ట్రాన్స్మిటర్ను ఉపయోగించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5884738958581810253">"టాబ్లెట్ యొక్క ఇన్ఫ్రారెడ్ ట్రాన్స్మిటర్ను ఉపయోగించడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permdesc_transmitIr" product="tv" msgid="3278506969529173281">"మీ Android TV పరికరం యొక్క ఇన్ఫ్రారెడ్ ట్రాన్స్మిటర్ని ఉపయోగించడానికి యాప్ని అనుమతిస్తుంది."</string>
- <string name="permdesc_transmitIr" product="default" msgid="8484193849295581808">"ఫోన్ యొక్క ఇన్ఫ్రారెడ్ ట్రాన్స్మిటర్ను ఉపయోగించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="8484193849295581808">"ఫోన్ యొక్క ఇన్ఫ్రారెడ్ ట్రాన్స్మిటర్ను ఉపయోగించడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_setWallpaper" msgid="6959514622698794511">"వాల్పేపర్ను సెట్ చేయడం"</string>
<string name="permdesc_setWallpaper" msgid="2973996714129021397">"సిస్టమ్ వాల్పేపర్ను సెట్ చేయడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_setWallpaperHints" msgid="1153485176642032714">"మీ వాల్పేపర్ పరిమాణాన్ని సర్దుబాటు చేయడం"</string>
@@ -507,13 +508,13 @@
<string name="permlab_changeTetherState" msgid="9079611809931863861">"టీథర్ చేయబడిన కనెక్టివిటీని మార్చడం"</string>
<string name="permdesc_changeTetherState" msgid="3025129606422533085">"టీథర్ చేసిన నెట్వర్క్ కనెక్టివిటీ యొక్క స్థితిని మార్చడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_accessWifiState" msgid="5552488500317911052">"Wi-Fi కనెక్షన్లను వీక్షించడం"</string>
- <string name="permdesc_accessWifiState" msgid="6913641669259483363">"Wi-Fi ప్రారంభించబడిందా, లేదా మరియు కనెక్ట్ చేయబడిన Wi-Fi పరికరాల పేరు వంటి Wi-Fi నెట్వర్కింగ్ గురించి సమాచారాన్ని వీక్షించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permdesc_accessWifiState" msgid="6913641669259483363">"Wi-Fi ప్రారంభించబడిందా, లేదా మరియు కనెక్ట్ చేయబడిన Wi-Fi పరికరాల పేరు వంటి Wi-Fi నెట్వర్కింగ్ గురించి సమాచారాన్ని వీక్షించడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_changeWifiState" msgid="7947824109713181554">"Wi-Fiకి కనెక్ట్ చేయడం మరియు దాని నుండి డిస్కనెక్ట్ చేయడం"</string>
<string name="permdesc_changeWifiState" msgid="7170350070554505384">"Wi-Fi యాక్సెస్ స్థానాలకు కనెక్ట్ చేయడానికి మరియు వాటి నుండి డిస్కనెక్ట్ చేయడానికి మరియు Wi-Fi నెట్వర్క్ల కోసం పరికర కాన్ఫిగరేషన్కు మార్పులు చేయడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_changeWifiMulticastState" msgid="285626875870754696">"Wi-Fi Multicast స్వీకరణను అనుమతించడం"</string>
<string name="permdesc_changeWifiMulticastState" product="tablet" msgid="191079868596433554">"మల్టీక్యాస్ట్ చిరునామాలను ఉపయోగించి మీ టాబ్లెట్కు మాత్రమే కాకుండా Wi-Fi నెట్వర్క్లోని అన్ని పరికరాలకు పంపబడిన ప్యాకెట్లను స్వీకరించడానికి యాప్ను అనుమతిస్తుంది. మల్టీక్యాస్ట్ యేతర మోడ్ కంటే ఇది ఎక్కువ పవర్ ఉపయోగిస్తుంది."</string>
<string name="permdesc_changeWifiMulticastState" product="tv" msgid="1336952358450652595">"మల్టీక్యాస్ట్ చిరునామాలను ఉపయోగించి మీ Android TV పరికరానికి మాత్రమే కాకుండా Wi-Fi నెట్వర్క్లోని అన్ని పరికరాలకు పంపిన ప్యాకెట్లను స్వీకరించడానికి యాప్ని అనుమతిస్తుంది. ఇది మల్టీక్యాస్ట్ యేతర మోడ్ కంటే ఎక్కువ పవర్ను ఉపయోగిస్తుంది."</string>
- <string name="permdesc_changeWifiMulticastState" product="default" msgid="8296627590220222740">"మల్టీక్యాస్ట్ చిరునామాలను ఉపయోగించి మీ ఫోన్కు మాత్రమే కాకుండా Wi-Fi నెట్వర్క్లోని అన్ని పరికరాలకు పంపబడిన ప్యాకెట్లను స్వీకరించడానికి అనువర్తనాన్ని అనుమతిస్తుంది. మల్టీక్యాస్ట్ యేతర మోడ్ కంటే ఇది ఎక్కువ పవర్ ఉపయోగిస్తుంది."</string>
+ <string name="permdesc_changeWifiMulticastState" product="default" msgid="8296627590220222740">"మల్టీక్యాస్ట్ చిరునామాలను ఉపయోగించి మీ ఫోన్కు మాత్రమే కాకుండా Wi-Fi నెట్వర్క్లోని అన్ని పరికరాలకు పంపబడిన ప్యాకెట్లను స్వీకరించడానికి యాప్ను అనుమతిస్తుంది. మల్టీక్యాస్ట్ యేతర మోడ్ కంటే ఇది ఎక్కువ పవర్ ఉపయోగిస్తుంది."</string>
<string name="permlab_bluetoothAdmin" msgid="6490373569441946064">"బ్లూటూత్ సెట్టింగ్లను యాక్సెస్ చేయడం"</string>
<string name="permdesc_bluetoothAdmin" product="tablet" msgid="5370837055438574863">"స్థానిక బ్లూటూత్ టాబ్లెట్ను కాన్ఫిగర్ చేయడానికి మరియు రిమోట్ పరికరాలతో దాన్ని కనుగొనడానికి మరియు జత చేయడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"మీ Android TV పరికరంలో బ్లూటూత్ను కాన్ఫిగర్ చేయడానికి మరియు రిమోట్ పరికరాలతో దాన్ని కనుగొని, జత చేయడానికి యాప్ను అనుమతిస్తుంది."</string>
@@ -521,7 +522,7 @@
<string name="permlab_accessWimaxState" msgid="7029563339012437434">"WiMAXకు కనెక్ట్ చేయడం మరియు దాని నుండి డిస్కనెక్ట్ చేయడం"</string>
<string name="permdesc_accessWimaxState" msgid="5372734776802067708">"Wi-Fi ప్రారంభించబడిందా, లేదా మరియు కనెక్ట్ చేయబడిన WiMAX నెట్వర్క్ల గురించి సమాచారాన్ని కనుగొనడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_changeWimaxState" msgid="6223305780806267462">"WiMAX స్థితిని మార్చడం"</string>
- <string name="permdesc_changeWimaxState" product="tablet" msgid="4011097664859480108">"WiMAX నెట్వర్క్లకు టాబ్లెట్ను కనెక్ట్ చేయడానికి మరియు వాటి నుండి టాబ్లెట్ను డిస్కనెక్ట్ చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permdesc_changeWimaxState" product="tablet" msgid="4011097664859480108">"WiMAX నెట్వర్క్లకు టాబ్లెట్ను కనెక్ట్ చేయడానికి మరియు వాటి నుండి టాబ్లెట్ను డిస్కనెక్ట్ చేయడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permdesc_changeWimaxState" product="tv" msgid="5373274458799425276">"మీ Android TV పరికరాన్ని WiMAX నెట్వర్క్లకు కనెక్ట్ చేయడానికి లేదా డిస్కనెక్ట్ చేయడానికి యాప్ని అనుమతిస్తుంది."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="1551666203780202101">"WiMAX నెట్వర్క్లకు ఫోన్ను కనెక్ట్ చేయడానికి మరియు వాటి నుండి ఫోన్ను డిస్కనెక్ట్ చేయడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_bluetooth" msgid="586333280736937209">"బ్లూటూత్ పరికరాలతో జత చేయడం"</string>
@@ -637,19 +638,19 @@
<string name="permlab_sdcardWrite" msgid="4863021819671416668">"మీ షేర్ చేసిన నిల్వ యొక్క కంటెంట్లను సవరించండి లేదా తొలగించండి"</string>
<string name="permdesc_sdcardWrite" msgid="8376047679331387102">"మీ షేర్ చేసిన నిల్వ యొక్క కంటెంట్లను రాయడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_use_sip" msgid="8250774565189337477">"SIP కాల్లను చేయడానికి/స్వీకరించడానికి"</string>
- <string name="permdesc_use_sip" msgid="3590270893253204451">"SIP కాల్లను చేయడానికి మరియు స్వీకరించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permdesc_use_sip" msgid="3590270893253204451">"SIP కాల్లను చేయడానికి మరియు స్వీకరించడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_register_sim_subscription" msgid="1653054249287576161">"కొత్త టెలికామ్ SIM కనెక్షన్లను నమోదు చేయడం"</string>
- <string name="permdesc_register_sim_subscription" msgid="4183858662792232464">"కొత్త టెలికామ్ SIM కనెక్షన్లను నమోదు చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permdesc_register_sim_subscription" msgid="4183858662792232464">"కొత్త టెలికామ్ SIM కనెక్షన్లను నమోదు చేయడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_register_call_provider" msgid="6135073566140050702">"కొత్త టెలికామ్ కనెక్షన్లను నమోదు చేయడం"</string>
- <string name="permdesc_register_call_provider" msgid="4201429251459068613">"కొత్త టెలికామ్ కనెక్షన్లను నమోదు చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permdesc_register_call_provider" msgid="4201429251459068613">"కొత్త టెలికామ్ కనెక్షన్లను నమోదు చేయడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_connection_manager" msgid="3179365584691166915">"టెలికామ్ కనెక్షన్లను నిర్వహించడం"</string>
- <string name="permdesc_connection_manager" msgid="1426093604238937733">"టెలికామ్ కనెక్షన్లను నిర్వహించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permdesc_connection_manager" msgid="1426093604238937733">"టెలికామ్ కనెక్షన్లను నిర్వహించడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_bind_incall_service" msgid="5990625112603493016">"ఇన్-కాల్ స్క్రీన్తో పరస్పర చర్య చేయడం"</string>
- <string name="permdesc_bind_incall_service" msgid="4124917526967765162">"వినియోగదారునికి ఇన్-కాల్ స్క్రీన్ ఎప్పుడు, ఎలా కనిపించాలనే దాన్ని నియంత్రించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permdesc_bind_incall_service" msgid="4124917526967765162">"వినియోగదారునికి ఇన్-కాల్ స్క్రీన్ ఎప్పుడు, ఎలా కనిపించాలనే దాన్ని నియంత్రించడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_bind_connection_service" msgid="5409268245525024736">"టెలిఫోన్ సేవలతో పరస్పర చర్య చేయడం"</string>
- <string name="permdesc_bind_connection_service" msgid="6261796725253264518">"కాల్లు చేయడం/స్వీకరించడం కోసం టెలిఫోన్ సేవలతో పరస్పర చర్య చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permdesc_bind_connection_service" msgid="6261796725253264518">"కాల్లు చేయడం/స్వీకరించడం కోసం టెలిఫోన్ సేవలతో పరస్పర చర్య చేయడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_control_incall_experience" msgid="6436863486094352987">"ఇన్-కాల్ వినియోగదారు అనుభవాన్ని అందించడం"</string>
- <string name="permdesc_control_incall_experience" msgid="5896723643771737534">"ఇన్-కాల్ వినియోగదారుని అనుభవాన్ని అందించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permdesc_control_incall_experience" msgid="5896723643771737534">"ఇన్-కాల్ వినియోగదారుని అనుభవాన్ని అందించడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_readNetworkUsageHistory" msgid="8470402862501573795">"చారిత్రక నెట్వర్క్ వినియోగాన్ని చదవడం"</string>
<string name="permdesc_readNetworkUsageHistory" msgid="1112962304941637102">"నిర్దిష్ట నెట్వర్క్లు మరియు యాప్ల కోసం చారిత్రాత్మక నెట్వర్క్ వినియోగాన్ని చదవడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_manageNetworkPolicy" msgid="6872549423152175378">"నెట్వర్క్ విధానాన్ని నిర్వహించడం"</string>
@@ -657,31 +658,31 @@
<string name="permlab_modifyNetworkAccounting" msgid="7448790834938749041">"నెట్వర్క్ వినియోగ అకౌంటింగ్ను సవరించడం"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5076042642247205390">"యాప్లలో నెట్వర్క్ వినియోగం ఎలా గణించాలనే దాన్ని సవరించడానికి యాప్ను అనుమతిస్తుంది. సాధారణ యాప్ల ద్వారా ఉపయోగించడానికి ఉద్దేశించినది కాదు."</string>
<string name="permlab_accessNotifications" msgid="7130360248191984741">"నోటిఫికేషన్లను యాక్సెస్ చేయడం"</string>
- <string name="permdesc_accessNotifications" msgid="761730149268789668">"నోటిఫికేషన్లను, ఇతర అనువర్తనాల ద్వారా పోస్ట్ చేయబడిన వాటిని తిరిగి పొందడానికి, పరిశీలించడానికి మరియు క్లియర్ చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permdesc_accessNotifications" msgid="761730149268789668">"నోటిఫికేషన్లను, ఇతర అనువర్తనాల ద్వారా పోస్ట్ చేయబడిన వాటిని తిరిగి పొందడానికి, పరిశీలించడానికి మరియు క్లియర్ చేయడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_bindNotificationListenerService" msgid="5848096702733262458">"నోటిఫికేషన్ పరిశీలన సేవకు అనుబంధించడం"</string>
<string name="permdesc_bindNotificationListenerService" msgid="4970553694467137126">"నోటిఫికేషన్ పరిశీలన సేవ యొక్క అగ్ర-స్థాయి ఇంటర్ఫేస్కు అనుబంధించడానికి హోల్డర్ను అనుమతిస్తుంది. సాధారణ అనువర్తనాల కోసం ఎప్పటికీ అవసరం ఉండకూడదు."</string>
<string name="permlab_bindConditionProviderService" msgid="5245421224814878483">"షరతు ప్రదాత సేవకు అనుబంధించడం"</string>
<string name="permdesc_bindConditionProviderService" msgid="6106018791256120258">"షరతు ప్రదాత సేవ యొక్క అగ్ర-స్థాయి ఇంటర్ఫేస్కు అనుబంధించడానికి హోల్డర్ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
<string name="permlab_bindDreamService" msgid="4776175992848982706">"డ్రీమ్ సేవకి అనుబంధించడం"</string>
<string name="permdesc_bindDreamService" msgid="9129615743300572973">"డ్రీమ్ సేవ యొక్క అగ్ర-స్థాయి ఇంటర్ఫేస్కు అనుబంధించడానికి హోల్డర్ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
- <string name="permlab_invokeCarrierSetup" msgid="5098810760209818140">"క్యారియర్ అందించిన కాన్ఫిగరేషన్ అనువర్తనాన్ని అభ్యర్థించడం"</string>
- <string name="permdesc_invokeCarrierSetup" msgid="4790845896063237887">"క్యారియర్ అందించిన కాన్ఫిగరేషన్ అనువర్తనాన్ని అభ్యర్థించడానికి హోల్డర్ను అనుమతిస్తుంది. సాధారణ అనువర్తనాల కోసం ఎప్పటికీ అవసరం ఉండకూడదు."</string>
+ <string name="permlab_invokeCarrierSetup" msgid="5098810760209818140">"క్యారియర్ అందించిన కాన్ఫిగరేషన్ యాప్ను అభ్యర్థించడం"</string>
+ <string name="permdesc_invokeCarrierSetup" msgid="4790845896063237887">"క్యారియర్ అందించిన కాన్ఫిగరేషన్ యాప్ను అభ్యర్థించడానికి హోల్డర్ను అనుమతిస్తుంది. సాధారణ అనువర్తనాల కోసం ఎప్పటికీ అవసరం ఉండకూడదు."</string>
<string name="permlab_accessNetworkConditions" msgid="1270732533356286514">"నెట్వర్క్ పరిస్థితులపై పరిశీలనల గురించి తెలుసుకోవడం"</string>
- <string name="permdesc_accessNetworkConditions" msgid="2959269186741956109">"నెట్వర్క్ పరిస్థితులపై పరిశీలనల గురించి తెలుసుకోవడానికి అనువర్తనాన్ని అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండకూడదు."</string>
+ <string name="permdesc_accessNetworkConditions" msgid="2959269186741956109">"నెట్వర్క్ పరిస్థితులపై పరిశీలనల గురించి తెలుసుకోవడానికి యాప్ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండకూడదు."</string>
<string name="permlab_setInputCalibration" msgid="932069700285223434">"ఇన్పుట్ పరికరం క్రమాంకనాన్ని మార్చండి"</string>
- <string name="permdesc_setInputCalibration" msgid="2937872391426631726">"టచ్ స్క్రీన్ యొక్క క్రమాంకన పరామితులను సవరించడానికి అనువర్తనాన్ని అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
+ <string name="permdesc_setInputCalibration" msgid="2937872391426631726">"టచ్ స్క్రీన్ యొక్క క్రమాంకన పరామితులను సవరించడానికి యాప్ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
<string name="permlab_accessDrmCertificates" msgid="6473765454472436597">"DRM ప్రమాణపత్రాలను యాక్సెస్ చేయడం"</string>
- <string name="permdesc_accessDrmCertificates" msgid="6983139753493781941">"DRM ప్రమాణపత్రాలను కేటాయించడానికి మరియు ఉపయోగించడానికి అనువర్తనాన్ని అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
+ <string name="permdesc_accessDrmCertificates" msgid="6983139753493781941">"DRM ప్రమాణపత్రాలను కేటాయించడానికి మరియు ఉపయోగించడానికి యాప్ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
<string name="permlab_handoverStatus" msgid="7620438488137057281">"Android Beam బదిలీ స్థితిని స్వీకరించడం"</string>
- <string name="permdesc_handoverStatus" msgid="3842269451732571070">"ప్రస్తుత Android Beam బదిలీలకు సంబంధించిన సమాచారాన్ని స్వీకరించడానికి ఈ అనువర్తనాన్ని అనుమతిస్తుంది"</string>
+ <string name="permdesc_handoverStatus" msgid="3842269451732571070">"ప్రస్తుత Android Beam బదిలీలకు సంబంధించిన సమాచారాన్ని స్వీకరించడానికి ఈ యాప్ను అనుమతిస్తుంది"</string>
<string name="permlab_removeDrmCertificates" msgid="710576248717404416">"DRM ప్రమాణపత్రాలను తీసివేయడం"</string>
- <string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"DRM ప్రమాణపత్రాలను తీసివేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
+ <string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"DRM ప్రమాణపత్రాలను తీసివేయడానికి యాప్ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
<string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"క్యారియర్ సందేశ సేవకు అనుబంధించడం"</string>
<string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"క్యారియర్ సందేశ సేవ యొక్క అగ్ర-స్థాయి ఇంటర్ఫేస్కు అనుబంధించడానికి హోల్డర్ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
<string name="permlab_bindCarrierServices" msgid="2395596978626237474">"క్యారియర్ సేవలకు అనుబంధించడం"</string>
<string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"క్యారియర్ సేవలకు అనుబంధించడానికి హోల్డర్ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
<string name="permlab_access_notification_policy" msgid="5524112842876975537">"అంతరాయం కలిగించవద్దును యాక్సెస్ చేయడం"</string>
- <string name="permdesc_access_notification_policy" msgid="8538374112403845013">"అంతరాయం కలిగించవద్దు ఎంపిక కాన్ఫిగరేషన్ చదవడానికి మరియు వ్రాయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permdesc_access_notification_policy" msgid="8538374112403845013">"అంతరాయం కలిగించవద్దు ఎంపిక కాన్ఫిగరేషన్ చదవడానికి మరియు వ్రాయడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"వీక్షణ అనుమతి వినియోగాన్ని ప్రారంభించండి"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"యాప్నకు అనుమతి వినియోగాన్ని ప్రారంభించడానికి హోల్డర్ను అనుమతిస్తుంది. సాధారణ యాప్లకు ఎప్పటికీ ఇటువంటి అనుమతి అవసరం ఉండదు."</string>
<string name="policylab_limitPassword" msgid="4851829918814422199">"పాస్వర్డ్ నియమాలను సెట్ చేయండి"</string>
@@ -1126,7 +1127,7 @@
<string name="low_internal_storage_view_text" msgid="8172166728369697835">"కొన్ని సిస్టమ్ కార్యాచరణలు పని చేయకపోవచ్చు"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="7368968163411251788">"సిస్టమ్ కోసం తగినంత నిల్వ లేదు. మీకు 250MB ఖాళీ స్థలం ఉందని నిర్ధారించుకుని, పునఃప్రారంభించండి."</string>
<string name="app_running_notification_title" msgid="8985999749231486569">"<xliff:g id="APP_NAME">%1$s</xliff:g> అమలులో ఉంది"</string>
- <string name="app_running_notification_text" msgid="5120815883400228566">"మరింత సమాచారం కోసం లేదా అనువర్తనాన్ని ఆపివేయడం కోసం నొక్కండి."</string>
+ <string name="app_running_notification_text" msgid="5120815883400228566">"మరింత సమాచారం కోసం లేదా యాప్ను ఆపివేయడం కోసం నొక్కండి."</string>
<string name="ok" msgid="2646370155170753815">"సరే"</string>
<string name="cancel" msgid="6908697720451760115">"రద్దు చేయి"</string>
<string name="yes" msgid="9069828999585032361">"సరే"</string>
@@ -1159,28 +1160,28 @@
<string name="whichSendToApplication" msgid="77101541959464018">"దీన్ని ఉపయోగించి పంపండి"</string>
<string name="whichSendToApplicationNamed" msgid="3385686512014670003">"%1$sని ఉపయోగించి పంపండి"</string>
<string name="whichSendToApplicationLabel" msgid="3543240188816513303">"పంపు"</string>
- <string name="whichHomeApplication" msgid="8276350727038396616">"హోమ్ అనువర్తనాన్ని ఎంచుకోండి"</string>
+ <string name="whichHomeApplication" msgid="8276350727038396616">"హోమ్ యాప్ను ఎంచుకోండి"</string>
<string name="whichHomeApplicationNamed" msgid="5855990024847433794">"%1$sని హోమ్గా ఉపయోగించండి"</string>
<string name="whichHomeApplicationLabel" msgid="8907334282202933959">"చిత్రాన్ని క్యాప్చర్ చేయి"</string>
<string name="whichImageCaptureApplication" msgid="2737413019463215284">"దీనితో చిత్రాన్ని క్యాప్చర్ చేయి"</string>
<string name="whichImageCaptureApplicationNamed" msgid="8820702441847612202">"%1$sతో చిత్రాన్ని క్యాప్చర్ చేయండి"</string>
<string name="whichImageCaptureApplicationLabel" msgid="6505433734824988277">"చిత్రాన్ని క్యాప్చర్ చేయి"</string>
<string name="alwaysUse" msgid="3153558199076112903">"ఈ చర్యకు డిఫాల్ట్గా ఉపయోగించండి."</string>
- <string name="use_a_different_app" msgid="4987790276170972776">"వేరొక అనువర్తనాన్ని ఉపయోగించండి"</string>
- <string name="clearDefaultHintMsg" msgid="1325866337702524936">"సిస్టమ్ సెట్టింగ్లు > అనువర్తనాలు > డౌన్లోడ్ చేయబడినవిలో డిఫాల్ట్ను క్లియర్ చేయి."</string>
+ <string name="use_a_different_app" msgid="4987790276170972776">"వేరొక యాప్ను ఉపయోగించండి"</string>
+ <string name="clearDefaultHintMsg" msgid="1325866337702524936">"సిస్టమ్ సెట్టింగ్లు > యాప్లు > డౌన్లోడ్ చేయబడినవిలో డిఫాల్ట్ను క్లియర్ చేయి."</string>
<string name="chooseActivity" msgid="8563390197659779956">"చర్యను ఎంచుకోండి"</string>
<string name="chooseUsbActivity" msgid="2096269989990986612">"USB పరికరం కోసం యాప్ను ఎంచుకోండి"</string>
- <string name="noApplications" msgid="1186909265235544019">"ఈ చర్యను అమలు చేయగల అనువర్తనాలు ఏవీ లేవు."</string>
+ <string name="noApplications" msgid="1186909265235544019">"ఈ చర్యను అమలు చేయగల యాప్లు ఏవీ లేవు."</string>
<string name="aerr_application" msgid="4090916809370389109">"<xliff:g id="APPLICATION">%1$s</xliff:g> ఆపివేయబడింది"</string>
<string name="aerr_process" msgid="4268018696970966407">"<xliff:g id="PROCESS">%1$s</xliff:g> ఆపివేయబడింది"</string>
<string name="aerr_application_repeated" msgid="7804378743218496566">"<xliff:g id="APPLICATION">%1$s</xliff:g> పునరావృతంగా ఆపివేయబడుతోంది"</string>
<string name="aerr_process_repeated" msgid="1153152413537954974">"<xliff:g id="PROCESS">%1$s</xliff:g> పునరావృతంగా ఆపివేయబడుతోంది"</string>
- <string name="aerr_restart" msgid="2789618625210505419">"అనువర్తనాన్ని మళ్లీ తెరువు"</string>
+ <string name="aerr_restart" msgid="2789618625210505419">"యాప్ను మళ్లీ తెరువు"</string>
<string name="aerr_report" msgid="3095644466849299308">"ఫీడ్బ్యాక్ను పంపు"</string>
<string name="aerr_close" msgid="3398336821267021852">"మూసివేయి"</string>
<string name="aerr_mute" msgid="2304972923480211376">"పరికరం పునఃప్రారంభమయ్యే వరకు మ్యూట్ చేయి"</string>
<string name="aerr_wait" msgid="3198677780474548217">"వేచి ఉండండి"</string>
- <string name="aerr_close_app" msgid="8318883106083050970">"అనువర్తనాన్ని మూసివేయి"</string>
+ <string name="aerr_close_app" msgid="8318883106083050970">"యాప్ను మూసివేయి"</string>
<string name="anr_title" msgid="7290329487067300120"></string>
<string name="anr_activity_application" msgid="8121716632960340680">"<xliff:g id="APPLICATION">%2$s</xliff:g> ప్రతిస్పందించడం లేదు"</string>
<string name="anr_activity_process" msgid="3477362583767128667">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ప్రతిస్పందించడం లేదు"</string>
@@ -1195,7 +1196,7 @@
<string name="launch_warning_original" msgid="3332206576800169626">"<xliff:g id="APP_NAME">%1$s</xliff:g> వాస్తవంగా ప్రారంభించబడింది."</string>
<string name="screen_compat_mode_scale" msgid="8627359598437527726">"ప్రమాణం"</string>
<string name="screen_compat_mode_show" msgid="5080361367584709857">"ఎల్లప్పుడూ చూపు"</string>
- <string name="screen_compat_mode_hint" msgid="4032272159093750908">"సిస్టమ్ సెట్టింగ్లు > అనువర్తనాలు > డౌన్లోడ్ చేసినవిలో దీన్ని పునఃప్రారంభించండి."</string>
+ <string name="screen_compat_mode_hint" msgid="4032272159093750908">"సిస్టమ్ సెట్టింగ్లు > యాప్లు > డౌన్లోడ్ చేసినవిలో దీన్ని పునఃప్రారంభించండి."</string>
<string name="unsupported_display_size_message" msgid="7265211375269394699">"<xliff:g id="APP_NAME">%1$s</xliff:g> ప్రస్తుత ప్రదర్శన పరిమాణ సెట్టింగ్కు మద్దతు ఇవ్వదు, దీని వలన ఊహించని సమస్యలు తలెత్తవచ్చు."</string>
<string name="unsupported_display_size_show" msgid="980129850974919375">"ఎల్లప్పుడూ చూపు"</string>
<string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"Android OS యొక్క అననుకూల వెర్షన్ కోసం <xliff:g id="APP_NAME">%1$s</xliff:g> రూపొందించబడింది మరియు ఊహించని సమస్యలు తలెత్తవచ్చు. యాప్ యొక్క అప్డేట్ చేసిన వెర్షన్ అందుబాటులో ఉండవచ్చు."</string>
@@ -1340,7 +1341,7 @@
<string name="taking_remote_bugreport_notification_title" msgid="1582531382166919850">"బగ్ నివేదికను తీస్తోంది…"</string>
<string name="share_remote_bugreport_notification_title" msgid="6708897723753334999">"బగ్ నివేదికను భాగస్వామ్యం చేయాలా?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="3077385149217638550">"బగ్ నివేదికను భాగస్వామ్యం చేస్తోంది..."</string>
- <string name="share_remote_bugreport_notification_message_finished" msgid="7325635795739260135">"మీ నిర్వాహకులు ఈ పరికరం సమస్యకు పరిష్కారాన్ని కనుగొనడంలో సహాయం కోసం బగ్ నివేదికను అభ్యర్థించారు. అనువర్తనాలు మరియు డేటా భాగస్వామ్యం చేయబడవచ్చు."</string>
+ <string name="share_remote_bugreport_notification_message_finished" msgid="7325635795739260135">"మీ నిర్వాహకులు ఈ పరికరం సమస్యకు పరిష్కారాన్ని కనుగొనడంలో సహాయం కోసం బగ్ నివేదికను అభ్యర్థించారు. యాప్లు మరియు డేటా భాగస్వామ్యం చేయబడవచ్చు."</string>
<string name="share_remote_bugreport_action" msgid="7630880678785123682">"షేర్ చేయి"</string>
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"తిరస్కరిస్తున్నాను"</string>
<string name="select_input_method" msgid="3971267998568587025">"ఇన్పుట్ పద్ధతిని ఎంచుకోండి"</string>
@@ -1403,13 +1404,13 @@
<string name="ext_media_status_missing" msgid="6520746443048867314">"చొప్పించబడలేదు"</string>
<string name="activity_list_empty" msgid="4219430010716034252">"సరిపోలే కార్యాచరణలు కనుగొనబడలేదు."</string>
<string name="permlab_route_media_output" msgid="8048124531439513118">"మీడియా అవుట్పుట్ను మళ్లించడం"</string>
- <string name="permdesc_route_media_output" msgid="1759683269387729675">"మీడియా అవుట్పుట్ను ఇతర బాహ్య పరికరాలకు మళ్లించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permdesc_route_media_output" msgid="1759683269387729675">"మీడియా అవుట్పుట్ను ఇతర బాహ్య పరికరాలకు మళ్లించడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_readInstallSessions" msgid="7279049337895583621">"ఇన్స్టాల్ సెషన్లను చదవడం"</string>
- <string name="permdesc_readInstallSessions" msgid="4012608316610763473">"ఇన్స్టాల్ సెషన్లను చదవడానికి అనువర్తనాన్ని అనుమతిస్తుంది. ఇది సక్రియ ప్యాకేజీ ఇన్స్టాలేషన్ల గురించి వివరాలను చూడటానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permdesc_readInstallSessions" msgid="4012608316610763473">"ఇన్స్టాల్ సెషన్లను చదవడానికి యాప్ను అనుమతిస్తుంది. ఇది సక్రియ ప్యాకేజీ ఇన్స్టాలేషన్ల గురించి వివరాలను చూడటానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_requestInstallPackages" msgid="7600020863445351154">"ఇన్స్టాల్ ప్యాకేజీలను అభ్యర్థించడం"</string>
- <string name="permdesc_requestInstallPackages" msgid="3969369278325313067">"ప్యాకేజీల ఇన్స్టాలేషన్ అభ్యర్థించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permdesc_requestInstallPackages" msgid="3969369278325313067">"ప్యాకేజీల ఇన్స్టాలేషన్ అభ్యర్థించడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_requestDeletePackages" msgid="2541172829260106795">"ప్యాకేజీలను తొలగించడానికి అభ్యర్థించు"</string>
- <string name="permdesc_requestDeletePackages" msgid="6133633516423860381">"ప్యాకేజీల తొలగింపును అభ్యర్థించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permdesc_requestDeletePackages" msgid="6133633516423860381">"ప్యాకేజీల తొలగింపును అభ్యర్థించడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="7646611326036631439">"బ్యాటరీ అనుకూలీకరణలను విస్మరించడానికి అడగాలి"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"ఆ యాప్ కోసం బ్యాటరీ అనుకూలీకరణలు విస్మరించేలా అనుమతి కోరడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"జూమ్ నియంత్రణ కోసం రెండుసార్లు నొక్కండి"</string>
@@ -1430,8 +1431,8 @@
<string name="deny" msgid="6632259981847676572">"తిరస్కరించండి"</string>
<string name="permission_request_notification_title" msgid="1810025922441048273">"అనుమతి అభ్యర్థించబడింది"</string>
<string name="permission_request_notification_with_subtitle" msgid="3743417870360129298">"ఖాతా <xliff:g id="ACCOUNT">%s</xliff:g> కోసం\nఅనుమతి అభ్యర్థించబడింది."</string>
- <string name="forward_intent_to_owner" msgid="4620359037192871015">"మీరు మీ కార్యాలయ ప్రొఫైల్కు వెలుపల ఈ అనువర్తనాన్ని ఉపయోగిస్తున్నారు"</string>
- <string name="forward_intent_to_work" msgid="3620262405636021151">"మీరు మీ కార్యాలయ ప్రొఫైల్లో ఈ అనువర్తనాన్ని ఉపయోగిస్తున్నారు"</string>
+ <string name="forward_intent_to_owner" msgid="4620359037192871015">"మీరు మీ కార్యాలయ ప్రొఫైల్కు వెలుపల ఈ యాప్ను ఉపయోగిస్తున్నారు"</string>
+ <string name="forward_intent_to_work" msgid="3620262405636021151">"మీరు మీ కార్యాలయ ప్రొఫైల్లో ఈ యాప్ను ఉపయోగిస్తున్నారు"</string>
<string name="input_method_binding_label" msgid="1166731601721983656">"ఇన్పుట్ పద్ధతి"</string>
<string name="sync_binding_label" msgid="469249309424662147">"సమకాలీకరణ"</string>
<string name="accessibility_binding_label" msgid="1974602776545801715">"యాక్సెస్ సామర్థ్యం"</string>
@@ -1909,7 +1910,7 @@
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ఈ యాప్ పాత వెర్షన్ Android కోసం రూపొందించబడింది మరియు అది సరిగ్గా పని చేయకపోవచ్చు. అప్డేట్ల కోసం తనిఖీ చేయడానికి ప్రయత్నించండి లేదా డెవలపర్ని సంప్రదించండి."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"అప్డేట్ కోసం తనిఖీ చేయండి"</string>
<string name="new_sms_notification_title" msgid="6528758221319927107">"మీకు కొత్త సందేశాలు ఉన్నాయి"</string>
- <string name="new_sms_notification_content" msgid="3197949934153460639">"వీక్షించడానికి SMS అనువర్తనాన్ని తెరవండి"</string>
+ <string name="new_sms_notification_content" msgid="3197949934153460639">"వీక్షించడానికి SMS యాప్ను తెరవండి"</string>
<string name="profile_encrypted_title" msgid="9001208667521266472">"కొంత ఫంక్షనాలిటీ పరిమితం కావచ్చు"</string>
<string name="profile_encrypted_detail" msgid="5279730442756849055">"కార్యాలయ ప్రొఫైల్ లాక్ అయింది"</string>
<string name="profile_encrypted_message" msgid="1128512616293157802">"కార్యాలయ ప్రొఫైల్ అన్లాక్ చేయుటకు నొక్కండి"</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"స్క్రీన్ మొత్తం లేదా కొంత భాగాన్ని జూమ్ చేయవచ్చు"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"సెట్టింగ్లలో ఆన్ చేయండి"</string>
<string name="dismiss_action" msgid="1728820550388704784">"విస్మరించు"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 01ffd62..aa3331a 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"หมายเลขผู้โทรเข้า"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"ซ่อนหมายเลขผู้โทรออก"</string>
<string name="ColpMmi" msgid="4736462893284419302">"รหัสสายที่เชื่อมต่อ"</string>
<string name="ColrMmi" msgid="5889782479745764278">"ข้อจำกัดรหัสสายที่เชื่อมต่อ"</string>
<string name="CfMmi" msgid="8390012691099787178">"การโอนสาย"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"บริการแจ้งเตือนเกี่ยวกับเซ็นเซอร์"</string>
<string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"ตัวตรวจจับเขตเวลา (ไม่มีการเชื่อมต่อ)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"ระบบจะลบข้อมูลในอุปกรณ์ของคุณ"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"ใช้แอปผู้ดูแลระบบนี้ไม่ได้ ขณะนี้ระบบจะลบข้อมูลในอุปกรณ์ของคุณ\n\nโปรดติดต่อผู้ดูแลระบบขององค์กรหากมีคำถาม"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ปิดใช้การพิมพ์แล้ว"</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"คุณสามารถขยายหน้าจอบางส่วนหรือทั้งหมดได้แล้วตอนนี้"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"เปิดในการตั้งค่า"</string>
<string name="dismiss_action" msgid="1728820550388704784">"ปิด"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 40968eb..d3a1fe7 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Papasok na Caller ID"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Itago ang Outgoing Caller ID"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Connected Line ID"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Paghihigpit sa Connected Line ID"</string>
<string name="CfMmi" msgid="8390012691099787178">"Pagpapasa ng tawag"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Serbisyo ng Notification ng Sensor"</string>
<string name="twilight_service" msgid="8964898045693187224">"Serbisyo ng Twilight"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Detector ng Time Zone (Walang koneksyon)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Buburahin ang iyong device"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Hindi magamit ang admin app. Mabubura na ang iyong device.\n\nKung mayroon kang mga tanong, makipag-ugnayan sa admin ng iyong organisasyon."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Na-disable ng <xliff:g id="OWNER_APP">%s</xliff:g> ang pag-print."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Mama-magnify na ang bahagi o kabuuan ng screen mo"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"I-on sa Mga Setting"</string>
<string name="dismiss_action" msgid="1728820550388704784">"I-dismiss"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 342ff20..26108fb 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Gelen Çağrı Kimliği"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Giden Arama Arayan Kimliğini Gizle"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Bağlanılan Hat Kimliği"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Bağlanılan Hat Kimliğini Kısıtlama"</string>
<string name="CfMmi" msgid="8390012691099787178">"Çağrı yönlendirme"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Sensör Bildirim Hizmeti"</string>
<string name="twilight_service" msgid="8964898045693187224">"Alacakaranlık Hizmeti"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Zaman Dilimi Algılayıcı (Bağlantı yok)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Cihazınız silinecek"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Yönetim uygulaması kullanılamıyor. Cihazınız şimdi silinecek.\n\nSorularınız varsa kuruluşunuzun yöneticisine başvurun."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Yazdırma işlemi <xliff:g id="OWNER_APP">%s</xliff:g> tarafından devre dışı bırakıldı."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Artık ekranınızın bir kısmını veya tamamını büyütebilirsiniz"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Ayarlar\'da aç"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Kapat"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index cf2c6f1..abb1b7d 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -59,8 +59,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Вхідн. ід. абонента"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Приховати ідентифікатор абонента для вихідних викликів"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Ідентифікатор під’єднаної лінії"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Обмеження ідентифікатора під’єднаної лінії"</string>
<string name="CfMmi" msgid="8390012691099787178">"Переадресація виклику"</string>
@@ -208,6 +207,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Сервіс \"Сповіщення датчика\""</string>
<string name="twilight_service" msgid="8964898045693187224">"Сервіс \"Сутінки\""</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Визначення часового поясу (без Інтернету)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"З вашого пристрою буде стерто всі дані"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Не можна запускати додаток для адміністраторів. Буде відновлено заводські налаштування пристрою.\n\nЯкщо у вас є запитання, зв’яжіться з адміністратором своєї організації."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Додаток <xliff:g id="OWNER_APP">%s</xliff:g> вимкнув друк."</string>
@@ -2272,4 +2273,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Тепер можна збільшити весь екран або його частину"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Увімкнути в налаштуваннях"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Закрити"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 8f54c27..ae7b5a5 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -149,8 +149,7 @@
<string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"صرف Wi-Fi"</string>
<!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
<skip />
- <!-- no translation found for crossSimFormat_spn_cross_sim_calling (779976494687695991) -->
- <skip />
+ <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> کراس sim کالنگ"</string>
<string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : فارورڈ نہیں کی گئی"</string>
<string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
<string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> بعد از <xliff:g id="TIME_DELAY">{2}</xliff:g> سیکنڈ"</string>
@@ -205,6 +204,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"سینسر نوٹیفکیشن سروس"</string>
<string name="twilight_service" msgid="8964898045693187224">"شفقی سروس"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"ٹائم زون ڈیٹیکٹر (کوئی کنیکٹوٹی نہیں ہے)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"آپ کا آلہ صاف کر دیا جائے گا"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"منتظم کی ایپ استعمال نہیں کی جا سکتی۔ آپ کا آلہ اب مٹا دیا جائے گا۔\n\nاگر آپ کے سوالات ہیں تو اپنی تنظیم کے منتظم سے رابطہ کریں۔"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> نے پرنٹنگ کو غیر فعال کر دیا ہے۔"</string>
@@ -2205,4 +2206,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"اب آپ اپنی تمام یا کچھ اسکرین کو بڑا کر سکتے ہیں"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"ترتیبات میں آن کریں"</string>
<string name="dismiss_action" msgid="1728820550388704784">"برخاست کریں"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index a8bc4ba..e72114a 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Kiruvchi raqami"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Chaqiruvchi raqamini yashirish"</string>
<string name="ColpMmi" msgid="4736462893284419302">"Qo‘ng‘iroq qiluvchining raqami"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Qo‘ng‘iroq qiluvchining raqamini cheklash"</string>
<string name="CfMmi" msgid="8390012691099787178">"Chaqiruvlarni uzatish"</string>
@@ -149,7 +148,7 @@
<string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Faqat Wi-Fi"</string>
<!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
<skip />
- <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> Umumiy sim chaqiruvlar"</string>
+ <string name="crossSimFormat_spn_cross_sim_calling" msgid="779976494687695991">"<xliff:g id="SPN">%s</xliff:g> Kross-SIM chaqiruvlar"</string>
<string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Yo‘naltirilmadi"</string>
<string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
<string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> soniyadan so‘ng"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Sensorli bildirishnoma xizmati"</string>
<string name="twilight_service" msgid="8964898045693187224">"Twilight xizmati"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Vaqt mintaqasini aniqlagich (Oflayn)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Qurilmangizdagi ma’lumotlar o‘chirib tashlanadi"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Administrator ilovasini ishlatib bo‘lmaydi. Qurilmada barcha ma’lumotlar o‘chirib tashlanadi.\n\nSavollaringiz bo‘lsa, administrator bilan bog‘laning."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Chop etish funksiyasi <xliff:g id="OWNER_APP">%s</xliff:g> tomonidan faolsizlantirilgan."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Ekranni toʻliq yoki qisman kattalashtirish mumkin"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Sozlamalar orqali yoqish"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Yopish"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 0af241e..b3fdcfc 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -204,6 +204,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Dịch vụ Thông báo của cảm biến"</string>
<string name="twilight_service" msgid="8964898045693187224">"Dịch vụ Twilight"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Trình phát hiện múi giờ (Không có kết nối)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Thiết bị của bạn sẽ bị xóa"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Không thể sử dụng ứng dụng quản trị. Thiết bị của bạn sẽ bị xóa ngay bây giờ.\n\nHãy liên hệ với quản trị viên của tổ chức nếu bạn có thắc mắc."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> đã tắt tính năng in."</string>
@@ -2204,4 +2206,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Giờ đây, bạn có thể phóng to một phần hoặc toàn màn hình"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Bật trong phần Cài đặt"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Đóng"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 4503305..347ad56 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"来电显示"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"外拨时隐藏本机号码"</string>
<string name="ColpMmi" msgid="4736462893284419302">"连接的线路ID"</string>
<string name="ColrMmi" msgid="5889782479745764278">"连接的线路ID限制"</string>
<string name="CfMmi" msgid="8390012691099787178">"来电转接"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"传感器通知服务"</string>
<string name="twilight_service" msgid="8964898045693187224">"Twilight 服务"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"时区检测器(无网络连接)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"系统将清空您的设备"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"无法使用管理应用,系统现在将清空您的设备。\n\n如有疑问,请与您所在单位的管理员联系。"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"“<xliff:g id="OWNER_APP">%s</xliff:g>”已停用打印功能。"</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"您现在可以放大屏幕上的部分或所有内容"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"在“设置”中开启"</string>
<string name="dismiss_action" msgid="1728820550388704784">"关闭"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 92b007c..79ce664 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"來電顯示"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"撥出時隱藏「來電顯示」資料"</string>
<string name="ColpMmi" msgid="4736462893284419302">"連接線識別功能"</string>
<string name="ColrMmi" msgid="5889782479745764278">"連接線識別限制"</string>
<string name="CfMmi" msgid="8390012691099787178">"來電轉駁"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"感應器通知服務"</string>
<string name="twilight_service" msgid="8964898045693187224">"暮光服務"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"時區偵測器 (沒有連線)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"您的裝置將被清除"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"無法使用管理員應用程式。系統會現在清除您的裝置。\n\n如有任何疑問,請聯絡您的機構管理員。"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"「<xliff:g id="OWNER_APP">%s</xliff:g>」暫停了列印。"</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"您現在可以放大部分或整個畫面"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"在「設定」中開啟"</string>
<string name="dismiss_action" msgid="1728820550388704784">"關閉"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index df2d5ea..15a1201 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"來電顯示"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"撥出時隱藏「來電顯示」資訊"</string>
<string name="ColpMmi" msgid="4736462893284419302">"連接的線路 ID"</string>
<string name="ColrMmi" msgid="5889782479745764278">"連接的線路 ID 限制"</string>
<string name="CfMmi" msgid="8390012691099787178">"來電轉接"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"感應器通知服務"</string>
<string name="twilight_service" msgid="8964898045693187224">"Twilight 服務"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"時區偵測器 (不必連上網路)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"你的裝置資料將遭到清除"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"無法使用管理應用程式,系統現在將清除你裝置中的資料。\n\n如有任何問題,請與貴機構的管理員聯絡。"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"「<xliff:g id="OWNER_APP">%s</xliff:g>」已停用列印功能。"</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"你可以放大局部或整個畫面"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"在「設定」中開啟"</string>
<string name="dismiss_action" msgid="1728820550388704784">"關閉"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 3f2d547..b18afe7 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -57,8 +57,7 @@
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"I-ID Yocingo Olungenayo"</string>
- <!-- no translation found for ClirMmi (6752346475055446417) -->
- <skip />
+ <string name="ClirMmi" msgid="6752346475055446417">"Fihla Ubunikazi Bekholi Ephumayo"</string>
<string name="ColpMmi" msgid="4736462893284419302">"I-ID yomugqa exhumekile"</string>
<string name="ColrMmi" msgid="5889782479745764278">"I-ID yomugqa oxhumekile ikhawulelwe"</string>
<string name="CfMmi" msgid="8390012691099787178">"Ukudlulisa ikholi"</string>
@@ -204,6 +203,8 @@
<string name="sensor_notification_service" msgid="7474531979178682676">"Isevisi Yesaziso Senzwa"</string>
<string name="twilight_service" msgid="8964898045693187224">"Isevisi Yangovivi"</string>
<string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Isitholi Sezoni Yesikhathi (Akukho ukuxhumana)"</string>
+ <!-- no translation found for gnss_time_update_service (9039489496037616095) -->
+ <skip />
<string name="factory_reset_warning" msgid="6858705527798047809">"Idivayisi yakho izosulwa"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Uhlelo lokusebenza lomlawuli alikwazi ukusetshenziswa. Idivayisi yakho manje izosuswa.\n\nUma unemibuzo, xhumana nomlawuli wezinhlangano zakho."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Ukuphrinta kukhutshazwe nge-<xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -2204,4 +2205,12 @@
<string name="window_magnification_prompt_content" msgid="4166711383253283838">"Manje usungakwazi ukukhulisa esinye noma sonke isikrini sakho"</string>
<string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Vula Kumasethingi"</string>
<string name="dismiss_action" msgid="1728820550388704784">"Cashisa"</string>
+ <!-- no translation found for sensor_privacy_start_use_mic_notification_content (8063355861118105607) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_camera_notification_content (4738005643315863736) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (7921147002346108119) -->
+ <skip />
+ <!-- no translation found for sensor_privacy_notification_channel_label (936036783155261349) -->
+ <skip />
</resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index bb26655..c16588c 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2487,7 +2487,7 @@
<attr name="directBootAware" />
<attr name="visibleToInstantApps" />
<!-- The code for this component is located in the given split.
- @deprecated Do not use it. This is not supported. -->
+ <p>NOTE: This is only applicable to instant app. -->
<attr name="splitName" />
</declare-styleable>
@@ -2604,7 +2604,7 @@
<attr name="externalService" format="boolean" />
<attr name="visibleToInstantApps" />
<!-- The code for this component is located in the given split.
- @deprecated Do not use it. This is not supported. -->
+ <p>NOTE: This is only applicable to instant app. -->
<attr name="splitName" />
<!-- If true, and this is an {@link android.R.attr#isolatedProcess} service, the service
will be spawned from an Application Zygote, instead of the regular Zygote.
diff --git a/core/res/res/values/colors_device_defaults.xml b/core/res/res/values/colors_device_defaults.xml
index b558087..e46147e 100644
--- a/core/res/res/values/colors_device_defaults.xml
+++ b/core/res/res/values/colors_device_defaults.xml
@@ -33,14 +33,14 @@
<color name="tertiary_device_default_settings">@color/tertiary_material_settings</color>
<color name="quaternary_device_default_settings">@color/quaternary_material_settings</color>
- <color name="accent_device_default_light">@color/system_accent_500</color>
+ <color name="accent_device_default_light">@color/system_accent_600</color>
<color name="accent_device_default_dark">@color/system_accent_200</color>
<color name="accent_device_default">@color/accent_device_default_light</color>
<color name="background_device_default_dark">@color/system_main_900</color>
- <color name="background_device_default_light">@color/system_main_100</color>
+ <color name="background_device_default_light">@color/system_main_50</color>
<color name="background_floating_device_default_dark">@color/system_main_800</color>
- <color name="background_floating_device_default_light">@color/system_main_200</color>
+ <color name="background_floating_device_default_light">@color/system_main_100</color>
<!-- Error color -->
<color name="error_color_device_default_dark">@color/error_color_material_dark</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 79e2210..7f6053e 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1577,6 +1577,10 @@
<item>network</item>
</string-array>
+ <!-- Enables the GnssTimeUpdate service. This is the global switch for enabling Gnss time based
+ suggestions to TimeDetector service. See also config_autoTimeSourcesPriority. -->
+ <bool name="config_enableGnssTimeUpdateService">false</bool>
+
<!-- Enables the TimeZoneRuleManager service. This is the global switch for the updateable time
zone update mechanism. -->
<bool name="config_enableUpdateableTimeZoneRules">false</bool>
@@ -2649,6 +2653,11 @@
<string name="config_usbResolverActivity" translatable="false"
>com.android.systemui/com.android.systemui.usb.UsbResolverActivity</string>
+ <!-- Component name of the activity used to inform a user about a sensory being blocked because
+ of privacy settings. -->
+ <string name="config_sensorUseStartedActivity" translatable="false"
+ >com.android.systemui/com.android.systemui.sensorprivacy.SensorUseStartedActivity</string>
+
<!-- Name of the dialog that is used to request the user's consent for a Platform VPN -->
<string name="config_platformVpnConfirmDialogComponent" translatable="false"
>com.android.vpndialogs/com.android.vpndialogs.PlatformVpnConfirmDialog</string>
diff --git a/core/res/res/values/dimens_car.xml b/core/res/res/values/dimens_car.xml
index c3cd80b..0ef60c4 100644
--- a/core/res/res/values/dimens_car.xml
+++ b/core/res/res/values/dimens_car.xml
@@ -17,6 +17,7 @@
-->
<resources>
<dimen name="car_large_avatar_size">96dp</dimen>
+ <dimen name="car_large_avatar_badge_size">32dp</dimen>
<!-- Application Bar -->
<dimen name="car_app_bar_height">80dp</dimen>
<!-- Margin -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 317a76f..996fbb3 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -450,6 +450,8 @@
understand which sub-unit of an application is requesting permissions and using power.
[CHAR LIMIT=NONE]-->
<string name="offline_location_time_zone_detection_service_attribution">Time Zone Detector (No connectivity)</string>
+ <!-- Attribution for Gnss Time Update service. [CHAR LIMIT=NONE]-->
+ <string name="gnss_time_update_service">GNSS Time Update Service</string>
<!-- Factory reset warning dialog strings--> <skip />
<!-- Shows up in the dialog's title to warn about an impeding factory reset. [CHAR LIMIT=NONE] -->
@@ -5817,4 +5819,13 @@
<!-- Notification action to dismiss. [CHAR LIMIT=50] -->
<string name="dismiss_action">Dismiss</string>
+ <!--- Content of notification triggered if the microphone is disabled but an app tried to access it. [CHAR LIMIT=NONE] -->
+ <string name="sensor_privacy_start_use_mic_notification_content">To continue, <b><xliff:g id="app" example="Gmail">%s</xliff:g></b> needs access to your device microphone.</string>
+ <!--- Content of notification triggered if the camera is disabled but an app tried to access it. [CHAR LIMIT=NONE] -->
+ <string name="sensor_privacy_start_use_camera_notification_content">To continue, <b><xliff:g id="app" example="Gmail">%s</xliff:g></b> needs access to your device’s camera.</string>
+ <!--- Action button in the dialog triggered if a sensor (e.g. microphone or camera) is disabled but an app tried to access it. [CHAR LIMIT=60] -->
+ <string name="sensor_privacy_start_use_dialog_turn_on_button">Turn on</string>
+ <!--- Label for notification channel for all sensor privacy related notifications. [CHAR LIMIT=NONE] -->
+ <string name="sensor_privacy_notification_channel_label">Sensor Privacy</string>
+
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 0c86905..e2271d1 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -379,6 +379,7 @@
<java-symbol type="string" name="config_usbAccessoryUriActivity" />
<java-symbol type="string" name="config_usbConfirmActivity" />
<java-symbol type="string" name="config_usbResolverActivity" />
+ <java-symbol type="string" name="config_sensorUseStartedActivity" />
<java-symbol type="integer" name="config_minNumVisibleRecentTasks_lowRam" />
<java-symbol type="integer" name="config_maxNumVisibleRecentTasks_lowRam" />
<java-symbol type="integer" name="config_minNumVisibleRecentTasks_grid" />
@@ -2176,6 +2177,7 @@
<java-symbol type="string" name="config_persistentDataPackageName" />
<java-symbol type="string" name="config_deviceConfiguratorPackageName" />
<java-symbol type="array" name="config_autoTimeSourcesPriority" />
+ <java-symbol type="bool" name="config_enableGnssTimeUpdateService" />
<java-symbol type="bool" name="config_enableGeolocationTimeZoneDetection" />
<java-symbol type="bool" name="config_enablePrimaryLocationTimeZoneProvider" />
<java-symbol type="bool" name="config_enablePrimaryLocationTimeZoneOverlay" />
@@ -4150,4 +4152,11 @@
<java-symbol type="bool" name="config_enableBackSound" />
<java-symbol type="bool" name="config_forceOrientationListenerEnabledWhileDreaming" />
+
+ <java-symbol type="drawable" name="ic_camera_blocked" />
+ <java-symbol type="drawable" name="ic_mic_blocked" />
+ <java-symbol type="string" name="sensor_privacy_start_use_mic_notification_content" />
+ <java-symbol type="string" name="sensor_privacy_start_use_camera_notification_content" />
+ <java-symbol type="string" name="sensor_privacy_start_use_dialog_turn_on_button" />
+ <java-symbol type="string" name="sensor_privacy_notification_channel_label" />
</resources>
diff --git a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
index d8ed805..daae957 100644
--- a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
+++ b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
@@ -76,6 +76,12 @@
private static final long DUMPSTATE_STARTUP_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10);
private static final long UIAUTOMATOR_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10);
+
+ // A small timeout used when waiting for the result of a BugreportCallback to be received.
+ // This value must be at least 1000ms since there is an intentional delay in
+ // BugreportManagerServiceImpl in the error case.
+ private static final long CALLBACK_RESULT_TIMEOUT_MS = 1500;
+
// Sent by Shell when its bugreport finishes (contains final bugreport/screenshot file name
// associated with the bugreport).
private static final String INTENT_BUGREPORT_FINISHED =
@@ -185,7 +191,7 @@
ParcelFileDescriptor bugreportFd2 = parcelFd(bugreportFile2);
ParcelFileDescriptor screenshotFd2 = parcelFd(screenshotFile2);
mBrm.startBugreport(bugreportFd2, screenshotFd2, wifi(), mExecutor, callback2);
- Thread.sleep(500 /* .5s */);
+ Thread.sleep(CALLBACK_RESULT_TIMEOUT_MS);
// Verify #2 encounters an error.
assertThat(callback2.getErrorCode()).isEqualTo(
@@ -194,7 +200,7 @@
// Cancel #1 so we can move on to the next test.
mBrm.cancelBugreport();
- Thread.sleep(500 /* .5s */);
+ waitTillDoneOrTimeout(callback);
assertThat(callback.isDone()).isTrue();
assertFdsAreClosed(mBugreportFd, mScreenshotFd);
}
@@ -220,7 +226,7 @@
// Try again, with DUMP permission.
getPermissions();
mBrm.cancelBugreport();
- Thread.sleep(500 /* .5s */);
+ waitTillDoneOrTimeout(callback);
assertThat(callback.isDone()).isTrue();
assertFdsAreClosed(mBugreportFd, mScreenshotFd);
}
diff --git a/core/tests/coretests/src/android/graphics/FontFileUtilTest.java b/core/tests/coretests/src/android/graphics/FontFileUtilTest.java
index 1771671..52cc4ca 100644
--- a/core/tests/coretests/src/android/graphics/FontFileUtilTest.java
+++ b/core/tests/coretests/src/android/graphics/FontFileUtilTest.java
@@ -17,11 +17,15 @@
package android.graphics;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.content.res.AssetManager;
+import android.graphics.fonts.Font;
import android.graphics.fonts.FontFileUtil;
import android.graphics.fonts.FontVariationAxis;
+import android.graphics.fonts.SystemFonts;
import android.util.Log;
import android.util.Pair;
@@ -144,4 +148,18 @@
assertEquals(path + "#" + axes, italic, FontFileUtil.unpackItalic(packed));
}
}
+
+ @Test
+ public void testExtension() throws IOException {
+ for (Font f : SystemFonts.getAvailableFonts()) {
+ String name = f.getFile().getName();
+ if (!name.endsWith(".ttf") && !name.endsWith(".otf")) {
+ continue; // Only test ttf/otf file
+ }
+ int isOtfFile = FontFileUtil.isPostScriptType1Font(f.getBuffer(), 0);
+ assertNotEquals(-1, isOtfFile);
+ String extension = isOtfFile == 1 ? ".otf" : ".ttf";
+ assertTrue(name.endsWith(extension));
+ }
+ }
}
diff --git a/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java b/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java
index 0f17d27..6be9306 100644
--- a/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java
+++ b/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java
@@ -254,7 +254,7 @@
assertEquals("19–22 de ene. de 2009",
formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY,
FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("lun., 19 de ene. – jue., 22 de ene. de 2009",
+ assertEquals("lun, 19 de ene. – jue, 22 de ene. de 2009",
formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY,
FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
assertEquals("lunes, 19 de enero–jueves, 22 de enero de 2009",
@@ -265,7 +265,7 @@
assertEquals("19 de ene. – 22 de abr. 2009",
formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH,
FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("lun., 19 de ene. – mié., 22 de abr. de 2009",
+ assertEquals("lun, 19 de ene. – mié, 22 de abr. de 2009",
formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH,
FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
assertEquals("enero–abril de 2009",
@@ -286,9 +286,9 @@
assertEquals("19–22 de enero de 2009",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, 0));
- assertEquals("19–22 ene. 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY,
+ assertEquals("19–22 ene 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY,
FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("lun., 19 ene. – jue., 22 ene. 2009",
+ assertEquals("lun, 19 ene – jue, 22 ene 2009",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY,
FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
assertEquals("lunes, 19 de enero–jueves, 22 de enero de 2009",
@@ -296,19 +296,19 @@
assertEquals("19 de enero–22 de abril de 2009",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, 0));
- assertEquals("19 ene. – 22 abr. 2009",
+ assertEquals("19 ene – 22 abr 2009",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH,
FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("lun., 19 ene. – mié., 22 abr. 2009",
+ assertEquals("lun, 19 ene – mié, 22 abr 2009",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH,
FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
assertEquals("enero–abril de 2009",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_NO_MONTH_DAY));
- assertEquals("19 ene. 2009 – 9 feb. 2012",
+ assertEquals("19 ene 2009 – 9 feb 2012",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR,
FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("ene. 2009 – feb. 2012",
+ assertEquals("ene 2009 – feb 2012",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR,
FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL));
assertEquals("19 de enero de 2009–9 de febrero de 2012",
diff --git a/core/tests/coretests/src/android/text/format/FormatterTest.java b/core/tests/coretests/src/android/text/format/FormatterTest.java
index 068d047..5612833 100644
--- a/core/tests/coretests/src/android/text/format/FormatterTest.java
+++ b/core/tests/coretests/src/android/text/format/FormatterTest.java
@@ -212,7 +212,7 @@
// Make sure it works on different locales.
setLocale(new Locale("ru", "RU"));
- assertEquals("1 мин.", Formatter.formatShortElapsedTimeRoundingUpToMinutes(
+ assertEquals("1 мин", Formatter.formatShortElapsedTimeRoundingUpToMinutes(
mContext, 1 * SECOND));
}
diff --git a/core/tests/coretests/src/android/text/format/RelativeDateTimeFormatterTest.java b/core/tests/coretests/src/android/text/format/RelativeDateTimeFormatterTest.java
index 4b3b573..b342516 100644
--- a/core/tests/coretests/src/android/text/format/RelativeDateTimeFormatterTest.java
+++ b/core/tests/coretests/src/android/text/format/RelativeDateTimeFormatterTest.java
@@ -755,8 +755,8 @@
final Locale locale = new Locale("fr");
android.icu.text.RelativeDateTimeFormatter icuFormatter =
android.icu.text.RelativeDateTimeFormatter.getInstance(locale);
- assertEquals("D à T", icuFormatter.combineDateAndTime("D", "T"));
+ assertEquals("D, T", icuFormatter.combineDateAndTime("D", "T"));
// Ensure single quote ' and curly braces {} are not interpreted in input values.
- assertEquals("D'x' à T{0}", icuFormatter.combineDateAndTime("D'x'", "T{0}"));
+ assertEquals("D'x', T{0}", icuFormatter.combineDateAndTime("D'x'", "T{0}"));
}
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/ConversationActionTest.java b/core/tests/coretests/src/android/view/textclassifier/ConversationActionTest.java
index 07eeae0..e1b403f 100644
--- a/core/tests/coretests/src/android/view/textclassifier/ConversationActionTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/ConversationActionTest.java
@@ -39,7 +39,8 @@
@Test
public void toBuilder() {
final Context context = InstrumentationRegistry.getTargetContext();
- final PendingIntent intent = PendingIntent.getActivity(context, 0, new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED);
+ final PendingIntent intent = PendingIntent.getActivity(
+ context, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE);
final Icon icon = Icon.createWithData(new byte[]{0}, 0, 1);
final Bundle extras = new Bundle();
extras.putInt("key", 5);
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
index db62e17..c393d68 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
@@ -16,6 +16,8 @@
package android.view.textclassifier;
+import static android.app.PendingIntent.FLAG_IMMUTABLE;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -79,7 +81,7 @@
final String primaryDescription = "primaryDescription";
final Intent primaryIntent = new Intent("primaryIntentAction");
final PendingIntent primaryPendingIntent = PendingIntent.getActivity(context, 0,
- primaryIntent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
+ primaryIntent, FLAG_IMMUTABLE);
final RemoteAction remoteAction0 = new RemoteAction(primaryIcon, primaryLabel,
primaryDescription, primaryPendingIntent);
@@ -88,7 +90,7 @@
final String secondaryDescription = "secondaryDescription";
final Intent secondaryIntent = new Intent("secondaryIntentAction");
final PendingIntent secondaryPendingIntent = PendingIntent.getActivity(context, 0,
- secondaryIntent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
+ secondaryIntent, FLAG_IMMUTABLE);
final RemoteAction remoteAction1 = new RemoteAction(secondaryIcon, secondaryLabel,
secondaryDescription, secondaryPendingIntent);
@@ -156,7 +158,7 @@
final int iconColor = Color.RED;
final String label = "label";
final PendingIntent pendingIntent = PendingIntent.getActivity(
- context, 0, new Intent("ACTION_0"), PendingIntent.FLAG_MUTABLE_UNAUDITED);
+ context, 0, new Intent("ACTION_0"), FLAG_IMMUTABLE);
final RemoteAction remoteAction = new RemoteAction(
generateTestIcon(width, height, iconColor),
label,
@@ -239,7 +241,8 @@
.setIntent(new Intent("action"))
.setOnClickListener(view -> { })
.addAction(new RemoteAction(icon1, "title1", "desc1",
- PendingIntent.getActivity(context, 0, new Intent("action1"), PendingIntent.FLAG_MUTABLE_UNAUDITED)))
+ PendingIntent.getActivity(
+ context, 0, new Intent("action1"), FLAG_IMMUTABLE)))
.addAction(new RemoteAction(icon1, "title2", "desc2",
PendingIntent.getActivity(context, 0, new Intent("action2"), 0)))
.setEntityType(TextClassifier.TYPE_EMAIL, 0.5f)
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java b/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java
index 5def552..14c077c 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java
@@ -16,6 +16,8 @@
package android.view.textclassifier;
+import static android.app.PendingIntent.FLAG_IMMUTABLE;
+
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
@@ -128,7 +130,8 @@
final TextClassification classification = new TextClassification.Builder()
.addAction(new RemoteAction(icon1, "title1", "desc1",
- PendingIntent.getActivity(context, 0, new Intent("action1"), 0)))
+ PendingIntent.getActivity(
+ context, 0, new Intent("action1"), FLAG_IMMUTABLE)))
.setEntityType(TextClassifier.TYPE_ADDRESS, 1.0f)
.build();
final TextSelection textSelection = new TextSelection.Builder(startIndex, endIndex)
diff --git a/core/tests/coretests/src/android/view/textservice/OWNERS b/core/tests/coretests/src/android/view/textservice/OWNERS
new file mode 100644
index 0000000..0471e29
--- /dev/null
+++ b/core/tests/coretests/src/android/view/textservice/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 816455
+
+include /services/core/java/com/android/server/textservices/OWNERS
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
index 8ff318e..143e07a 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -46,6 +46,7 @@
BstatsCpuTimesValidationTest.class,
CameraPowerCalculatorTest.class,
FlashlightPowerCalculatorTest.class,
+ GnssPowerCalculatorTest.class,
IdlePowerCalculatorTest.class,
KernelCpuProcStringReaderTest.class,
KernelCpuUidActiveTimeReaderTest.class,
@@ -58,9 +59,11 @@
KernelWakelockReaderTest.class,
LongSamplingCounterTest.class,
LongSamplingCounterArrayTest.class,
+ MobileRadioPowerCalculatorTest.class,
PowerCalculatorTest.class,
PowerProfileTest.class,
ScreenPowerCalculatorTest.class,
+ SensorPowerCalculatorTest.class,
SystemServicePowerCalculatorTest.class,
VideoPowerCalculatorTest.class,
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
index 55f64f9..59534e4 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
@@ -16,10 +16,13 @@
package com.android.internal.os;
+import static org.mockito.ArgumentMatchers.anyDouble;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.net.NetworkStats;
import android.os.BatteryStats;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
@@ -32,6 +35,7 @@
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
+import org.mockito.stubbing.Answer;
public class BatteryUsageStatsRule implements TestRule {
private final PowerProfile mPowerProfile;
@@ -53,6 +57,14 @@
public BatteryUsageStatsRule setAveragePower(String key, double value) {
when(mPowerProfile.getAveragePower(key)).thenReturn(value);
+ when(mPowerProfile.getAveragePowerOrDefault(eq(key), anyDouble())).thenReturn(value);
+ return this;
+ }
+
+ public BatteryUsageStatsRule setAveragePowerUnspecified(String key) {
+ when(mPowerProfile.getAveragePower(key)).thenReturn(0.0);
+ when(mPowerProfile.getAveragePowerOrDefault(eq(key), anyDouble()))
+ .thenAnswer((Answer<Double>) invocation -> (Double) invocation.getArguments()[1]);
return this;
}
@@ -64,6 +76,10 @@
return this;
}
+ public void setNetworkStats(NetworkStats networkStats) {
+ mBatteryStats.setNetworkStats(networkStats);
+ }
+
@Override
public Statement apply(Statement base, Description description) {
return new Statement() {
@@ -76,6 +92,7 @@
}
private void noteOnBattery() {
+ mBatteryStats.setOnBatteryInternal(true);
mBatteryStats.getOnBatteryTimeBase().setRunning(true, 0, 0);
}
diff --git a/core/tests/coretests/src/com/android/internal/os/GnssPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/GnssPowerCalculatorTest.java
new file mode 100644
index 0000000..bd7f1e2
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/GnssPowerCalculatorTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.BatteryConsumer;
+import android.os.Process;
+import android.os.UidBatteryConsumer;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class GnssPowerCalculatorTest {
+ private static final double PRECISION = 0.00001;
+
+ private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
+
+ @Rule
+ public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
+ .setAveragePower(PowerProfile.POWER_GPS_ON, 360.0)
+ .setAveragePower(PowerProfile.POWER_GPS_SIGNAL_QUALITY_BASED,
+ new double[] {720.0, 1440.0, 1800.0});
+
+ @Test
+ public void testTimerBasedModel() {
+ BatteryStatsImpl.Uid uidStats = mStatsRule.getUidStats(APP_UID);
+ uidStats.noteStartGps(1000);
+ uidStats.noteStopGps(2000);
+
+ GnssPowerCalculator calculator =
+ new GnssPowerCalculator(mStatsRule.getPowerProfile());
+
+ mStatsRule.apply(calculator);
+
+ UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID);
+ assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_GNSS))
+ .isEqualTo(1000);
+ assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_GNSS))
+ .isWithin(PRECISION).of(0.1);
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java
new file mode 100644
index 0000000..4230066
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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.internal.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.net.ConnectivityManager;
+import android.net.NetworkStats;
+import android.os.BatteryConsumer;
+import android.os.Process;
+import android.os.SystemBatteryConsumer;
+import android.os.UidBatteryConsumer;
+import android.telephony.DataConnectionRealTimeInfo;
+import android.telephony.ModemActivityInfo;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+import android.telephony.TelephonyManager;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class MobileRadioPowerCalculatorTest {
+ private static final double PRECISION = 0.00001;
+ private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
+
+ @Rule
+ public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
+ .setAveragePowerUnspecified(PowerProfile.POWER_RADIO_ACTIVE)
+ .setAveragePowerUnspecified(PowerProfile.POWER_RADIO_ON)
+ .setAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_IDLE, 360.0)
+ .setAveragePower(PowerProfile.POWER_RADIO_SCANNING, 720.0)
+ .setAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_RX, 1440.0)
+ .setAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_TX,
+ new double[] {720.0, 1080.0, 1440.0, 1800.0, 2160.0});
+
+ @Test
+ public void testCounterBasedModel() {
+ BatteryStatsImpl stats = mStatsRule.getBatteryStats();
+
+ // Scan for a cell
+ stats.notePhoneStateLocked(ServiceState.STATE_OUT_OF_SERVICE,
+ TelephonyManager.SIM_STATE_READY,
+ 2000, 2000);
+
+ // Found a cell
+ stats.notePhoneStateLocked(ServiceState.STATE_IN_SERVICE, TelephonyManager.SIM_STATE_READY,
+ 5000, 5000);
+
+ // Note cell signal strength
+ SignalStrength signalStrength = mock(SignalStrength.class);
+ when(signalStrength.getLevel()).thenReturn(SignalStrength.SIGNAL_STRENGTH_MODERATE);
+ stats.notePhoneSignalStrengthLocked(signalStrength, 5000, 5000);
+
+ stats.noteMobileRadioPowerStateLocked(DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH,
+ 8_000_000_000L, APP_UID, 8000, 8000);
+
+ // Note established network
+ stats.noteNetworkInterfaceType("cellular", ConnectivityManager.TYPE_MOBILE);
+
+ // Note application network activity
+ NetworkStats networkStats = new NetworkStats(10000, 1)
+ .insertEntry("cellular", APP_UID, 0, 0, 1000, 100, 2000, 20, 100);
+ mStatsRule.setNetworkStats(networkStats);
+
+ ModemActivityInfo mai = new ModemActivityInfo(10000, 2000, 3000,
+ new int[] {100, 200, 300, 400, 500}, 600);
+ stats.noteModemControllerActivity(mai, 10000, 10000);
+
+ mStatsRule.setTime(12_000_000, 12_000_000);
+
+ MobileRadioPowerCalculator calculator =
+ new MobileRadioPowerCalculator(mStatsRule.getPowerProfile());
+
+ mStatsRule.apply(calculator);
+
+ SystemBatteryConsumer consumer =
+ mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_MOBILE_RADIO);
+ assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
+ .isWithin(PRECISION).of(1.44440);
+
+ UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
+ assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
+ .isWithin(PRECISION).of(0.8);
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index fc23721..bf74c8d 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -16,7 +16,7 @@
package com.android.internal.os;
-import android.location.GnssSignalQuality;
+import android.net.NetworkStats;
import android.os.Handler;
import android.os.Looper;
import android.util.SparseIntArray;
@@ -38,26 +38,14 @@
public class MockBatteryStatsImpl extends BatteryStatsImpl {
public BatteryStatsImpl.Clocks clocks;
public boolean mForceOnBattery;
+ private NetworkStats mNetworkStats;
MockBatteryStatsImpl(Clocks clocks) {
super(clocks);
this.clocks = mClocks;
- mScreenOnTimer = new BatteryStatsImpl.StopwatchTimer(clocks, null, -1, null,
- mOnBatteryTimeBase);
- mScreenDozeTimer = new BatteryStatsImpl.StopwatchTimer(clocks, null, -1, null,
- mOnBatteryTimeBase);
- for (int i = 0; i < mScreenBrightnessTimer.length; i++) {
- mScreenBrightnessTimer[i] = new BatteryStatsImpl.StopwatchTimer(clocks, null, -1, null,
- mOnBatteryTimeBase);
- }
- mBluetoothScanTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase);
- mBluetoothActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase, 1);
- setExternalStatsSyncLocked(new DummyExternalStatsSync());
+ initTimersAndCounters();
- for (int i = 0; i < GnssSignalQuality.NUM_GNSS_SIGNAL_QUALITY_LEVELS; i++) {
- mGpsSignalQualityTimer[i] = new StopwatchTimer(clocks, null, -1000 - i, null,
- mOnBatteryTimeBase);
- }
+ setExternalStatsSyncLocked(new DummyExternalStatsSync());
final boolean[] supportedBuckets = new boolean[MeasuredEnergyStats.NUMBER_ENERGY_BUCKETS];
Arrays.fill(supportedBuckets, true);
@@ -106,6 +94,16 @@
return getUidStatsLocked(uid).mOnBatteryScreenOffBackgroundTimeBase;
}
+ public MockBatteryStatsImpl setNetworkStats(NetworkStats networkStats) {
+ mNetworkStats = networkStats;
+ return this;
+ }
+
+ @Override
+ protected NetworkStats readNetworkStatsLocked(String[] ifaces) {
+ return mNetworkStats;
+ }
+
public MockBatteryStatsImpl setPowerProfile(PowerProfile powerProfile) {
mPowerProfile = powerProfile;
return this;
diff --git a/core/tests/coretests/src/com/android/internal/os/SensorPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/SensorPowerCalculatorTest.java
new file mode 100644
index 0000000..b50435b
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/SensorPowerCalculatorTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.internal.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.hardware.Sensor;
+import android.hardware.SensorManager;
+import android.hardware.input.InputSensorInfo;
+import android.os.BatteryConsumer;
+import android.os.Process;
+import android.os.UidBatteryConsumer;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class SensorPowerCalculatorTest {
+ private static final double PRECISION = 0.00001;
+
+ private static final int SENSOR_HANDLE_1 = 1;
+ private static final int SENSOR_HANDLE_2 = 2;
+
+ private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
+
+ @Rule
+ public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule();
+
+ @Test
+ public void testTimerBasedModel() {
+ Sensor sensor1 = createSensor(SENSOR_HANDLE_1, Sensor.TYPE_AMBIENT_TEMPERATURE, 360);
+ Sensor sensor2 = createSensor(SENSOR_HANDLE_2, Sensor.TYPE_STEP_COUNTER, 720);
+
+ SensorManager sensorManager = mock(SensorManager.class);
+ when(sensorManager.getSensorList(Sensor.TYPE_ALL))
+ .thenReturn(List.of(sensor1, sensor2));
+
+ BatteryStatsImpl.Uid uidStats = mStatsRule.getUidStats(APP_UID);
+ uidStats.noteStartSensor(SENSOR_HANDLE_1, 1000);
+ uidStats.noteStopSensor(SENSOR_HANDLE_1, 2000);
+ uidStats.noteStartSensor(SENSOR_HANDLE_2, 3000);
+ uidStats.noteStopSensor(SENSOR_HANDLE_2, 5000);
+
+ SensorPowerCalculator calculator = new SensorPowerCalculator(sensorManager);
+
+ mStatsRule.apply(calculator);
+
+ UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID);
+ assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SENSORS))
+ .isEqualTo(3000);
+ assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SENSORS))
+ .isWithin(PRECISION).of(0.5);
+ }
+
+ private Sensor createSensor(int handle, int type, double power) {
+ return new Sensor(new InputSensorInfo("name", "vendor", 0 /* version */,
+ handle, type, 100.0f /*maxRange */, 0.02f /* resolution */,
+ (float) power, 1000 /* minDelay */, 0 /* fifoReservedEventCount */,
+ 0 /* fifoMaxEventCount */, "" /* stringType */, "" /* requiredPermission */,
+ 0 /* maxDelay */, 0 /* flags */, 0 /* id */));
+ }
+}
diff --git a/core/tests/overlaytests/device/Android.bp b/core/tests/overlaytests/device/Android.bp
index 12a2b08..f86ac9c 100644
--- a/core/tests/overlaytests/device/Android.bp
+++ b/core/tests/overlaytests/device/Android.bp
@@ -16,7 +16,11 @@
name: "OverlayDeviceTests",
srcs: ["src/**/*.java"],
platform_apis: true,
- static_libs: ["androidx.test.rules"],
+ certificate: "platform",
+ static_libs: [
+ "androidx.test.rules",
+ "testng",
+ ],
test_suites: ["device-tests"],
data: [
":OverlayDeviceTests_AppOverlayOne",
diff --git a/core/tests/overlaytests/device/AndroidManifest.xml b/core/tests/overlaytests/device/AndroidManifest.xml
index 4881636..a69911f 100644
--- a/core/tests/overlaytests/device/AndroidManifest.xml
+++ b/core/tests/overlaytests/device/AndroidManifest.xml
@@ -19,6 +19,8 @@
<uses-sdk android:minSdkVersion="21" />
+ <uses-permission android:name="android.permission.CHANGE_OVERLAY_PACKAGES" />
+
<application>
<uses-library android:name="android.test.runner"/>
</application>
diff --git a/core/tests/overlaytests/device/AndroidTest.xml b/core/tests/overlaytests/device/AndroidTest.xml
index 6507839..ebbdda5 100644
--- a/core/tests/overlaytests/device/AndroidTest.xml
+++ b/core/tests/overlaytests/device/AndroidTest.xml
@@ -19,9 +19,20 @@
<option name="test-suite-tag" value="apct" />
<option name="test-suite-tag" value="apct-instrumentation" />
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="cleanup" value="true" />
+ <option name="remount-system" value="true" />
+ <option name="push" value="OverlayDeviceTests.apk->/system/app/OverlayDeviceTests.apk" />
+ </target_preparer>
+
+ <!-- Reboot to have the test APK scanned by PM and reboot after to remove the test APK. -->
+ <target_preparer class="com.android.tradefed.targetprep.RebootTargetPreparer">
+ <option name="pre-reboot" value="true" />
+ <option name="post-reboot" value="true" />
+ </target_preparer>
+
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
<option name="cleanup-apks" value="true" />
- <option name="test-file-name" value="OverlayDeviceTests.apk" />
<option name="test-file-name" value="OverlayDeviceTests_AppOverlayOne.apk" />
<option name="test-file-name" value="OverlayDeviceTests_AppOverlayTwo.apk" />
<option name="test-file-name" value="OverlayDeviceTests_FrameworkOverlay.apk" />
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/LocalOverlayManager.java b/core/tests/overlaytests/device/src/com/android/overlaytest/LocalOverlayManager.java
index 390bb76..76c01a7 100644
--- a/core/tests/overlaytests/device/src/com/android/overlaytest/LocalOverlayManager.java
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/LocalOverlayManager.java
@@ -18,60 +18,76 @@
import static java.util.concurrent.TimeUnit.SECONDS;
-import android.app.UiAutomation;
-import android.content.res.Resources;
-import android.os.ParcelFileDescriptor;
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.om.OverlayManager;
+import android.content.om.OverlayManagerTransaction;
+import android.os.UserHandle;
import androidx.test.InstrumentationRegistry;
-import java.io.BufferedReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
import java.util.concurrent.Executor;
import java.util.concurrent.FutureTask;
class LocalOverlayManager {
private static final long TIMEOUT = 30;
- public static void setEnabledAndWait(Executor executor, final String packageName,
- boolean enable) throws Exception {
- final String pattern = (enable ? "[x]" : "[ ]") + " " + packageName;
- if (executeShellCommand("cmd overlay list").contains(pattern)) {
- // nothing to do, overlay already in the requested state
- return;
+ public static void toggleOverlaysAndWait(@NonNull final String[] overlaysToEnable,
+ @NonNull final String[] overlaysToDisable) throws Exception {
+ final int userId = UserHandle.myUserId();
+ OverlayManagerTransaction.Builder builder = new OverlayManagerTransaction.Builder();
+ for (String pkg : overlaysToEnable) {
+ builder.setEnabled(pkg, true, userId);
}
+ for (String pkg : overlaysToDisable) {
+ builder.setEnabled(pkg, false, userId);
+ }
+ OverlayManagerTransaction transaction = builder.build();
- final Resources res = InstrumentationRegistry.getContext().getResources();
- final String[] oldApkPaths = res.getAssets().getApkPaths();
+ final Context ctx = InstrumentationRegistry.getTargetContext();
FutureTask<Boolean> task = new FutureTask<>(() -> {
while (true) {
- if (!Arrays.equals(oldApkPaths, res.getAssets().getApkPaths())) {
+ final String[] paths = ctx.getResources().getAssets().getApkPaths();
+ if (arrayTailContains(paths, overlaysToEnable)
+ && arrayDoesNotContain(paths, overlaysToDisable)) {
return true;
}
Thread.sleep(10);
}
});
+
+ OverlayManager om = ctx.getSystemService(OverlayManager.class);
+ om.commit(transaction);
+
+ Executor executor = (cmd) -> new Thread(cmd).start();
executor.execute(task);
- executeShellCommand("cmd overlay " + (enable ? "enable " : "disable ") + packageName);
task.get(TIMEOUT, SECONDS);
}
- private static String executeShellCommand(final String command)
- throws Exception {
- final UiAutomation uiAutomation =
- InstrumentationRegistry.getInstrumentation().getUiAutomation();
- final ParcelFileDescriptor pfd = uiAutomation.executeShellCommand(command);
- try (InputStream in = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
- final BufferedReader reader = new BufferedReader(
- new InputStreamReader(in, StandardCharsets.UTF_8));
- StringBuilder str = new StringBuilder();
- String line;
- while ((line = reader.readLine()) != null) {
- str.append(line);
- }
- return str.toString();
+ private static boolean arrayTailContains(@NonNull final String[] array,
+ @NonNull final String[] substrings) {
+ if (array.length < substrings.length) {
+ return false;
}
+ for (int i = 0; i < substrings.length; i++) {
+ String a = array[array.length - substrings.length + i];
+ String s = substrings[i];
+ if (!a.contains(s)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static boolean arrayDoesNotContain(@NonNull final String[] array,
+ @NonNull final String[] substrings) {
+ for (String s : substrings) {
+ for (String a : array) {
+ if (a.contains(s)) {
+ return false;
+ }
+ }
+ }
+ return true;
}
}
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/TransactionTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/TransactionTest.java
new file mode 100644
index 0000000..0b4f5e2
--- /dev/null
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/TransactionTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.overlaytest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.testng.Assert.assertThrows;
+
+import android.content.Context;
+import android.content.om.OverlayInfo;
+import android.content.om.OverlayManager;
+import android.content.om.OverlayManagerTransaction;
+import android.content.res.Resources;
+import android.os.UserHandle;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.List;
+
+@RunWith(JUnit4.class)
+@MediumTest
+public class TransactionTest {
+ static final String APP_OVERLAY_ONE_PKG = "com.android.overlaytest.app_overlay_one";
+ static final String APP_OVERLAY_TWO_PKG = "com.android.overlaytest.app_overlay_two";
+
+ private Context mContext;
+ private Resources mResources;
+ private OverlayManager mOverlayManager;
+ private int mUserId;
+ private UserHandle mUserHandle;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getContext();
+ mResources = mContext.getResources();
+ mOverlayManager = mContext.getSystemService(OverlayManager.class);
+ mUserId = UserHandle.myUserId();
+ mUserHandle = UserHandle.of(mUserId);
+
+ LocalOverlayManager.toggleOverlaysAndWait(
+ new String[]{},
+ new String[]{APP_OVERLAY_ONE_PKG, APP_OVERLAY_TWO_PKG});
+ }
+
+ @Test
+ public void testValidTransaction() throws Exception {
+ assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, false, mUserId);
+ assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, false, mUserId);
+
+ OverlayManagerTransaction t = new OverlayManagerTransaction.Builder()
+ .setEnabled(APP_OVERLAY_ONE_PKG, true)
+ .setEnabled(APP_OVERLAY_TWO_PKG, true)
+ .build();
+ mOverlayManager.commit(t);
+
+ assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, true, mUserId);
+ assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, true, mUserId);
+ List<OverlayInfo> ois =
+ mOverlayManager.getOverlayInfosForTarget("com.android.overlaytest", mUserHandle);
+ assertEquals(ois.size(), 2);
+ assertEquals(ois.get(0).packageName, APP_OVERLAY_ONE_PKG);
+ assertEquals(ois.get(1).packageName, APP_OVERLAY_TWO_PKG);
+
+ OverlayManagerTransaction t2 = new OverlayManagerTransaction.Builder()
+ .setEnabled(APP_OVERLAY_TWO_PKG, true)
+ .setEnabled(APP_OVERLAY_ONE_PKG, true)
+ .build();
+ mOverlayManager.commit(t2);
+
+ assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, true, mUserId);
+ assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, true, mUserId);
+ List<OverlayInfo> ois2 =
+ mOverlayManager.getOverlayInfosForTarget("com.android.overlaytest", mUserHandle);
+ assertEquals(ois2.size(), 2);
+ assertEquals(ois2.get(0).packageName, APP_OVERLAY_TWO_PKG);
+ assertEquals(ois2.get(1).packageName, APP_OVERLAY_ONE_PKG);
+
+ OverlayManagerTransaction t3 = new OverlayManagerTransaction.Builder()
+ .setEnabled(APP_OVERLAY_TWO_PKG, false)
+ .build();
+ mOverlayManager.commit(t3);
+
+ assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, true, mUserId);
+ assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, false, mUserId);
+ List<OverlayInfo> ois3 =
+ mOverlayManager.getOverlayInfosForTarget("com.android.overlaytest", mUserHandle);
+ assertEquals(ois3.size(), 2);
+ assertEquals(ois3.get(0).packageName, APP_OVERLAY_TWO_PKG);
+ assertEquals(ois3.get(1).packageName, APP_OVERLAY_ONE_PKG);
+ }
+
+ @Test
+ public void testInvalidRequestHasNoEffect() {
+ assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, false, mUserId);
+ assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, false, mUserId);
+
+ OverlayManagerTransaction t = new OverlayManagerTransaction.Builder()
+ .setEnabled(APP_OVERLAY_ONE_PKG, true)
+ .setEnabled("does-not-exist", true)
+ .setEnabled(APP_OVERLAY_TWO_PKG, true)
+ .build();
+ assertThrows(SecurityException.class, () -> mOverlayManager.commit(t));
+
+ assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, false, mUserId);
+ assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, false, mUserId);
+ }
+
+ private void assertOverlayIsEnabled(final String packageName, boolean enabled, int userId) {
+ final OverlayInfo oi = mOverlayManager.getOverlayInfo(packageName, UserHandle.of(userId));
+ assertNotNull(oi);
+ assertEquals(oi.isEnabled(), enabled);
+ }
+}
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java
index d28c47d..420f755 100644
--- a/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java
@@ -22,8 +22,6 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import java.util.concurrent.Executor;
-
@RunWith(JUnit4.class)
@MediumTest
public class WithMultipleOverlaysTest extends OverlayBaseTest {
@@ -33,9 +31,8 @@
@BeforeClass
public static void enableOverlay() throws Exception {
- Executor executor = (cmd) -> new Thread(cmd).start();
- LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_ONE_PKG, true);
- LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_TWO_PKG, true);
- LocalOverlayManager.setEnabledAndWait(executor, FRAMEWORK_OVERLAY_PKG, true);
+ LocalOverlayManager.toggleOverlaysAndWait(
+ new String[]{FRAMEWORK_OVERLAY_PKG, APP_OVERLAY_ONE_PKG, APP_OVERLAY_TWO_PKG},
+ new String[]{});
}
}
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java
index 6566ad3..a86255e 100644
--- a/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java
@@ -22,8 +22,6 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import java.util.concurrent.Executor;
-
@RunWith(JUnit4.class)
@MediumTest
public class WithOverlayTest extends OverlayBaseTest {
@@ -32,10 +30,9 @@
}
@BeforeClass
- public static void enableOverlay() throws Exception {
- Executor executor = (cmd) -> new Thread(cmd).start();
- LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_ONE_PKG, true);
- LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_TWO_PKG, false);
- LocalOverlayManager.setEnabledAndWait(executor, FRAMEWORK_OVERLAY_PKG, true);
+ public static void enableOverlays() throws Exception {
+ LocalOverlayManager.toggleOverlaysAndWait(
+ new String[]{FRAMEWORK_OVERLAY_PKG, APP_OVERLAY_ONE_PKG},
+ new String[]{APP_OVERLAY_TWO_PKG});
}
}
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java
index 48cfeab..51c4118 100644
--- a/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java
@@ -22,8 +22,6 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import java.util.concurrent.Executor;
-
@RunWith(JUnit4.class)
@MediumTest
public class WithoutOverlayTest extends OverlayBaseTest {
@@ -33,9 +31,8 @@
@BeforeClass
public static void disableOverlays() throws Exception {
- Executor executor = (cmd) -> new Thread(cmd).start();
- LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_ONE_PKG, false);
- LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_TWO_PKG, false);
- LocalOverlayManager.setEnabledAndWait(executor, FRAMEWORK_OVERLAY_PKG, false);
+ LocalOverlayManager.toggleOverlaysAndWait(
+ new String[]{},
+ new String[]{FRAMEWORK_OVERLAY_PKG, APP_OVERLAY_ONE_PKG, APP_OVERLAY_TWO_PKG});
}
}
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp
index da3aa00..847b491 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp
@@ -15,6 +15,6 @@
android_test {
name: "OverlayDeviceTests_AppOverlayOne",
sdk_version: "current",
-
+ certificate: "platform",
aaptflags: ["--no-resource-removal"],
}
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp
index 215b66da3..7d5f82a 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp
@@ -15,6 +15,6 @@
android_test {
name: "OverlayDeviceTests_AppOverlayTwo",
sdk_version: "current",
-
+ certificate: "platform",
aaptflags: ["--no-resource-removal"],
}
diff --git a/data/etc/car/Android.bp b/data/etc/car/Android.bp
index 7f20b3b..41a6fea 100644
--- a/data/etc/car/Android.bp
+++ b/data/etc/car/Android.bp
@@ -122,13 +122,6 @@
}
prebuilt_etc {
- name: "allowed_privapp_com.android.car.companiondevicesupport",
- sub_dir: "permissions",
- src: "com.android.car.companiondevicesupport.xml",
- filename_from_src: true,
-}
-
-prebuilt_etc {
name: "allowed_privapp_com.google.android.car.kitchensink",
sub_dir: "permissions",
src: "com.google.android.car.kitchensink.xml",
diff --git a/data/etc/car/com.android.car.companiondevicesupport.xml b/data/etc/car/com.android.car.companiondevicesupport.xml
deleted file mode 100644
index 2067bab..0000000
--- a/data/etc/car/com.android.car.companiondevicesupport.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<permissions>
- <privapp-permissions package="com.android.car.companiondevicesupport">
- <permission name="android.permission.INTERACT_ACROSS_USERS"/>
- <permission name="android.permission.MANAGE_USERS"/>
- <permission name="android.permission.PROVIDE_TRUST_AGENT"/>
- <permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"/>
- </privapp-permissions>
-</permissions>
diff --git a/data/etc/com.android.cellbroadcastreceiver.xml b/data/etc/com.android.cellbroadcastreceiver.xml
index ef49bfa..01a28a8 100644
--- a/data/etc/com.android.cellbroadcastreceiver.xml
+++ b/data/etc/com.android.cellbroadcastreceiver.xml
@@ -16,6 +16,7 @@
-->
<permissions>
<privapp-permissions package="com.android.cellbroadcastreceiver">
+ <permission name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS"/>
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
<permission name="android.permission.MANAGE_USERS"/>
<permission name="android.permission.MODIFY_PHONE_STATE"/>
diff --git a/data/etc/com.android.launcher3.xml b/data/etc/com.android.launcher3.xml
index 17d614e..99c38db 100644
--- a/data/etc/com.android.launcher3.xml
+++ b/data/etc/com.android.launcher3.xml
@@ -20,5 +20,6 @@
<permission name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"/>
<permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+ <permission name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS"/>
</privapp-permissions>
</permissions>
diff --git a/data/etc/preinstalled-packages-platform.xml b/data/etc/preinstalled-packages-platform.xml
index 6255584..ff8d96d 100644
--- a/data/etc/preinstalled-packages-platform.xml
+++ b/data/etc/preinstalled-packages-platform.xml
@@ -17,9 +17,8 @@
<!--
This XML file declares which system packages should be initially installed for new users based on
their user type. All system packages on the device should ideally have an entry in an xml file
-(keyed by its manifest name), except auto-generated rro packages. Auto-generated RRO packages
-(package name ends with ".auto_generated_rro_product__" or ".auto_generated_rro_vendor__")
-will be installed for new users according to corresponding overlay target packages.
+(keyed by its manifest name), except for static overlays which are instead treated automatically
+according to the entry for their corresponding overlay target package.
Base user-types (every user will be at least one of these types) are:
SYSTEM (user 0)
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index c3d822c..69b919c 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -46,6 +46,7 @@
</privapp-permissions>
<privapp-permissions package="com.android.cellbroadcastreceiver.module">
+ <permission name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS"/>
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
<permission name="android.permission.MANAGE_USERS"/>
<permission name="android.permission.MODIFY_PHONE_STATE"/>
diff --git a/graphics/java/android/graphics/BLASTBufferQueue.java b/graphics/java/android/graphics/BLASTBufferQueue.java
index 4914336..3aaf11c 100644
--- a/graphics/java/android/graphics/BLASTBufferQueue.java
+++ b/graphics/java/android/graphics/BLASTBufferQueue.java
@@ -28,11 +28,12 @@
public long mNativeObject; // BLASTBufferQueue*
private static native long nativeCreate(String name, long surfaceControl, long width,
- long height, boolean tripleBufferingEnabled);
+ long height, int format, boolean tripleBufferingEnabled);
private static native void nativeDestroy(long ptr);
private static native Surface nativeGetSurface(long ptr, boolean includeSurfaceControlHandle);
private static native void nativeSetNextTransaction(long ptr, long transactionPtr);
- private static native void nativeUpdate(long ptr, long surfaceControl, long width, long height);
+ private static native void nativeUpdate(long ptr, long surfaceControl, long width, long height,
+ int format);
private static native void nativeFlushShadowQueue(long ptr);
private static native void nativeMergeWithNextTransaction(long ptr, long transactionPtr,
long frameNumber);
@@ -52,8 +53,9 @@
/** Create a new connection with the surface flinger. */
public BLASTBufferQueue(String name, SurfaceControl sc, int width, int height,
- boolean tripleBufferingEnabled) {
- mNativeObject = nativeCreate(name, sc.mNativeObject, width, height, tripleBufferingEnabled);
+ @PixelFormat.Format int format, boolean tripleBufferingEnabled) {
+ mNativeObject = nativeCreate(name, sc.mNativeObject, width, height, format,
+ tripleBufferingEnabled);
}
public void destroy() {
@@ -85,8 +87,15 @@
nativeSetNextTransaction(mNativeObject, t == null ? 0 : t.mNativeObject);
}
- public void update(SurfaceControl sc, int width, int height) {
- nativeUpdate(mNativeObject, sc.mNativeObject, width, height);
+ /**
+ * Updates {@link SurfaceControl}, size, and format for a particular BLASTBufferQueue
+ * @param sc The new SurfaceControl that this BLASTBufferQueue will update
+ * @param width The new width for the buffer.
+ * @param height The new height for the buffer.
+ * @param format The new format for the buffer.
+ */
+ public void update(SurfaceControl sc, int width, int height, @PixelFormat.Format int format) {
+ nativeUpdate(mNativeObject, sc.mNativeObject, width, height, format);
}
/**
diff --git a/graphics/java/android/graphics/fonts/FontFileUtil.java b/graphics/java/android/graphics/fonts/FontFileUtil.java
index 2896c46..af49619 100644
--- a/graphics/java/android/graphics/fonts/FontFileUtil.java
+++ b/graphics/java/android/graphics/fonts/FontFileUtil.java
@@ -166,6 +166,23 @@
return nGetFontPostScriptName(buffer, index);
}
+ /**
+ * Analyze name OpenType table and return true if the font has PostScript Type 1 glyphs.
+ *
+ * IllegalArgumentException will be thrown for invalid font data.
+ * -1 will be returned if the byte buffer is not a OpenType font data.
+ * 0 will be returned if the font file doesn't have PostScript Type 1 glyphs, i.e. ttf file.
+ * 1 will be returned if the font file has PostScript Type 1 glyphs, i.e. otf file.
+ *
+ * @param buffer a buffer of OpenType font
+ * @param index a font index
+ * @return a post script name or null if it is invalid or not found.
+ */
+ public static int isPostScriptType1Font(@NonNull ByteBuffer buffer,
+ @IntRange(from = 0) int index) {
+ return nIsPostScriptType1Font(buffer, index);
+ }
+
@FastNative
private static native long nGetFontRevision(@NonNull ByteBuffer buffer,
@IntRange(from = 0) int index);
@@ -173,4 +190,8 @@
@FastNative
private static native String nGetFontPostScriptName(@NonNull ByteBuffer buffer,
@IntRange(from = 0) int index);
+
+ @FastNative
+ private static native int nIsPostScriptType1Font(@NonNull ByteBuffer buffer,
+ @IntRange(from = 0) int index);
}
diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java
index 54167b4..6aa50db 100644
--- a/graphics/java/android/graphics/fonts/SystemFonts.java
+++ b/graphics/java/android/graphics/fonts/SystemFonts.java
@@ -50,9 +50,11 @@
private static final String DEFAULT_FAMILY = "sans-serif";
private static final String FONTS_XML = "/system/etc/fonts.xml";
- private static final String SYSTEM_FONT_DIR = "/system/fonts/";
+ /** @hide */
+ public static final String SYSTEM_FONT_DIR = "/system/fonts/";
private static final String OEM_XML = "/product/etc/fonts_customization.xml";
- private static final String OEM_FONT_DIR = "/product/fonts/";
+ /** @hide */
+ public static final String OEM_FONT_DIR = "/product/fonts/";
private SystemFonts() {} // Do not instansiate.
diff --git a/keystore/java/android/security/Authorization.java b/keystore/java/android/security/Authorization.java
index 1fde2b5..fcc518c 100644
--- a/keystore/java/android/security/Authorization.java
+++ b/keystore/java/android/security/Authorization.java
@@ -17,11 +17,13 @@
package android.security;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.hardware.security.keymint.HardwareAuthToken;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
import android.security.authorization.IKeystoreAuthorization;
+import android.security.authorization.LockScreenEvent;
import android.system.keystore2.ResponseCode;
import android.util.Log;
@@ -75,4 +77,31 @@
return addAuthToken(AuthTokenUtils.toHardwareAuthToken(authToken));
}
+ /**
+ * Informs keystore2 about lock screen event.
+ *
+ * @param locked - whether it is a lock (true) or unlock (false) event
+ * @param syntheticPassword - if it is an unlock event with the password, pass the synthetic
+ * password provided by the LockSettingService
+ *
+ * @return 0 if successful or a {@code ResponseCode}.
+ */
+ public int onLockScreenEvent(@NonNull boolean locked, @NonNull int userId,
+ @Nullable byte[] syntheticPassword) {
+ if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
+ try {
+ if (locked) {
+ getService().onLockScreenEvent(LockScreenEvent.LOCK, userId, null);
+ } else {
+ getService().onLockScreenEvent(LockScreenEvent.UNLOCK, userId, syntheticPassword);
+ }
+ return 0;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Can not connect to keystore", e);
+ return SYSTEM_ERROR;
+ } catch (ServiceSpecificException e) {
+ return e.errorCode;
+ }
+ }
+
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
index b43203d..0958a07 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
@@ -100,7 +100,7 @@
mSplitScreenOptional.ifPresent(SplitScreen::onOrganizerRegistered);
// Bind the splitscreen impl to the drag drop controller
- mDragAndDropController.initialize(mLegacySplitScreenOptional);
+ mDragAndDropController.initialize(mSplitScreenOptional);
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
mTransitions.register(mShellTaskOrganizer);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
index c721908..16cd3cf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
@@ -85,7 +85,7 @@
bitmapSize = positioner.bubbleBitmapSize
iconBitmapSize = (bitmapSize * 0.46f).toInt()
val bubbleSize = positioner.bubbleSize
- overflowBtn?.setLayoutParams(FrameLayout.LayoutParams(bubbleSize, bubbleSize))
+ overflowBtn?.layoutParams = FrameLayout.LayoutParams(bubbleSize, bubbleSize)
expandedView?.updateDimensions()
}
@@ -95,7 +95,7 @@
// Set overflow button accent color, dot color
val typedValue = TypedValue()
context.theme.resolveAttribute(android.R.attr.colorAccent, typedValue, true)
- val colorAccent = res.getColor(typedValue.resourceId)
+ val colorAccent = res.getColor(typedValue.resourceId, null)
overflowBtn?.drawable?.setTint(colorAccent)
dotColor = colorAccent
@@ -105,7 +105,7 @@
val nightMode = (res.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
== Configuration.UI_MODE_NIGHT_YES)
val bg = ColorDrawable(res.getColor(
- if (nightMode) R.color.bubbles_dark else R.color.bubbles_light))
+ if (nightMode) R.color.bubbles_dark else R.color.bubbles_light, null))
val fg = InsetDrawable(overflowBtn?.drawable,
bitmapSize - iconBitmapSize /* inset */)
@@ -115,7 +115,7 @@
// Update dot path
dotPath = PathParser.createPathFromPathData(
res.getString(com.android.internal.R.string.config_icon_mask))
- val scale = iconFactory.normalizer.getScale(getIconView()!!.getDrawable(),
+ val scale = iconFactory.normalizer.getScale(iconView!!.drawable,
null /* outBounds */, null /* path */, null /* outMaskShape */)
val radius = BadgedImageView.DEFAULT_PATH_SIZE / 2f
val matrix = Matrix()
@@ -176,10 +176,10 @@
overflowBtn = inflater.inflate(R.layout.bubble_overflow_button,
null /* root */, false /* attachToRoot */) as BadgedImageView
overflowBtn?.initialize(positioner)
- overflowBtn?.setContentDescription(context.resources.getString(
- R.string.bubble_overflow_button_content_description))
+ overflowBtn?.contentDescription = context.resources.getString(
+ R.string.bubble_overflow_button_content_description)
val bubbleSize = positioner.bubbleSize
- overflowBtn?.setLayoutParams(FrameLayout.LayoutParams(bubbleSize, bubbleSize))
+ overflowBtn?.layoutParams = FrameLayout.LayoutParams(bubbleSize, bubbleSize)
updateBtnTheme()
}
return overflowBtn
@@ -190,10 +190,10 @@
}
override fun getTaskId(): Int {
- return if (expandedView != null) expandedView!!.getTaskId() else INVALID_TASK_ID
+ return if (expandedView != null) expandedView!!.taskId else INVALID_TASK_ID
}
companion object {
- @JvmField val KEY = "Overflow"
+ const val KEY = "Overflow"
}
}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RelativeTouchListener.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RelativeTouchListener.kt
index b347329..a1b0dbe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RelativeTouchListener.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RelativeTouchListener.kt
@@ -18,6 +18,7 @@
import android.graphics.PointF
import android.os.Handler
+import android.os.Looper
import android.view.MotionEvent
import android.view.VelocityTracker
import android.view.View
@@ -90,7 +91,7 @@
private var touchSlop: Int = -1
private var movedEnough = false
- private val handler = Handler()
+ private val handler = Handler(Looper.myLooper()!!)
private var performedLongClick = false
@Suppress("UNCHECKED_CAST")
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt
index b4d7387..9f6dd1f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/magnetictarget/MagnetizedObject.kt
@@ -460,9 +460,9 @@
/** Plays the given vibration effect if haptics are enabled. */
@SuppressLint("MissingPermission")
- private fun vibrateIfEnabled(effect: Int) {
+ private fun vibrateIfEnabled(effectId: Int) {
if (hapticsEnabled && systemHapticsEnabled) {
- vibrator.vibrate(effect.toLong())
+ vibrator.vibrate(VibrationEffect.createPredefined(effectId))
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
index e17a943..c27c929 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
@@ -135,7 +135,7 @@
final int position = mSplitLayout.getDividePosition() + touchPos - mStartPos;
final DividerSnapAlgorithm.SnapTarget snapTarget =
- mSplitLayout.findSnapTarget(position, velocity);
+ mSplitLayout.findSnapTarget(position, velocity, false /* hardDismiss */);
mSplitLayout.snapToTarget(position, snapTarget);
break;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index d77def5..60231df 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -188,11 +188,11 @@
public void snapToTarget(int currentPosition, DividerSnapAlgorithm.SnapTarget snapTarget) {
switch (snapTarget.flag) {
case FLAG_DISMISS_START:
- mLayoutChangeListener.onSnappedToDismiss(false /* snappedToEnd */);
+ mLayoutChangeListener.onSnappedToDismiss(false /* bottomOrRight */);
mSplitWindowManager.setResizingSplits(false);
break;
case FLAG_DISMISS_END:
- mLayoutChangeListener.onSnappedToDismiss(true /* snappedToEnd */);
+ mLayoutChangeListener.onSnappedToDismiss(true /* bottomOrRight */);
mSplitWindowManager.setResizingSplits(false);
break;
default:
@@ -207,9 +207,11 @@
/**
* Returns {@link DividerSnapAlgorithm.SnapTarget} which matches passing position and velocity.
+ * If hardDismiss is set to {@code true}, it will be harder to reach dismiss target.
*/
- public DividerSnapAlgorithm.SnapTarget findSnapTarget(int position, float velocity) {
- return mDividerSnapAlgorithm.calculateSnapTarget(position, velocity);
+ public DividerSnapAlgorithm.SnapTarget findSnapTarget(int position, float velocity,
+ boolean hardDismiss) {
+ return mDividerSnapAlgorithm.calculateSnapTarget(position, velocity, hardDismiss);
}
private DividerSnapAlgorithm getSnapAlgorithm(Resources resources, Rect rootBounds) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index c8b4e10..c8938ad 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -52,7 +52,7 @@
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
+import com.android.wm.shell.splitscreen.SplitScreen;
import java.util.Optional;
@@ -66,7 +66,7 @@
private final Context mContext;
private final DisplayController mDisplayController;
- private LegacySplitScreen mLegacySplitScreen;
+ private SplitScreen mSplitScreen;
private final SparseArray<PerDisplay> mDisplayDropTargets = new SparseArray<>();
private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
@@ -76,8 +76,8 @@
mDisplayController = displayController;
}
- public void initialize(Optional<LegacySplitScreen> splitscreen) {
- mLegacySplitScreen = splitscreen.orElse(null);
+ public void initialize(Optional<SplitScreen> splitscreen) {
+ mSplitScreen = splitscreen.orElse(null);
mDisplayController.addDisplayWindowListener(this);
}
@@ -104,7 +104,7 @@
R.layout.global_drop_target, null);
rootView.setOnDragListener(this);
rootView.setVisibility(View.INVISIBLE);
- DragLayout dragLayout = new DragLayout(context, mLegacySplitScreen);
+ DragLayout dragLayout = new DragLayout(context, mSplitScreen);
rootView.addView(dragLayout,
new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
try {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
index 4043d0b..800150c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -34,6 +34,8 @@
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_LEFT;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP;
+import static com.android.wm.shell.splitscreen.SplitScreen.SIDE_STAGE_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.splitscreen.SplitScreen.SIDE_STAGE_POSITION_TOP_OR_LEFT;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
@@ -59,13 +61,12 @@
import androidx.annotation.VisibleForTesting;
import com.android.wm.shell.common.DisplayLayout;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
+import com.android.wm.shell.splitscreen.SplitScreen;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
-import java.util.function.Consumer;
/**
* The policy for handling drag and drop operations to shell.
@@ -77,22 +78,22 @@
private final Context mContext;
private final ActivityTaskManager mActivityTaskManager;
private final Starter mStarter;
- private final LegacySplitScreen mLegacySplitScreen;
+ private final SplitScreen mSplitScreen;
private final ArrayList<DragAndDropPolicy.Target> mTargets = new ArrayList<>();
private DragSession mSession;
- public DragAndDropPolicy(Context context, LegacySplitScreen legacySplitScreen) {
- this(context, ActivityTaskManager.getInstance(), legacySplitScreen,
- new DefaultStarter(context, legacySplitScreen));
+ public DragAndDropPolicy(Context context, SplitScreen splitScreen) {
+ this(context, ActivityTaskManager.getInstance(), splitScreen,
+ new DefaultStarter(context, splitScreen));
}
@VisibleForTesting
DragAndDropPolicy(Context context, ActivityTaskManager activityTaskManager,
- LegacySplitScreen legacySplitScreen, Starter starter) {
+ SplitScreen splitScreen, Starter starter) {
mContext = context;
mActivityTaskManager = activityTaskManager;
- mLegacySplitScreen = legacySplitScreen;
+ mSplitScreen = splitScreen;
mStarter = starter;
}
@@ -122,64 +123,54 @@
final int ih = h - insets.top - insets.bottom;
final int l = insets.left;
final int t = insets.top;
- final boolean isVerticalSplit = mSession.isPhone && !mSession.displayLayout.isLandscape();
- if (mSession.dragItemSupportsSplitscreen
- && mSession.runningTaskActType == ACTIVITY_TYPE_STANDARD
- && mSession.runningTaskWinMode == WINDOWING_MODE_FULLSCREEN
- && mSession.runningTaskIsResizeable) {
- // Allow splitting when there is a fullscreen standard activity running
- if (isVerticalSplit) {
- // TODO(b/169894807): For now, only allow splitting to the right/bottom until we
- // have split pairs
- mTargets.add(new Target(TYPE_FULLSCREEN,
- new Rect(l, t, l + iw, t + ih / 2),
- new Rect(l, t, l + iw, t + ih),
- new Rect(0, 0, w, h)));
- mTargets.add(new Target(TYPE_SPLIT_BOTTOM,
- new Rect(l, t + ih / 2, l + iw, t + ih),
- new Rect(l, t + ih / 2, l + iw, t + ih),
- new Rect(0, h / 2, w, h)));
- } else {
- mTargets.add(new Target(TYPE_FULLSCREEN,
- new Rect(l, t, l + iw / 2, t + ih),
- new Rect(l, t, l + iw, t + ih),
- new Rect(0, 0, w, h)));
- mTargets.add(new Target(TYPE_SPLIT_RIGHT,
- new Rect(l + iw / 2, t, l + iw, t + ih),
- new Rect(l + iw / 2, t, l + iw, t + ih),
- new Rect(w / 2, 0, w, h)));
- }
- } else if (mSession.dragItemSupportsSplitscreen
- && mLegacySplitScreen != null
- && mLegacySplitScreen.isDividerVisible()) {
+ final Rect displayRegion = new Rect(l, t, l + iw, t + ih);
+ final Rect fullscreenDrawRegion = new Rect(displayRegion);
+ final Rect fullscreenHitRegion = new Rect(displayRegion);
+ final boolean inLandscape = mSession.displayLayout.isLandscape();
+ final boolean inSplitScreen = mSplitScreen != null && mSplitScreen.isSplitScreenVisible();
+ // We allow splitting if we are already in split-screen or the running task is a standard
+ // task in fullscreen mode.
+ final boolean allowSplit = inSplitScreen
+ || (mSession.runningTaskActType == ACTIVITY_TYPE_STANDARD
+ && mSession.runningTaskWinMode == WINDOWING_MODE_FULLSCREEN);
+ if (allowSplit) {
// Already split, allow replacing existing split task
- // TODO(b/169894807): For now, only allow replacing the non-primary task until we have
- // split pairs
- final Rect secondarySplitRawBounds =
- mLegacySplitScreen.getDividerView().getNonMinimizedSplitScreenSecondaryBounds();
- final Rect secondarySplitBounds = new Rect(secondarySplitRawBounds);
- secondarySplitBounds.intersect(new Rect(l, t, l + iw, t + ih));
- if (isVerticalSplit) {
- mTargets.add(new Target(TYPE_FULLSCREEN,
- new Rect(l, t, l + iw, secondarySplitRawBounds.top),
- new Rect(l, t, l + iw, t + ih),
- new Rect(0, 0, w, secondarySplitRawBounds.top)));
+ final Rect topOrLeftBounds = new Rect();
+ final Rect bottomOrRightBounds = new Rect();
+ mSplitScreen.getStageBounds(topOrLeftBounds, bottomOrRightBounds);
+ topOrLeftBounds.intersect(displayRegion);
+ bottomOrRightBounds.intersect(displayRegion);
+
+ if (inLandscape) {
+ final Rect leftHitRegion = new Rect();
+ final Rect leftDrawRegion = topOrLeftBounds;
+ final Rect rightHitRegion = new Rect();
+ final Rect rightDrawRegion = bottomOrRightBounds;
+
+ displayRegion.splitVertically(leftHitRegion, fullscreenHitRegion, rightHitRegion);
+
+ mTargets.add(
+ new Target(TYPE_FULLSCREEN, fullscreenHitRegion, fullscreenDrawRegion));
+ mTargets.add(new Target(TYPE_SPLIT_LEFT, leftHitRegion, leftDrawRegion));
+ mTargets.add(new Target(TYPE_SPLIT_RIGHT, rightHitRegion, rightDrawRegion));
+
} else {
- mTargets.add(new Target(TYPE_FULLSCREEN,
- new Rect(l, t, secondarySplitRawBounds.left, t + ih),
- new Rect(l, t, l + iw, t + ih),
- new Rect(0, 0, w, h)));
+ final Rect topHitRegion = new Rect();
+ final Rect topDrawRegion = topOrLeftBounds;
+ final Rect bottomHitRegion = new Rect();
+ final Rect bottomDrawRegion = bottomOrRightBounds;
+
+ displayRegion.splitHorizontally(
+ topHitRegion, fullscreenHitRegion, bottomHitRegion);
+
+ mTargets.add(
+ new Target(TYPE_FULLSCREEN, fullscreenHitRegion, fullscreenDrawRegion));
+ mTargets.add(new Target(TYPE_SPLIT_TOP, topHitRegion, topDrawRegion));
+ mTargets.add(new Target(TYPE_SPLIT_BOTTOM, bottomHitRegion, bottomDrawRegion));
}
- mTargets.add(new Target(isVerticalSplit ? TYPE_SPLIT_BOTTOM : TYPE_SPLIT_RIGHT,
- new Rect(secondarySplitBounds),
- new Rect(secondarySplitBounds),
- new Rect(secondarySplitBounds)));
} else {
- // Otherwise only show the fullscreen target
- mTargets.add(new Target(TYPE_FULLSCREEN,
- new Rect(l, t, l + iw, t + ih),
- new Rect(l, t, l + iw, t + ih),
- new Rect(0, 0, w, h)));
+ // Split-screen not allowed, so only show the fullscreen target
+ mTargets.add(new Target(TYPE_FULLSCREEN, fullscreenHitRegion, fullscreenDrawRegion));
}
return mTargets;
}
@@ -208,58 +199,34 @@
final boolean isTask = description.hasMimeType(MIMETYPE_APPLICATION_TASK);
final boolean isShortcut = description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT);
final Intent dragData = mSession.dragData;
+ final boolean inSplitScreen = mSplitScreen != null && mSplitScreen.isSplitScreenVisible();
+ final boolean leftOrTop = target.type == TYPE_SPLIT_TOP || target.type == TYPE_SPLIT_LEFT;
+ final Bundle opts = dragData.hasExtra(EXTRA_ACTIVITY_OPTIONS)
+ ? dragData.getBundleExtra(EXTRA_ACTIVITY_OPTIONS)
+ : new Bundle();
- boolean deferAppLaunchUntilSplit = false;
if (target.type == TYPE_FULLSCREEN) {
- if (mLegacySplitScreen != null && mLegacySplitScreen.isDividerVisible()) {
- // If in split, remove split and launch fullscreen
- mStarter.exitSplitScreen(mSession.runningTaskId);
- } else {
- // Not in split, fall through to launch
+ // Exit split stages if needed
+ mStarter.exitSplitScreen();
+ } else if (mSplitScreen != null) {
+ // Update launch options for the split side we are targeting.
+ final int position = leftOrTop
+ ? SIDE_STAGE_POSITION_TOP_OR_LEFT : SIDE_STAGE_POSITION_BOTTOM_OR_RIGHT;
+ if (!inSplitScreen) {
+ // Update the side stage position to match where we want to launch.
+ mSplitScreen.setSideStagePosition(position);
}
- } else {
- if (mLegacySplitScreen != null && mLegacySplitScreen.isDividerVisible()) {
- // Split is already visible, just replace the task
- // TODO(b/169894807): Since we only allow replacing the non-primary target above
- // just fall through and start the activity
- } else {
- // Not in split, enter split now
- mStarter.enterSplitScreen(mSession.runningTaskId,
- target.type == TYPE_SPLIT_LEFT || target.type == TYPE_SPLIT_TOP);
- deferAppLaunchUntilSplit = true;
- }
+ mSplitScreen.updateActivityOptions(opts, position);
}
- final Runnable startAppRunnable = () -> {
- Bundle opts = dragData.hasExtra(EXTRA_ACTIVITY_OPTIONS)
- ? dragData.getBundleExtra(EXTRA_ACTIVITY_OPTIONS)
- : null;
- if (isTask) {
- mStarter.startTask(dragData.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID), opts);
- } else if (isShortcut) {
- mStarter.startShortcut(dragData.getStringExtra(EXTRA_PACKAGE_NAME),
- dragData.getStringExtra(EXTRA_SHORTCUT_ID),
- opts, dragData.getParcelableExtra(EXTRA_USER));
- } else {
- mStarter.startIntent(dragData.getParcelableExtra(EXTRA_PENDING_INTENT), opts);
- }
- };
- if (deferAppLaunchUntilSplit) {
- // TODO(b/169894807): The enterSplitScreen() call above will trigger the current task
- // into split, and we should wait for home and other tasks to be moved to
- // split-secondary before trying to launch the new secondary task. This can be removed
- // once we have app-pairs.
- mLegacySplitScreen.registerInSplitScreenListener(new Consumer<Boolean>() {
- @Override
- public void accept(Boolean inSplit) {
- if (inSplit) {
- startAppRunnable.run();
- mLegacySplitScreen.unregisterInSplitScreenListener(this);
- }
- }
- });
+ if (isTask) {
+ mStarter.startTask(dragData.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID), opts);
+ } else if (isShortcut) {
+ mStarter.startShortcut(dragData.getStringExtra(EXTRA_PACKAGE_NAME),
+ dragData.getStringExtra(EXTRA_SHORTCUT_ID),
+ opts, dragData.getParcelableExtra(EXTRA_USER));
} else {
- startAppRunnable.run();
+ mStarter.startIntent(dragData.getParcelableExtra(EXTRA_PENDING_INTENT), opts);
}
}
@@ -323,7 +290,7 @@
UserHandle user);
void startIntent(PendingIntent intent, Bundle activityOptions);
void enterSplitScreen(int taskId, boolean leftOrTop);
- void exitSplitScreen(int taskId);
+ void exitSplitScreen();
}
/**
@@ -332,17 +299,17 @@
*/
private static class DefaultStarter implements Starter {
private final Context mContext;
- private final LegacySplitScreen mLegacySplitScreen;
+ private final SplitScreen mSplitScreen;
- public DefaultStarter(Context context, LegacySplitScreen legacySplitScreen) {
+ public DefaultStarter(Context context, SplitScreen splitScreen) {
mContext = context;
- mLegacySplitScreen = legacySplitScreen;
+ mSplitScreen = splitScreen;
}
@Override
public void startTask(int taskId, Bundle activityOptions) {
try {
- ActivityTaskManager.getService().startActivityFromRecents(taskId, null);
+ ActivityTaskManager.getService().startActivityFromRecents(taskId, activityOptions);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to launch task", e);
}
@@ -372,12 +339,14 @@
@Override
public void enterSplitScreen(int taskId, boolean leftOrTop) {
- mLegacySplitScreen.splitPrimaryTask();
+ mSplitScreen.moveToSideStage(taskId,
+ leftOrTop ? SIDE_STAGE_POSITION_TOP_OR_LEFT
+ : SIDE_STAGE_POSITION_BOTTOM_OR_RIGHT);
}
@Override
- public void exitSplitScreen(int taskId) {
- mLegacySplitScreen.dismissSplitToPrimaryTask();
+ public void exitSplitScreen() {
+ mSplitScreen.exitSplitScreen();
}
}
@@ -406,19 +375,16 @@
final Rect hitRegion;
// The approximate visual region for where the task will start
final Rect drawRegion;
- // The
- final Rect dropTargetBounds;
- public Target(@Type int t, Rect hit, Rect draw, Rect drop) {
+ public Target(@Type int t, Rect hit, Rect draw) {
type = t;
hitRegion = hit;
drawRegion = draw;
- dropTargetBounds = drop;
}
@Override
public String toString() {
- return "Target {hit=" + hitRegion + " drop=" + dropTargetBounds + "}";
+ return "Target {hit=" + hitRegion + " draw=" + drawRegion + "}";
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index a56fe8d..82c4e44 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -42,7 +42,7 @@
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
+import com.android.wm.shell.splitscreen.SplitScreen;
import java.util.ArrayList;
@@ -61,7 +61,7 @@
private boolean mIsShowing;
private boolean mHasDropped;
- public DragLayout(Context context, LegacySplitScreen splitscreen) {
+ public DragLayout(Context context, SplitScreen splitscreen) {
super(context);
mPolicy = new DragAndDropPolicy(context, splitscreen);
mDisplayMargin = context.getResources().getDimensionPixelSize(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
index 552eba4..7f98965 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
@@ -38,12 +38,6 @@
private boolean mIsActive = false;
- private static final int[] CONTROLLED_ACTIVITY_TYPES = {ACTIVITY_TYPE_STANDARD};
- private static final int[] CONTROLLED_WINDOWING_MODES =
- {WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED};
- private static final int[] CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE =
- {WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED, WINDOWING_MODE_MULTI_WINDOW};
-
MainStage(ShellTaskOrganizer taskOrganizer, int displayId,
StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue) {
super(taskOrganizer, displayId, callbacks, syncQueue);
@@ -92,7 +86,7 @@
null /* newParent */,
CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE,
CONTROLLED_ACTIVITY_TYPES,
- true /* onTop */)
+ false /* onTop */)
.reorder(rootToken, false /* onTop */);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
index 5645c19..cd44e4b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
@@ -16,6 +16,8 @@
package com.android.wm.shell.splitscreen;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+
import android.app.ActivityManager;
import android.graphics.Rect;
import android.window.WindowContainerToken;
@@ -48,6 +50,17 @@
.reorder(rootToken, true);
}
+ boolean removeAllTasks(WindowContainerTransaction wct) {
+ if (mChildrenTaskInfo.size() == 0) return false;
+ wct.reparentTasks(
+ mRootTaskInfo.token,
+ null /* newParent */,
+ CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE,
+ CONTROLLED_ACTIVITY_TYPES,
+ false /* onTop */);
+ return true;
+ }
+
boolean removeTask(int taskId, WindowContainerToken newParent, WindowContainerTransaction wct) {
final ActivityManager.RunningTaskInfo task = mChildrenTaskInfo.get(taskId);
if (task == null) return false;
@@ -57,4 +70,12 @@
.reparent(task.token, newParent, false /* onTop */);
return true;
}
+
+ int getTopVisibleTaskId() {
+ for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) {
+ final ActivityManager.RunningTaskInfo task = mChildrenTaskInfo.valueAt(i);
+ if (task.isVisible) return task.taskId;
+ }
+ return INVALID_TASK_ID;
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
index 08c2856..7c1b9d8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -18,6 +18,8 @@
import android.annotation.IntDef;
import android.app.ActivityManager;
+import android.graphics.Rect;
+import android.os.Bundle;
import androidx.annotation.NonNull;
@@ -61,6 +63,12 @@
void setSideStagePosition(@SideStagePosition int sideStagePosition);
/** Hides the side-stage if it is currently visible. */
void setSideStageVisibility(boolean visible);
+ /** Removes the split-screen stages. */
+ void exitSplitScreen();
+ /** Gets the stage bounds. */
+ void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds);
+ /** Updates the launch activity options for the split position we want to launch it in. */
+ void updateActivityOptions(Bundle opts, @SideStagePosition int position);
/** Dumps current status of split-screen. */
void dump(@NonNull PrintWriter pw, String prefix);
/** Called when the shell organizer has been registered. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 55cfea5..27d3b81 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -20,6 +20,8 @@
import android.app.ActivityManager;
import android.content.Context;
+import android.graphics.Rect;
+import android.os.Bundle;
import androidx.annotation.NonNull;
@@ -69,7 +71,10 @@
@Override
public boolean moveToSideStage(int taskId, @SideStagePosition int sideStagePosition) {
final ActivityManager.RunningTaskInfo task = mTaskOrganizer.getRunningTaskInfo(taskId);
- return task != null && moveToSideStage(task, sideStagePosition);
+ if (task == null) {
+ throw new IllegalArgumentException("Unknown taskId" + taskId);
+ }
+ return moveToSideStage(task, sideStagePosition);
}
@Override
@@ -94,6 +99,21 @@
}
@Override
+ public void exitSplitScreen() {
+ mStageCoordinator.exitSplitScreen();
+ }
+
+ @Override
+ public void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds) {
+ mStageCoordinator.getStageBounds(outTopOrLeftBounds, outBottomOrRightBounds);
+ }
+
+ @Override
+ public void updateActivityOptions(Bundle opts, @SideStagePosition int position) {
+ mStageCoordinator.updateActivityOptions(opts, position);
+ }
+
+ @Override
public void dump(@NonNull PrintWriter pw, String prefix) {
pw.println(prefix + TAG);
if (mStageCoordinator != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 5c1d18e..dd41957 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -16,6 +16,8 @@
package com.android.wm.shell.splitscreen;
+import static android.app.ActivityOptions.KEY_LAUNCH_ROOT_TASK_TOKEN;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
@@ -25,6 +27,7 @@
import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Rect;
+import android.os.Bundle;
import android.view.SurfaceControl;
import android.window.DisplayAreaInfo;
import android.window.WindowContainerTransaction;
@@ -142,6 +145,31 @@
mTaskOrganizer.applyTransaction(wct);
}
+ void exitSplitScreen() {
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ mSideStage.removeAllTasks(wct);
+ mMainStage.deactivate(wct);
+ mTaskOrganizer.applyTransaction(wct);
+ }
+
+ void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds) {
+ outTopOrLeftBounds.set(mSplitLayout.getBounds1());
+ outBottomOrRightBounds.set(mSplitLayout.getBounds2());
+ }
+
+ void updateActivityOptions(Bundle opts, @SplitScreen.SideStagePosition int position) {
+ final StageTaskListener stage = position == mSideStagePosition ? mSideStage : mMainStage;
+ opts.putParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN, stage.mRootTaskInfo.token);
+
+ if (!mMainStage.isActive()) {
+ // Activate the main stage in anticipation of an app launch.
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ mMainStage.activate(getMainStageBounds(), wct);
+ mSideStage.setBounds(getSideStageBounds(), wct);
+ mTaskOrganizer.applyTransaction(wct);
+ }
+ }
+
private void onStageRootTaskAppeared(StageListenerImpl stageListener) {
if (mMainStageListener.mHasRootTask && mSideStageListener.mHasRootTask) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
@@ -175,6 +203,12 @@
}
}
+ if (!mainStageVisible && !sideStageVisible) {
+ // Exit split-screen if both stage are not visible.
+ // TODO: This is only a temporary request from UX and is likely to be removed soon...
+ exitSplitScreen();
+ }
+
if (mainStageVisible) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
if (sideStageVisible) {
@@ -252,10 +286,27 @@
}
@Override
- public void onSnappedToDismiss(boolean snappedToEnd) {
- // TODO: What to do...what to do...
+ public void onSnappedToDismiss(boolean bottomOrRight) {
+ if (mSideStagePosition == SIDE_STAGE_POSITION_BOTTOM_OR_RIGHT && bottomOrRight) {
+ // Main stage was fully expanded...Just side side-stage.
+ setSideStageVisibility(false);
+ } else {
+ // Side stage was fully expanded...Move its top task to the main stage
+ // and hide side-stage.
+ // TODO: Would UX prefer the side-stage go into fullscreen mode here?
+ final int taskId = mSideStage.getTopVisibleTaskId();
+ if (taskId == INVALID_TASK_ID) {
+ throw new IllegalStateException("Side stage doesn't have visible task? "
+ + mSideStage);
+ }
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ mSideStage.removeTask(taskId, mMainStage.mRootTaskInfo.getToken(), wct);
+ mSideStage.setVisibility(false, wct);
+ mTaskOrganizer.applyTransaction(wct);
+ }
+
+ // Reset divider position.
mSplitLayout.resetDividerPosition();
- onBoundsChanged(mSplitLayout);
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index efd42ce..1aa7552 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -16,7 +16,10 @@
package com.android.wm.shell.splitscreen;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import android.annotation.CallSuper;
import android.app.ActivityManager;
@@ -45,6 +48,12 @@
class StageTaskListener implements ShellTaskOrganizer.TaskListener {
private static final String TAG = StageTaskListener.class.getSimpleName();
+ protected static final int[] CONTROLLED_ACTIVITY_TYPES = {ACTIVITY_TYPE_STANDARD};
+ protected static final int[] CONTROLLED_WINDOWING_MODES =
+ {WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED};
+ protected static final int[] CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE =
+ {WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED, WINDOWING_MODE_MULTI_WINDOW};
+
/** Callback interface for listening to changes in a split-screen stage. */
public interface StageListenerCallbacks {
void onRootTaskAppeared();
@@ -69,7 +78,7 @@
@Override
@CallSuper
public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
- if (!taskInfo.hasParentTask()) {
+ if (mRootTaskInfo == null && !taskInfo.hasParentTask()) {
mRootLeash = leash;
mRootTaskInfo = taskInfo;
mCallbacks.onRootTaskAppeared();
@@ -78,7 +87,8 @@
mChildrenTaskInfo.put(taskInfo.taskId, taskInfo);
updateChildTaskSurface(taskInfo, leash, true /* firstAppeared */);
} else {
- throw new IllegalArgumentException("Unknown task: " + taskInfo);
+ throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo
+ + "\n mRootTaskInfo: " + mRootTaskInfo);
}
sendStatusChanged();
}
@@ -93,7 +103,8 @@
updateChildTaskSurface(
taskInfo, mChildrenLeashes.get(taskInfo.taskId), false /* firstAppeared */);
} else {
- throw new IllegalArgumentException("Unknown task: " + taskInfo);
+ throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo
+ + "\n mRootTaskInfo: " + mRootTaskInfo);
}
sendStatusChanged();
}
@@ -110,7 +121,8 @@
mChildrenLeashes.remove(taskId);
sendStatusChanged();
} else {
- throw new IllegalArgumentException("Unknown task: " + taskInfo);
+ throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo
+ + "\n mRootTaskInfo: " + mRootTaskInfo);
}
}
@@ -143,6 +155,8 @@
@Override
@CallSuper
public void dump(@NonNull PrintWriter pw, String prefix) {
-
+ final String innerPrefix = prefix + " ";
+ final String childPrefix = innerPrefix + " ";
+ pw.println(prefix + this);
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
index 912418d..79bdaf4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
@@ -26,7 +26,9 @@
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_FULLSCREEN;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM;
+import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_LEFT;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
+import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
@@ -35,7 +37,6 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
@@ -52,7 +53,6 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Insets;
-import android.graphics.Rect;
import android.os.RemoteException;
import android.view.DisplayInfo;
@@ -61,20 +61,17 @@
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.draganddrop.DragAndDropPolicy.Target;
-import com.android.wm.shell.legacysplitscreen.DividerView;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
+import com.android.wm.shell.splitscreen.SplitScreen;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.mockito.stubbing.Answer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
-import java.util.function.Consumer;
/**
* Tests for the drag and drop policy.
@@ -90,12 +87,13 @@
private ActivityTaskManager mActivityTaskManager;
@Mock
- private LegacySplitScreen mLegacySplitScreen;
+ private SplitScreen mSplitScreen;
@Mock
private DragAndDropPolicy.Starter mStarter;
- private DisplayLayout mDisplayLayout;
+ private DisplayLayout mLandscapeDisplayLayout;
+ private DisplayLayout mPortraitDisplayLayout;
private Insets mInsets;
private DragAndDropPolicy mPolicy;
@@ -116,25 +114,19 @@
Resources res = mock(Resources.class);
Configuration config = new Configuration();
doReturn(config).when(res).getConfiguration();
+ doReturn(res).when(mContext).getResources();
DisplayInfo info = new DisplayInfo();
- info.logicalWidth = 100;
+ info.logicalWidth = 200;
info.logicalHeight = 100;
- mDisplayLayout = new DisplayLayout(info, res, false, false);
+ mLandscapeDisplayLayout = new DisplayLayout(info, res, false, false);
+ DisplayInfo info2 = new DisplayInfo();
+ info.logicalWidth = 100;
+ info.logicalHeight = 200;
+ mPortraitDisplayLayout = new DisplayLayout(info2, res, false, false);
mInsets = Insets.of(0, 0, 0, 0);
- DividerView divider = mock(DividerView.class);
- doReturn(divider).when(mLegacySplitScreen).getDividerView();
- doReturn(new Rect(50, 0, 100, 100)).when(divider)
- .getNonMinimizedSplitScreenSecondaryBounds();
-
- doAnswer((Answer<Void>) invocation -> {
- Consumer<Boolean> callback = invocation.getArgument(0);
- callback.accept(true);
- return null;
- }).when(mLegacySplitScreen).registerInSplitScreenListener(any());
-
mPolicy = new DragAndDropPolicy(
- mContext, mActivityTaskManager, mLegacySplitScreen, mStarter);
+ mContext, mActivityTaskManager, mSplitScreen, mStarter);
mActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY);
mNonResizeableActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY);
setClipDataResizeable(mNonResizeableActivityClipData, false);
@@ -149,7 +141,6 @@
mSplitPrimaryAppTask = createTaskInfo(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
ACTIVITY_TYPE_STANDARD);
- setIsPhone(false);
setInSplitScreen(false);
setRunningTask(mFullscreenAppTask);
}
@@ -199,22 +190,14 @@
: ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
}
- private void setIsPhone(boolean isPhone) {
- Resources res = mock(Resources.class);
- Configuration config = mock(Configuration.class);
- config.smallestScreenWidthDp = isPhone ? 400 : 800;
- doReturn(config).when(res).getConfiguration();
- doReturn(res).when(mContext).getResources();
- }
-
private void setInSplitScreen(boolean inSplitscreen) {
- doReturn(inSplitscreen).when(mLegacySplitScreen).isDividerVisible();
+ doReturn(inSplitscreen).when(mSplitScreen).isSplitScreenVisible();
}
@Test
- public void testDragAppOverFullscreenHome_expectOnlyFullscreenTarget() throws RemoteException {
+ public void testDragAppOverFullscreenHome_expectOnlyFullscreenTarget() {
setRunningTask(mHomeTask);
- mPolicy.start(mDisplayLayout, mActivityClipData);
+ mPolicy.start(mLandscapeDisplayLayout, mActivityClipData);
ArrayList<Target> targets = assertExactTargetTypes(
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN);
@@ -223,77 +206,66 @@
}
@Test
- public void testDragAppOverFullscreenApp_expectSplitScreenAndFullscreenTargets()
- throws RemoteException {
+ public void testDragAppOverFullscreenApp_expectSplitScreenAndFullscreenTargets() {
setRunningTask(mFullscreenAppTask);
- mPolicy.start(mDisplayLayout, mActivityClipData);
- // TODO(b/169894807): For now, only allow splitting to the right/bottom until we have split
- // pairs
+ mPolicy.start(mLandscapeDisplayLayout, mActivityClipData);
ArrayList<Target> targets = assertExactTargetTypes(
- mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_RIGHT);
+ mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
+ verify(mStarter).exitSplitScreen();
verify(mStarter).startIntent(any(), any());
reset(mStarter);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData);
- verify(mStarter).enterSplitScreen(anyInt(), eq(false));
verify(mStarter).startIntent(any(), any());
}
@Test
- public void testDragAppOverFullscreenAppPhone_expectVerticalSplitScreenAndFullscreenTargets()
- throws RemoteException {
- setIsPhone(true);
+ public void testDragAppOverFullscreenAppPhone_expectVerticalSplitScreenAndFullscreenTargets() {
setRunningTask(mFullscreenAppTask);
- mPolicy.start(mDisplayLayout, mActivityClipData);
- // TODO(b/169894807): For now, only allow splitting to the right/bottom until we have split
- // pairs
+ mPolicy.start(mPortraitDisplayLayout, mActivityClipData);
ArrayList<Target> targets = assertExactTargetTypes(
- mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_BOTTOM);
+ mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
+ verify(mStarter).exitSplitScreen();
verify(mStarter).startIntent(any(), any());
reset(mStarter);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData);
- verify(mStarter).enterSplitScreen(anyInt(), eq(false));
verify(mStarter).startIntent(any(), any());
}
@Test
- public void testDragAppOverFullscreenNonResizeableApp_expectOnlyFullscreenTargets()
- throws RemoteException {
+ public void testDragAppOverFullscreenNonResizeableApp_expectOnlyFullscreenTargets() {
setRunningTask(mNonResizeableFullscreenAppTask);
- mPolicy.start(mDisplayLayout, mActivityClipData);
+ mPolicy.start(mLandscapeDisplayLayout, mActivityClipData);
ArrayList<Target> targets = assertExactTargetTypes(
- mPolicy.getTargets(mInsets), TYPE_FULLSCREEN);
+ mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
verify(mStarter).startIntent(any(), any());
}
@Test
- public void testDragNonResizeableAppOverFullscreenApp_expectOnlyFullscreenTargets()
- throws RemoteException {
+ public void testDragNonResizeableAppOverFullscreenApp_expectOnlyFullscreenTargets() {
setRunningTask(mFullscreenAppTask);
- mPolicy.start(mDisplayLayout, mNonResizeableActivityClipData);
+ mPolicy.start(mLandscapeDisplayLayout, mNonResizeableActivityClipData);
ArrayList<Target> targets = assertExactTargetTypes(
- mPolicy.getTargets(mInsets), TYPE_FULLSCREEN);
+ mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
verify(mStarter).startIntent(any(), any());
}
@Test
- public void testDragAppOverSplitApp_expectFullscreenAndSplitTargets() throws RemoteException {
+ public void testDragAppOverSplitApp_expectFullscreenAndSplitTargets() {
setInSplitScreen(true);
setRunningTask(mSplitPrimaryAppTask);
- mPolicy.start(mDisplayLayout, mActivityClipData);
- // TODO(b/169894807): For now, only allow splitting to the right/bottom until we have split
- // pairs
+ mPolicy.start(mLandscapeDisplayLayout, mActivityClipData);
ArrayList<Target> targets = assertExactTargetTypes(
- mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_RIGHT);
+ mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
verify(mStarter).startIntent(any(), any());
@@ -305,16 +277,12 @@
}
@Test
- public void testDragAppOverSplitAppPhone_expectFullscreenAndVerticalSplitTargets()
- throws RemoteException {
- setIsPhone(true);
+ public void testDragAppOverSplitAppPhone_expectFullscreenAndVerticalSplitTargets() {
setInSplitScreen(true);
setRunningTask(mSplitPrimaryAppTask);
- mPolicy.start(mDisplayLayout, mActivityClipData);
- // TODO(b/169894807): For now, only allow splitting to the right/bottom until we have split
- // pairs
+ mPolicy.start(mPortraitDisplayLayout, mActivityClipData);
ArrayList<Target> targets = assertExactTargetTypes(
- mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_BOTTOM);
+ mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
verify(mStarter).startIntent(any(), any());
@@ -326,9 +294,9 @@
}
@Test
- public void testTargetHitRects() throws RemoteException {
+ public void testTargetHitRects() {
setRunningTask(mFullscreenAppTask);
- mPolicy.start(mDisplayLayout, mActivityClipData);
+ mPolicy.start(mLandscapeDisplayLayout, mActivityClipData);
ArrayList<Target> targets = mPolicy.getTargets(mInsets);
for (Target t : targets) {
assertTrue(mPolicy.getTargetAtLocation(t.hitRegion.left, t.hitRegion.top) == t);
diff --git a/libs/androidfw/LocaleDataTables.cpp b/libs/androidfw/LocaleDataTables.cpp
index 6c6c5c9..8a10599 100644
--- a/libs/androidfw/LocaleDataTables.cpp
+++ b/libs/androidfw/LocaleDataTables.cpp
@@ -64,42 +64,43 @@
/* 60 */ {'N', 'k', 'o', 'o'},
/* 61 */ {'N', 's', 'h', 'u'},
/* 62 */ {'O', 'g', 'a', 'm'},
- /* 63 */ {'O', 'r', 'k', 'h'},
- /* 64 */ {'O', 'r', 'y', 'a'},
- /* 65 */ {'O', 's', 'g', 'e'},
- /* 66 */ {'P', 'a', 'u', 'c'},
- /* 67 */ {'P', 'h', 'l', 'i'},
- /* 68 */ {'P', 'h', 'n', 'x'},
- /* 69 */ {'P', 'l', 'r', 'd'},
- /* 70 */ {'P', 'r', 't', 'i'},
- /* 71 */ {'R', 'u', 'n', 'r'},
- /* 72 */ {'S', 'a', 'm', 'r'},
- /* 73 */ {'S', 'a', 'r', 'b'},
- /* 74 */ {'S', 'a', 'u', 'r'},
- /* 75 */ {'S', 'g', 'n', 'w'},
- /* 76 */ {'S', 'i', 'n', 'h'},
- /* 77 */ {'S', 'o', 'g', 'd'},
- /* 78 */ {'S', 'o', 'r', 'a'},
- /* 79 */ {'S', 'o', 'y', 'o'},
- /* 80 */ {'S', 'y', 'r', 'c'},
- /* 81 */ {'T', 'a', 'l', 'e'},
- /* 82 */ {'T', 'a', 'l', 'u'},
- /* 83 */ {'T', 'a', 'm', 'l'},
- /* 84 */ {'T', 'a', 'n', 'g'},
- /* 85 */ {'T', 'a', 'v', 't'},
- /* 86 */ {'T', 'e', 'l', 'u'},
- /* 87 */ {'T', 'f', 'n', 'g'},
- /* 88 */ {'T', 'h', 'a', 'a'},
- /* 89 */ {'T', 'h', 'a', 'i'},
- /* 90 */ {'T', 'i', 'b', 't'},
- /* 91 */ {'U', 'g', 'a', 'r'},
- /* 92 */ {'V', 'a', 'i', 'i'},
- /* 93 */ {'W', 'c', 'h', 'o'},
- /* 94 */ {'X', 'p', 'e', 'o'},
- /* 95 */ {'X', 's', 'u', 'x'},
- /* 96 */ {'Y', 'i', 'i', 'i'},
- /* 97 */ {'~', '~', '~', 'A'},
- /* 98 */ {'~', '~', '~', 'B'},
+ /* 63 */ {'O', 'l', 'c', 'k'},
+ /* 64 */ {'O', 'r', 'k', 'h'},
+ /* 65 */ {'O', 'r', 'y', 'a'},
+ /* 66 */ {'O', 's', 'g', 'e'},
+ /* 67 */ {'P', 'a', 'u', 'c'},
+ /* 68 */ {'P', 'h', 'l', 'i'},
+ /* 69 */ {'P', 'h', 'n', 'x'},
+ /* 70 */ {'P', 'l', 'r', 'd'},
+ /* 71 */ {'P', 'r', 't', 'i'},
+ /* 72 */ {'R', 'u', 'n', 'r'},
+ /* 73 */ {'S', 'a', 'm', 'r'},
+ /* 74 */ {'S', 'a', 'r', 'b'},
+ /* 75 */ {'S', 'a', 'u', 'r'},
+ /* 76 */ {'S', 'g', 'n', 'w'},
+ /* 77 */ {'S', 'i', 'n', 'h'},
+ /* 78 */ {'S', 'o', 'g', 'd'},
+ /* 79 */ {'S', 'o', 'r', 'a'},
+ /* 80 */ {'S', 'o', 'y', 'o'},
+ /* 81 */ {'S', 'y', 'r', 'c'},
+ /* 82 */ {'T', 'a', 'l', 'e'},
+ /* 83 */ {'T', 'a', 'l', 'u'},
+ /* 84 */ {'T', 'a', 'm', 'l'},
+ /* 85 */ {'T', 'a', 'n', 'g'},
+ /* 86 */ {'T', 'a', 'v', 't'},
+ /* 87 */ {'T', 'e', 'l', 'u'},
+ /* 88 */ {'T', 'f', 'n', 'g'},
+ /* 89 */ {'T', 'h', 'a', 'a'},
+ /* 90 */ {'T', 'h', 'a', 'i'},
+ /* 91 */ {'T', 'i', 'b', 't'},
+ /* 92 */ {'U', 'g', 'a', 'r'},
+ /* 93 */ {'V', 'a', 'i', 'i'},
+ /* 94 */ {'W', 'c', 'h', 'o'},
+ /* 95 */ {'X', 'p', 'e', 'o'},
+ /* 96 */ {'X', 's', 'u', 'x'},
+ /* 97 */ {'Y', 'i', 'i', 'i'},
+ /* 98 */ {'~', '~', '~', 'A'},
+ /* 99 */ {'~', '~', '~', 'B'},
};
@@ -120,7 +121,7 @@
{0x80600000u, 46u}, // ada -> Latn
{0x90600000u, 46u}, // ade -> Latn
{0xA4600000u, 46u}, // adj -> Latn
- {0xBC600000u, 90u}, // adp -> Tibt
+ {0xBC600000u, 91u}, // adp -> Tibt
{0xE0600000u, 17u}, // ady -> Cyrl
{0xE4600000u, 46u}, // adz -> Latn
{0x61650000u, 4u}, // ae -> Avst
@@ -138,7 +139,7 @@
{0xB8E00000u, 0u}, // aho -> Ahom
{0x99200000u, 46u}, // ajg -> Latn
{0x616B0000u, 46u}, // ak -> Latn
- {0xA9400000u, 95u}, // akk -> Xsux
+ {0xA9400000u, 96u}, // akk -> Xsux
{0x81600000u, 46u}, // ala -> Latn
{0xA1600000u, 46u}, // ali -> Latn
{0xB5600000u, 46u}, // aln -> Latn
@@ -163,7 +164,7 @@
{0xC9E00000u, 46u}, // aps -> Latn
{0xE5E00000u, 46u}, // apz -> Latn
{0x61720000u, 1u}, // ar -> Arab
- {0x61725842u, 98u}, // ar-XB -> ~~~B
+ {0x61725842u, 99u}, // ar-XB -> ~~~B
{0x8A200000u, 2u}, // arc -> Armi
{0x9E200000u, 46u}, // arh -> Latn
{0xB6200000u, 46u}, // arn -> Latn
@@ -174,7 +175,7 @@
{0xE6200000u, 1u}, // arz -> Arab
{0x61730000u, 7u}, // as -> Beng
{0x82400000u, 46u}, // asa -> Latn
- {0x92400000u, 75u}, // ase -> Sgnw
+ {0x92400000u, 76u}, // ase -> Sgnw
{0x9A400000u, 46u}, // asg -> Latn
{0xBA400000u, 46u}, // aso -> Latn
{0xCE400000u, 46u}, // ast -> Latn
@@ -231,7 +232,7 @@
{0xDC810000u, 46u}, // bex -> Latn
{0xE4810000u, 46u}, // bez -> Latn
{0x8CA10000u, 46u}, // bfd -> Latn
- {0xC0A10000u, 83u}, // bfq -> Taml
+ {0xC0A10000u, 84u}, // bfq -> Taml
{0xCCA10000u, 1u}, // bft -> Arab
{0xE0A10000u, 18u}, // bfy -> Deva
{0x62670000u, 17u}, // bg -> Cyrl
@@ -265,7 +266,7 @@
{0xC1410000u, 46u}, // bkq -> Latn
{0xD1410000u, 46u}, // bku -> Latn
{0xD5410000u, 46u}, // bkv -> Latn
- {0xCD610000u, 85u}, // blt -> Tavt
+ {0xCD610000u, 86u}, // blt -> Tavt
{0x626D0000u, 46u}, // bm -> Latn
{0x9D810000u, 46u}, // bmh -> Latn
{0xA9810000u, 46u}, // bmk -> Latn
@@ -275,7 +276,7 @@
{0x99A10000u, 46u}, // bng -> Latn
{0xB1A10000u, 46u}, // bnm -> Latn
{0xBDA10000u, 46u}, // bnp -> Latn
- {0x626F0000u, 90u}, // bo -> Tibt
+ {0x626F0000u, 91u}, // bo -> Tibt
{0xA5C10000u, 46u}, // boj -> Latn
{0xB1C10000u, 46u}, // bom -> Latn
{0xB5C10000u, 46u}, // bon -> Latn
@@ -322,6 +323,7 @@
{0x9F210000u, 46u}, // bzh -> Latn
{0xDB210000u, 46u}, // bzw -> Latn
{0x63610000u, 46u}, // ca -> Latn
+ {0x8C020000u, 46u}, // cad -> Latn
{0xB4020000u, 46u}, // can -> Latn
{0xA4220000u, 46u}, // cbj -> Latn
{0x9C420000u, 46u}, // cch -> Latn
@@ -346,7 +348,7 @@
{0xE1420000u, 46u}, // cky -> Latn
{0x81620000u, 46u}, // cla -> Latn
{0x91820000u, 46u}, // cme -> Latn
- {0x99820000u, 79u}, // cmg -> Soyo
+ {0x99820000u, 80u}, // cmg -> Soyo
{0x636F0000u, 46u}, // co -> Latn
{0xBDC20000u, 15u}, // cop -> Copt
{0xC9E20000u, 46u}, // cps -> Latn
@@ -360,7 +362,7 @@
{0x63730000u, 46u}, // cs -> Latn
{0x86420000u, 46u}, // csb -> Latn
{0xDA420000u, 10u}, // csw -> Cans
- {0x8E620000u, 66u}, // ctd -> Pauc
+ {0x8E620000u, 67u}, // ctd -> Pauc
{0x63750000u, 17u}, // cu -> Cyrl
{0x63760000u, 17u}, // cv -> Cyrl
{0x63790000u, 46u}, // cy -> Latn
@@ -389,7 +391,7 @@
{0x91230000u, 46u}, // dje -> Latn
{0xA5A30000u, 46u}, // dnj -> Latn
{0x85C30000u, 46u}, // dob -> Latn
- {0xA1C30000u, 1u}, // doi -> Arab
+ {0xA1C30000u, 18u}, // doi -> Deva
{0xBDC30000u, 46u}, // dop -> Latn
{0xD9C30000u, 46u}, // dow -> Latn
{0x9E230000u, 56u}, // drh -> Mong
@@ -404,12 +406,12 @@
{0x8A830000u, 46u}, // duc -> Latn
{0x8E830000u, 46u}, // dud -> Latn
{0x9A830000u, 46u}, // dug -> Latn
- {0x64760000u, 88u}, // dv -> Thaa
+ {0x64760000u, 89u}, // dv -> Thaa
{0x82A30000u, 46u}, // dva -> Latn
{0xDAC30000u, 46u}, // dww -> Latn
{0xBB030000u, 46u}, // dyo -> Latn
{0xD3030000u, 46u}, // dyu -> Latn
- {0x647A0000u, 90u}, // dz -> Tibt
+ {0x647A0000u, 91u}, // dz -> Tibt
{0x9B230000u, 46u}, // dzg -> Latn
{0xD0240000u, 46u}, // ebu -> Latn
{0x65650000u, 46u}, // ee -> Latn
@@ -422,7 +424,7 @@
{0x81840000u, 46u}, // ema -> Latn
{0xA1840000u, 46u}, // emi -> Latn
{0x656E0000u, 46u}, // en -> Latn
- {0x656E5841u, 97u}, // en-XA -> ~~~A
+ {0x656E5841u, 98u}, // en-XA -> ~~~A
{0xB5A40000u, 46u}, // enn -> Latn
{0xC1A40000u, 46u}, // enq -> Latn
{0x656F0000u, 46u}, // eo -> Latn
@@ -438,6 +440,7 @@
{0x65750000u, 46u}, // eu -> Latn
{0xBAC40000u, 46u}, // ewo -> Latn
{0xCEE40000u, 46u}, // ext -> Latn
+ {0x83240000u, 46u}, // eza -> Latn
{0x66610000u, 1u}, // fa -> Arab
{0x80050000u, 46u}, // faa -> Latn
{0x84050000u, 46u}, // fab -> Latn
@@ -521,7 +524,7 @@
{0x95C60000u, 20u}, // gof -> Ethi
{0xA1C60000u, 46u}, // goi -> Latn
{0xB1C60000u, 18u}, // gom -> Deva
- {0xB5C60000u, 86u}, // gon -> Telu
+ {0xB5C60000u, 87u}, // gon -> Telu
{0xC5C60000u, 46u}, // gor -> Latn
{0xC9C60000u, 46u}, // gos -> Latn
{0xCDC60000u, 24u}, // got -> Goth
@@ -566,7 +569,7 @@
{0xAD070000u, 46u}, // hil -> Latn
{0x81670000u, 46u}, // hla -> Latn
{0xD1670000u, 32u}, // hlu -> Hluw
- {0x8D870000u, 69u}, // hmd -> Plrd
+ {0x8D870000u, 70u}, // hmd -> Plrd
{0xCD870000u, 46u}, // hmt -> Latn
{0x8DA70000u, 1u}, // hnd -> Arab
{0x91A70000u, 18u}, // hne -> Deva
@@ -601,7 +604,7 @@
{0x69670000u, 46u}, // ig -> Latn
{0x84C80000u, 46u}, // igb -> Latn
{0x90C80000u, 46u}, // ige -> Latn
- {0x69690000u, 96u}, // ii -> Yiii
+ {0x69690000u, 97u}, // ii -> Yiii
{0xA5280000u, 46u}, // ijj -> Latn
{0x696B0000u, 46u}, // ik -> Latn
{0xA9480000u, 46u}, // ikk -> Latn
@@ -626,6 +629,7 @@
{0x6A610000u, 36u}, // ja -> Jpan
{0x84090000u, 46u}, // jab -> Latn
{0xB0090000u, 46u}, // jam -> Latn
+ {0xC4090000u, 46u}, // jar -> Latn
{0xB8290000u, 46u}, // jbo -> Latn
{0xD0290000u, 46u}, // jbu -> Latn
{0xB4890000u, 46u}, // jen -> Latn
@@ -661,7 +665,7 @@
{0x906A0000u, 46u}, // kde -> Latn
{0x9C6A0000u, 1u}, // kdh -> Arab
{0xAC6A0000u, 46u}, // kdl -> Latn
- {0xCC6A0000u, 89u}, // kdt -> Thai
+ {0xCC6A0000u, 90u}, // kdt -> Thai
{0x808A0000u, 46u}, // kea -> Latn
{0xB48A0000u, 46u}, // ken -> Latn
{0xE48A0000u, 46u}, // kez -> Latn
@@ -673,7 +677,7 @@
{0x94CA0000u, 46u}, // kgf -> Latn
{0xBCCA0000u, 46u}, // kgp -> Latn
{0x80EA0000u, 46u}, // kha -> Latn
- {0x84EA0000u, 82u}, // khb -> Talu
+ {0x84EA0000u, 83u}, // khb -> Talu
{0xB4EA0000u, 18u}, // khn -> Deva
{0xC0EA0000u, 46u}, // khq -> Latn
{0xC8EA0000u, 46u}, // khs -> Latn
@@ -766,7 +770,8 @@
{0x82EA0000u, 46u}, // kxa -> Latn
{0x8AEA0000u, 20u}, // kxc -> Ethi
{0x92EA0000u, 46u}, // kxe -> Latn
- {0xB2EA0000u, 89u}, // kxm -> Thai
+ {0xAEEA0000u, 18u}, // kxl -> Deva
+ {0xB2EA0000u, 90u}, // kxm -> Thai
{0xBEEA0000u, 1u}, // kxp -> Arab
{0xDAEA0000u, 46u}, // kxw -> Latn
{0xE6EA0000u, 46u}, // kxz -> Latn
@@ -775,6 +780,7 @@
{0x6B795452u, 46u}, // ky-TR -> Latn
{0x930A0000u, 46u}, // kye -> Latn
{0xDF0A0000u, 46u}, // kyx -> Latn
+ {0x9F2A0000u, 1u}, // kzh -> Arab
{0xA72A0000u, 46u}, // kzj -> Latn
{0xC72A0000u, 46u}, // kzr -> Latn
{0xCF2A0000u, 46u}, // kzt -> Latn
@@ -790,7 +796,7 @@
{0xD02B0000u, 46u}, // lbu -> Latn
{0xD82B0000u, 46u}, // lbw -> Latn
{0xB04B0000u, 46u}, // lcm -> Latn
- {0xBC4B0000u, 89u}, // lcp -> Thai
+ {0xBC4B0000u, 90u}, // lcp -> Thai
{0x846B0000u, 46u}, // ldb -> Latn
{0x8C8B0000u, 46u}, // led -> Latn
{0x908B0000u, 46u}, // lee -> Latn
@@ -814,7 +820,7 @@
{0xCD4B0000u, 46u}, // lkt -> Latn
{0x916B0000u, 46u}, // lle -> Latn
{0xB56B0000u, 46u}, // lln -> Latn
- {0xB58B0000u, 86u}, // lmn -> Telu
+ {0xB58B0000u, 87u}, // lmn -> Telu
{0xB98B0000u, 46u}, // lmo -> Latn
{0xBD8B0000u, 46u}, // lmp -> Latn
{0x6C6E0000u, 46u}, // ln -> Latn
@@ -836,7 +842,7 @@
{0xE28B0000u, 46u}, // luy -> Latn
{0xE68B0000u, 1u}, // luz -> Arab
{0x6C760000u, 46u}, // lv -> Latn
- {0xAECB0000u, 89u}, // lwl -> Thai
+ {0xAECB0000u, 90u}, // lwl -> Thai
{0x9F2B0000u, 28u}, // lzh -> Hans
{0xE72B0000u, 46u}, // lzz -> Latn
{0x8C0C0000u, 46u}, // mad -> Latn
@@ -927,7 +933,6 @@
{0xBA2C0000u, 57u}, // mro -> Mroo
{0x6D730000u, 46u}, // ms -> Latn
{0x6D734343u, 1u}, // ms-CC -> Arab
- {0x6D734944u, 1u}, // ms-ID -> Arab
{0x6D740000u, 46u}, // mt -> Latn
{0x8A6C0000u, 46u}, // mtc -> Latn
{0x966C0000u, 46u}, // mtf -> Latn
@@ -1006,11 +1011,11 @@
{0x9DAD0000u, 46u}, // nnh -> Latn
{0xA9AD0000u, 46u}, // nnk -> Latn
{0xB1AD0000u, 46u}, // nnm -> Latn
- {0xBDAD0000u, 93u}, // nnp -> Wcho
+ {0xBDAD0000u, 94u}, // nnp -> Wcho
{0x6E6F0000u, 46u}, // no -> Latn
{0x8DCD0000u, 44u}, // nod -> Lana
{0x91CD0000u, 18u}, // noe -> Deva
- {0xB5CD0000u, 71u}, // non -> Runr
+ {0xB5CD0000u, 72u}, // non -> Runr
{0xBDCD0000u, 46u}, // nop -> Latn
{0xD1CD0000u, 46u}, // nou -> Latn
{0xBA0D0000u, 60u}, // nqo -> Nkoo
@@ -1044,18 +1049,18 @@
{0xB5AE0000u, 46u}, // onn -> Latn
{0xC9AE0000u, 46u}, // ons -> Latn
{0xB1EE0000u, 46u}, // opm -> Latn
- {0x6F720000u, 64u}, // or -> Orya
+ {0x6F720000u, 65u}, // or -> Orya
{0xBA2E0000u, 46u}, // oro -> Latn
{0xD22E0000u, 1u}, // oru -> Arab
{0x6F730000u, 17u}, // os -> Cyrl
- {0x824E0000u, 65u}, // osa -> Osge
+ {0x824E0000u, 66u}, // osa -> Osge
{0x826E0000u, 1u}, // ota -> Arab
- {0xAA6E0000u, 63u}, // otk -> Orkh
+ {0xAA6E0000u, 64u}, // otk -> Orkh
{0xB32E0000u, 46u}, // ozm -> Latn
{0x70610000u, 27u}, // pa -> Guru
{0x7061504Bu, 1u}, // pa-PK -> Arab
{0x980F0000u, 46u}, // pag -> Latn
- {0xAC0F0000u, 67u}, // pal -> Phli
+ {0xAC0F0000u, 68u}, // pal -> Phli
{0xB00F0000u, 46u}, // pam -> Latn
{0xBC0F0000u, 46u}, // pap -> Latn
{0xD00F0000u, 46u}, // pau -> Latn
@@ -1065,11 +1070,11 @@
{0x886F0000u, 46u}, // pdc -> Latn
{0xCC6F0000u, 46u}, // pdt -> Latn
{0x8C8F0000u, 46u}, // ped -> Latn
- {0xB88F0000u, 94u}, // peo -> Xpeo
+ {0xB88F0000u, 95u}, // peo -> Xpeo
{0xDC8F0000u, 46u}, // pex -> Latn
{0xACAF0000u, 46u}, // pfl -> Latn
{0xACEF0000u, 1u}, // phl -> Arab
- {0xB4EF0000u, 68u}, // phn -> Phnx
+ {0xB4EF0000u, 69u}, // phn -> Phnx
{0xAD0F0000u, 46u}, // pil -> Latn
{0xBD0F0000u, 46u}, // pip -> Latn
{0x814F0000u, 8u}, // pka -> Brah
@@ -1105,7 +1110,7 @@
{0xB4D10000u, 46u}, // rgn -> Latn
{0x98F10000u, 1u}, // rhg -> Arab
{0x81110000u, 46u}, // ria -> Latn
- {0x95110000u, 87u}, // rif -> Tfng
+ {0x95110000u, 88u}, // rif -> Tfng
{0x95114E4Cu, 46u}, // rif-NL -> Latn
{0xC9310000u, 18u}, // rjs -> Deva
{0xCD510000u, 7u}, // rkt -> Beng
@@ -1135,9 +1140,9 @@
{0x9C120000u, 17u}, // sah -> Cyrl
{0xC0120000u, 46u}, // saq -> Latn
{0xC8120000u, 46u}, // sas -> Latn
- {0xCC120000u, 46u}, // sat -> Latn
+ {0xCC120000u, 63u}, // sat -> Olck
{0xD4120000u, 46u}, // sav -> Latn
- {0xE4120000u, 74u}, // saz -> Saur
+ {0xE4120000u, 75u}, // saz -> Saur
{0x80320000u, 46u}, // sba -> Latn
{0x90320000u, 46u}, // sbe -> Latn
{0xBC320000u, 46u}, // sbp -> Latn
@@ -1161,11 +1166,11 @@
{0xD8D20000u, 20u}, // sgw -> Ethi
{0xE4D20000u, 46u}, // sgz -> Latn
{0x73680000u, 46u}, // sh -> Latn
- {0xA0F20000u, 87u}, // shi -> Tfng
+ {0xA0F20000u, 88u}, // shi -> Tfng
{0xA8F20000u, 46u}, // shk -> Latn
{0xB4F20000u, 58u}, // shn -> Mymr
{0xD0F20000u, 1u}, // shu -> Arab
- {0x73690000u, 76u}, // si -> Sinh
+ {0x73690000u, 77u}, // si -> Sinh
{0x8D120000u, 46u}, // sid -> Latn
{0x99120000u, 46u}, // sig -> Latn
{0xAD120000u, 46u}, // sil -> Latn
@@ -1184,7 +1189,7 @@
{0x81920000u, 46u}, // sma -> Latn
{0xA5920000u, 46u}, // smj -> Latn
{0xB5920000u, 46u}, // smn -> Latn
- {0xBD920000u, 72u}, // smp -> Samr
+ {0xBD920000u, 73u}, // smp -> Samr
{0xC1920000u, 46u}, // smq -> Latn
{0xC9920000u, 46u}, // sms -> Latn
{0x736E0000u, 46u}, // sn -> Latn
@@ -1194,10 +1199,10 @@
{0xDDB20000u, 46u}, // snx -> Latn
{0xE1B20000u, 46u}, // sny -> Latn
{0x736F0000u, 46u}, // so -> Latn
- {0x99D20000u, 77u}, // sog -> Sogd
+ {0x99D20000u, 78u}, // sog -> Sogd
{0xA9D20000u, 46u}, // sok -> Latn
{0xC1D20000u, 46u}, // soq -> Latn
- {0xD1D20000u, 89u}, // sou -> Thai
+ {0xD1D20000u, 90u}, // sou -> Thai
{0xE1D20000u, 46u}, // soy -> Latn
{0x8DF20000u, 46u}, // spd -> Latn
{0xADF20000u, 46u}, // spl -> Latn
@@ -1208,7 +1213,7 @@
{0x7372524Fu, 46u}, // sr-RO -> Latn
{0x73725255u, 46u}, // sr-RU -> Latn
{0x73725452u, 46u}, // sr-TR -> Latn
- {0x86320000u, 78u}, // srb -> Sora
+ {0x86320000u, 79u}, // srb -> Sora
{0xB6320000u, 46u}, // srn -> Latn
{0xC6320000u, 46u}, // srr -> Latn
{0xDE320000u, 18u}, // srx -> Deva
@@ -1235,9 +1240,9 @@
{0xB6F20000u, 46u}, // sxn -> Latn
{0xDAF20000u, 46u}, // sxw -> Latn
{0xAF120000u, 7u}, // syl -> Beng
- {0xC7120000u, 80u}, // syr -> Syrc
+ {0xC7120000u, 81u}, // syr -> Syrc
{0xAF320000u, 46u}, // szl -> Latn
- {0x74610000u, 83u}, // ta -> Taml
+ {0x74610000u, 84u}, // ta -> Taml
{0xA4130000u, 18u}, // taj -> Deva
{0xAC130000u, 46u}, // tal -> Latn
{0xB4130000u, 46u}, // tan -> Latn
@@ -1251,11 +1256,11 @@
{0xE4330000u, 46u}, // tbz -> Latn
{0xA0530000u, 46u}, // tci -> Latn
{0xE0530000u, 42u}, // tcy -> Knda
- {0x8C730000u, 81u}, // tdd -> Tale
+ {0x8C730000u, 82u}, // tdd -> Tale
{0x98730000u, 18u}, // tdg -> Deva
{0x9C730000u, 18u}, // tdh -> Deva
{0xD0730000u, 46u}, // tdu -> Latn
- {0x74650000u, 86u}, // te -> Telu
+ {0x74650000u, 87u}, // te -> Telu
{0x8C930000u, 46u}, // ted -> Latn
{0xB0930000u, 46u}, // tem -> Latn
{0xB8930000u, 46u}, // teo -> Latn
@@ -1266,7 +1271,7 @@
{0x88D30000u, 46u}, // tgc -> Latn
{0xB8D30000u, 46u}, // tgo -> Latn
{0xD0D30000u, 46u}, // tgu -> Latn
- {0x74680000u, 89u}, // th -> Thai
+ {0x74680000u, 90u}, // th -> Thai
{0xACF30000u, 18u}, // thl -> Deva
{0xC0F30000u, 18u}, // thq -> Deva
{0xC4F30000u, 18u}, // thr -> Deva
@@ -1305,14 +1310,14 @@
{0x8E530000u, 25u}, // tsd -> Grek
{0x96530000u, 18u}, // tsf -> Deva
{0x9A530000u, 46u}, // tsg -> Latn
- {0xA6530000u, 90u}, // tsj -> Tibt
+ {0xA6530000u, 91u}, // tsj -> Tibt
{0xDA530000u, 46u}, // tsw -> Latn
{0x74740000u, 17u}, // tt -> Cyrl
{0x8E730000u, 46u}, // ttd -> Latn
{0x92730000u, 46u}, // tte -> Latn
{0xA6730000u, 46u}, // ttj -> Latn
{0xC6730000u, 46u}, // ttr -> Latn
- {0xCA730000u, 89u}, // tts -> Thai
+ {0xCA730000u, 90u}, // tts -> Thai
{0xCE730000u, 46u}, // ttt -> Latn
{0x9E930000u, 46u}, // tuh -> Latn
{0xAE930000u, 46u}, // tul -> Latn
@@ -1323,7 +1328,7 @@
{0xD2B30000u, 46u}, // tvu -> Latn
{0x9ED30000u, 46u}, // twh -> Latn
{0xC2D30000u, 46u}, // twq -> Latn
- {0x9AF30000u, 84u}, // txg -> Tang
+ {0x9AF30000u, 85u}, // txg -> Tang
{0x74790000u, 46u}, // ty -> Latn
{0x83130000u, 46u}, // tya -> Latn
{0xD7130000u, 17u}, // tyv -> Cyrl
@@ -1333,7 +1338,7 @@
{0x75670000u, 1u}, // ug -> Arab
{0x75674B5Au, 17u}, // ug-KZ -> Cyrl
{0x75674D4Eu, 17u}, // ug-MN -> Cyrl
- {0x80D40000u, 91u}, // uga -> Ugar
+ {0x80D40000u, 92u}, // uga -> Ugar
{0x756B0000u, 17u}, // uk -> Cyrl
{0xA1740000u, 46u}, // uli -> Latn
{0x85940000u, 46u}, // umb -> Latn
@@ -1346,6 +1351,7 @@
{0xCE340000u, 46u}, // urt -> Latn
{0xDA340000u, 46u}, // urw -> Latn
{0x82540000u, 46u}, // usa -> Latn
+ {0x9E740000u, 46u}, // uth -> Latn
{0xC6740000u, 46u}, // utr -> Latn
{0x9EB40000u, 46u}, // uvh -> Latn
{0xAEB40000u, 46u}, // uvl -> Latn
@@ -1353,7 +1359,7 @@
{0x757A4146u, 1u}, // uz-AF -> Arab
{0x757A434Eu, 17u}, // uz-CN -> Cyrl
{0x98150000u, 46u}, // vag -> Latn
- {0xA0150000u, 92u}, // vai -> Vaii
+ {0xA0150000u, 93u}, // vai -> Vaii
{0xB4150000u, 46u}, // van -> Latn
{0x76650000u, 46u}, // ve -> Latn
{0x88950000u, 46u}, // vec -> Latn
@@ -1376,7 +1382,7 @@
{0xB4160000u, 46u}, // wan -> Latn
{0xC4160000u, 46u}, // war -> Latn
{0xBC360000u, 46u}, // wbp -> Latn
- {0xC0360000u, 86u}, // wbq -> Telu
+ {0xC0360000u, 87u}, // wbq -> Telu
{0xC4360000u, 18u}, // wbr -> Deva
{0xA0560000u, 46u}, // wci -> Latn
{0xC4960000u, 46u}, // wer -> Latn
@@ -1418,9 +1424,9 @@
{0xC5B70000u, 18u}, // xnr -> Deva
{0x99D70000u, 46u}, // xog -> Latn
{0xB5D70000u, 46u}, // xon -> Latn
- {0xC5F70000u, 70u}, // xpr -> Prti
+ {0xC5F70000u, 71u}, // xpr -> Prti
{0x86370000u, 46u}, // xrb -> Latn
- {0x82570000u, 73u}, // xsa -> Sarb
+ {0x82570000u, 74u}, // xsa -> Sarb
{0xA2570000u, 46u}, // xsi -> Latn
{0xB2570000u, 46u}, // xsm -> Latn
{0xC6570000u, 18u}, // xsr -> Deva
@@ -1461,7 +1467,7 @@
{0x98190000u, 46u}, // zag -> Latn
{0xA4790000u, 1u}, // zdj -> Arab
{0x80990000u, 46u}, // zea -> Latn
- {0x9CD90000u, 87u}, // zgh -> Tfng
+ {0x9CD90000u, 88u}, // zgh -> Tfng
{0x7A680000u, 28u}, // zh -> Hans
{0x7A684155u, 29u}, // zh-AU -> Hant
{0x7A68424Eu, 29u}, // zh-BN -> Hant
@@ -1470,7 +1476,6 @@
{0x7A68484Bu, 29u}, // zh-HK -> Hant
{0x7A684944u, 29u}, // zh-ID -> Hant
{0x7A684D4Fu, 29u}, // zh-MO -> Hant
- {0x7A684D59u, 29u}, // zh-MY -> Hant
{0x7A685041u, 29u}, // zh-PA -> Hant
{0x7A685046u, 29u}, // zh-PF -> Hant
{0x7A685048u, 29u}, // zh-PH -> Hant
@@ -1592,6 +1597,7 @@
0xD701434D4C61746ELLU, // byv_Latn_CM
0x93214D4C4C61746ELLU, // bze_Latn_ML
0x636145534C61746ELLU, // ca_Latn_ES
+ 0x8C0255534C61746ELLU, // cad_Latn_US
0x9C424E474C61746ELLU, // cch_Latn_NG
0xBC42424443616B6DLLU, // ccp_Cakm_BD
0x636552554379726CLLU, // ce_Cyrl_RU
@@ -1627,6 +1633,7 @@
0x637652554379726CLLU, // cv_Cyrl_RU
0x637947424C61746ELLU, // cy_Latn_GB
0x6461444B4C61746ELLU, // da_Latn_DK
+ 0x940343494C61746ELLU, // daf_Latn_CI
0xA80355534C61746ELLU, // dak_Latn_US
0xC40352554379726CLLU, // dar_Cyrl_RU
0xD4034B454C61746ELLU, // dav_Latn_KE
@@ -1636,7 +1643,7 @@
0xC4C343414C61746ELLU, // dgr_Latn_CA
0x91234E454C61746ELLU, // dje_Latn_NE
0xA5A343494C61746ELLU, // dnj_Latn_CI
- 0xA1C3494E41726162LLU, // doi_Arab_IN
+ 0xA1C3494E44657661LLU, // doi_Deva_IN
0x9E23434E4D6F6E67LLU, // drh_Mong_CN
0x864344454C61746ELLU, // dsb_Latn_DE
0xB2634D4C4C61746ELLU, // dtm_Latn_ML
@@ -1839,6 +1846,7 @@
0xC6AA49444C61746ELLU, // kvr_Latn_ID
0xDEAA504B41726162LLU, // kvx_Arab_PK
0x6B7747424C61746ELLU, // kw_Latn_GB
+ 0xAEEA494E44657661LLU, // kxl_Deva_IN
0xB2EA544854686169LLU, // kxm_Thai_TH
0xBEEA504B41726162LLU, // kxp_Arab_PK
0x6B79434E41726162LLU, // ky_Arab_CN
@@ -2047,7 +2055,7 @@
0x9C1252554379726CLLU, // sah_Cyrl_RU
0xC0124B454C61746ELLU, // saq_Latn_KE
0xC81249444C61746ELLU, // sas_Latn_ID
- 0xCC12494E4C61746ELLU, // sat_Latn_IN
+ 0xCC12494E4F6C636BLLU, // sat_Olck_IN
0xD412534E4C61746ELLU, // sav_Latn_SN
0xE412494E53617572LLU, // saz_Saur_IN
0xBC32545A4C61746ELLU, // sbp_Latn_TZ
@@ -2149,6 +2157,7 @@
0x747254524C61746ELLU, // tr_Latn_TR
0xD23354524C61746ELLU, // tru_Latn_TR
0xD63354574C61746ELLU, // trv_Latn_TW
+ 0xDA33504B41726162LLU, // trw_Arab_PK
0x74735A414C61746ELLU, // ts_Latn_ZA
0x8E5347524772656BLLU, // tsd_Grek_GR
0x96534E5044657661LLU, // tsf_Deva_NP
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index bce70e2..2233827 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -30,6 +30,7 @@
#include <memory>
#include <set>
#include <type_traits>
+#include <vector>
#include <android-base/macros.h>
#include <androidfw/ByteBucketArray.h>
@@ -1029,7 +1030,7 @@
// But we don't want to hit the cache, so instead we will have a
// local temporary allocation for the conversions.
size_t convBufferLen = strLen + 4;
- char16_t* convBuffer = (char16_t*)calloc(convBufferLen, sizeof(char16_t));
+ std::vector<char16_t> convBuffer(convBufferLen);
ssize_t l = 0;
ssize_t h = mHeader->stringCount-1;
@@ -1043,8 +1044,8 @@
}
if (s.has_value()) {
char16_t* end = utf8_to_utf16(reinterpret_cast<const uint8_t*>(s->data()),
- s->size(), convBuffer, convBufferLen);
- c = strzcmp16(convBuffer, end-convBuffer, str, strLen);
+ s->size(), convBuffer.data(), convBufferLen);
+ c = strzcmp16(convBuffer.data(), end-convBuffer.data(), str, strLen);
}
if (kDebugStringPoolNoisy) {
ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
@@ -1054,7 +1055,6 @@
if (kDebugStringPoolNoisy) {
ALOGI("MATCH!");
}
- free(convBuffer);
return mid;
} else if (c < 0) {
l = mid + 1;
@@ -1062,7 +1062,6 @@
h = mid - 1;
}
}
- free(convBuffer);
} else {
// It is unusual to get the ID from an unsorted string block...
// most often this happens because we want to get IDs for style
diff --git a/libs/hwui/jni/fonts/Font.cpp b/libs/hwui/jni/fonts/Font.cpp
index 943423f..b944310 100644
--- a/libs/hwui/jni/fonts/Font.cpp
+++ b/libs/hwui/jni/fonts/Font.cpp
@@ -277,6 +277,28 @@
}
return env->NewStringUTF(psName->c_str());
}
+
+static jint FontFileUtil_isPostScriptType1Font(JNIEnv* env, jobject, jobject buffer, jint index) {
+ NPE_CHECK_RETURN_ZERO(env, buffer);
+ const void* fontPtr = env->GetDirectBufferAddress(buffer);
+ if (fontPtr == nullptr) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "Not a direct buffer");
+ return -1;
+ }
+ jlong fontSize = env->GetDirectBufferCapacity(buffer);
+ if (fontSize <= 0) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "buffer size must not be zero or negative");
+ return -1;
+ }
+ minikin::FontFileParser parser(fontPtr, fontSize, index);
+ std::optional<bool> isType1 = parser.isPostScriptType1Font();
+ if (!isType1.has_value()) {
+ return -1; // not an OpenType font. HarfBuzz failed to parse it.
+ }
+ return isType1.value();
+}
+
///////////////////////////////////////////////////////////////////////////////
static const JNINativeMethod gFontBuilderMethods[] = {
@@ -304,6 +326,8 @@
{ "nGetFontRevision", "(Ljava/nio/ByteBuffer;I)J", (void*) FontFileUtil_getFontRevision },
{ "nGetFontPostScriptName", "(Ljava/nio/ByteBuffer;I)Ljava/lang/String;",
(void*) FontFileUtil_getFontPostScriptName },
+ { "nIsPostScriptType1Font", "(Ljava/nio/ByteBuffer;I)I",
+ (void*) FontFileUtil_isPostScriptType1Font },
};
int register_android_graphics_fonts_Font(JNIEnv* env) {
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 2703ee3..49f9d66 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -21,8 +21,10 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringDef;
+import android.annotation.TestApi;
import android.app.ActivityThread;
import android.compat.annotation.UnsupportedAppUsage;
+import android.media.metrics.PlaybackComponent;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.Looper;
@@ -35,8 +37,8 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
@@ -49,7 +51,6 @@
import java.util.function.Consumer;
import java.util.function.Function;
-
/**
* MediaDrm can be used to obtain keys for decrypting protected media streams, in
* conjunction with {@link android.media.MediaCrypto}. The MediaDrm APIs
@@ -963,14 +964,30 @@
* a session
*/
@NonNull
- public native byte[] openSession(@SecurityLevel int level) throws
+ public byte[] openSession(@SecurityLevel int level) throws
+ NotProvisionedException, ResourceBusyException {
+ byte[] sessionId = openSessionNative(level);
+ mPlaybackComponentMap.put(ByteBuffer.wrap(sessionId), new PlaybackComponentImpl(sessionId));
+ return sessionId;
+ }
+
+ @NonNull
+ private native byte[] openSessionNative(int level) throws
NotProvisionedException, ResourceBusyException;
/**
* Close a session on the MediaDrm object that was previously opened
* with {@link #openSession}.
*/
- public native void closeSession(@NonNull byte[] sessionId);
+ public void closeSession(@NonNull byte[] sessionId) {
+ closeSessionNative(sessionId);
+ mPlaybackComponentMap.remove(ByteBuffer.wrap(sessionId));
+ }
+
+ private native void closeSessionNative(@NonNull byte[] sessionId);
+
+ private final Map<ByteBuffer, PlaybackComponent> mPlaybackComponentMap
+ = new ConcurrentHashMap<>();
/**
* This key request type species that the keys will be for online use, they will
@@ -2056,6 +2073,7 @@
mCloseGuard.close();
if (mClosed.compareAndSet(false, true)) {
native_release();
+ mPlaybackComponentMap.clear();
}
}
@@ -2430,4 +2448,49 @@
public static final String EVENT_SESSION_RECLAIMED_COUNT
= "drm.mediadrm.event.SESSION_RECLAIMED.count";
}
+
+ /**
+ * Obtain a {@link PlaybackComponent} associated with a DRM session.
+ * Call {@link PlaybackComponent#setPlaybackId(String)} on the returned object
+ * to associate a playback session with the DRM session.
+ *
+ * @param sessionId a DRM session ID obtained from {@link #openSession()}
+ * @return a {@link PlaybackComponent} associated with the session,
+ * or {@code null} if the session is closed or does not exist.
+ * @see PlaybackComponent
+ * @hide
+ */
+ @TestApi
+ @Nullable
+ public PlaybackComponent getPlaybackComponent(@NonNull byte[] sessionId) {
+ if (sessionId == null) {
+ throw new IllegalArgumentException("sessionId is null");
+ }
+ return mPlaybackComponentMap.get(ByteBuffer.wrap(sessionId));
+ }
+
+ private native void setPlaybackId(byte[] sessionId, String playbackId);
+
+ private final class PlaybackComponentImpl implements PlaybackComponent {
+ private final byte[] mSessionId;
+ private String mPlaybackId = "";
+
+ public PlaybackComponentImpl(byte[] sessionId) {
+ mSessionId = sessionId;
+ }
+
+ @Override
+ public void setPlaybackId(@NonNull String playbackId) {
+ if (playbackId == null) {
+ throw new IllegalArgumentException("playbackId is null");
+ }
+ MediaDrm.this.setPlaybackId(mSessionId, playbackId);
+ mPlaybackId = playbackId;
+ }
+
+ @Override
+ @NonNull public String getPlaybackId() {
+ return mPlaybackId;
+ }
+ }
}
diff --git a/media/java/android/media/metrics/PlaybackComponent.java b/media/java/android/media/metrics/PlaybackComponent.java
index 625dd0a..94e55b4 100644
--- a/media/java/android/media/metrics/PlaybackComponent.java
+++ b/media/java/android/media/metrics/PlaybackComponent.java
@@ -17,11 +17,13 @@
package android.media.metrics;
import android.annotation.NonNull;
+import android.annotation.TestApi;
/**
* Interface for playback related components used by playback metrics.
* @hide
*/
+@TestApi
public interface PlaybackComponent {
/**
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 4f27b197..6141b7f 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -769,10 +769,12 @@
try {
Log.i(TAG, "openFile with transcode support: " + path);
- // TODO(b/158466651): Pass the |transcode| variable as flag to openFile
- Bundle bundle = null;
- if (!transcode) {
- bundle = new Bundle();
+ Bundle bundle = new Bundle();
+ if (transcode) {
+ bundle.putParcelable(MediaStore.EXTRA_MEDIA_CAPABILITIES,
+ new ApplicationMediaCapabilities.Builder().addUnsupportedVideoMimeType(
+ MediaFormat.MIMETYPE_VIDEO_HEVC).build());
+ } else {
bundle.putParcelable(MediaStore.EXTRA_MEDIA_CAPABILITIES,
new ApplicationMediaCapabilities.Builder().addSupportedVideoMimeType(
MediaFormat.MIMETYPE_VIDEO_HEVC).build());
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index babb16b..0e8719e 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -1978,6 +1978,24 @@
return drm->requiresSecureDecoder(mimeType.c_str(), securityLevel);
}
+static void android_media_MediaDrm_setPlaybackId(
+ JNIEnv *env, jobject thiz, jbyteArray jsessionId,
+ jstring jplaybackId) {
+ sp<IDrm> drm = GetDrm(env, thiz);
+ if (!CheckSession(env, drm, jsessionId)) {
+ return;
+ }
+
+ Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+
+ String8 playbackId;
+ if (jplaybackId != NULL) {
+ playbackId = JStringToString8(env, jplaybackId);
+ }
+ status_t err = drm->setPlaybackId(sessionId, playbackId.c_str());
+ throwExceptionAsNecessary(env, err, "Failed to set playbackId");
+}
+
static const JNINativeMethod gMethods[] = {
{ "native_release", "()V", (void *)android_media_MediaDrm_native_release },
@@ -1992,10 +2010,10 @@
{ "isCryptoSchemeSupportedNative", "([BLjava/lang/String;I)Z",
(void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
- { "openSession", "(I)[B",
+ { "openSessionNative", "(I)[B",
(void *)android_media_MediaDrm_openSession },
- { "closeSession", "([B)V",
+ { "closeSessionNative", "([B)V",
(void *)android_media_MediaDrm_closeSession },
{ "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
@@ -2102,6 +2120,9 @@
{ "requiresSecureDecoder", "(Ljava/lang/String;I)Z",
(void *)android_media_MediaDrm_requiresSecureDecoder },
+
+ { "setPlaybackId", "([BLjava/lang/String;)V",
+ (void *)android_media_MediaDrm_setPlaybackId },
};
int register_android_media_Drm(JNIEnv *env) {
diff --git a/media/jni/tuner/LnbClient.cpp b/media/jni/tuner/LnbClient.cpp
index 7f3916f..77583b8 100644
--- a/media/jni/tuner/LnbClient.cpp
+++ b/media/jni/tuner/LnbClient.cpp
@@ -19,6 +19,7 @@
#include <android-base/logging.h>
#include <utils/Log.h>
+#include "TunerClient.h"
#include "LnbClient.h"
using ::android::hardware::tv::tuner::V1_0::Result;
@@ -27,14 +28,13 @@
/////////////// LnbClient ///////////////////////
-// TODO: pending aidl interface
-LnbClient::LnbClient() {
- //mTunerLnb = tunerLnb;
+LnbClient::LnbClient(shared_ptr<ITunerLnb> tunerLnb) {
+ mTunerLnb = tunerLnb;
mId = -1;
}
LnbClient::~LnbClient() {
- //mTunerLnb = NULL;
+ mTunerLnb = NULL;
mLnb = NULL;
mId = -1;
}
@@ -45,19 +45,21 @@
}
Result LnbClient::setCallback(sp<LnbClientCallback> cb) {
- // TODO: pending aidl interface
- /*if (mTunerFrontend != NULL) {
+ if (mTunerLnb != NULL) {
mAidlCallback = ::ndk::SharedRefBase::make<TunerLnbCallback>(cb);
- mTunerLnb->setCallback(mAidlCallback);
- return Result::SUCCESS;
- }*/
+ Status s = mTunerLnb->setCallback(mAidlCallback);
+ return TunerClient::getServiceSpecificErrorCode(s);
+ }
mHidlCallback = new HidlLnbCallback(cb);
return mLnb->setCallback(mHidlCallback);
}
Result LnbClient::setVoltage(LnbVoltage voltage) {
- // TODO: pending aidl interface
+ if (mTunerLnb != NULL) {
+ Status s = mTunerLnb->setVoltage((int)voltage);
+ return TunerClient::getServiceSpecificErrorCode(s);
+ }
if (mLnb != NULL) {
return mLnb->setVoltage(voltage);
@@ -67,7 +69,10 @@
}
Result LnbClient::setTone(LnbTone tone) {
- // TODO: pending aidl interface
+ if (mTunerLnb != NULL) {
+ Status s = mTunerLnb->setTone((int)tone);
+ return TunerClient::getServiceSpecificErrorCode(s);
+ }
if (mLnb != NULL) {
return mLnb->setTone(tone);
@@ -77,7 +82,10 @@
}
Result LnbClient::setSatellitePosition(LnbPosition position) {
- // TODO: pending aidl interface
+ if (mTunerLnb != NULL) {
+ Status s = mTunerLnb->setSatellitePosition((int)position);
+ return TunerClient::getServiceSpecificErrorCode(s);
+ }
if (mLnb != NULL) {
return mLnb->setSatellitePosition(position);
@@ -87,7 +95,10 @@
}
Result LnbClient::sendDiseqcMessage(vector<uint8_t> diseqcMessage) {
- // TODO: pending aidl interface
+ if (mTunerLnb != NULL) {
+ Status s = mTunerLnb->sendDiseqcMessage(diseqcMessage);
+ return TunerClient::getServiceSpecificErrorCode(s);
+ }
if (mLnb != NULL) {
return mLnb->sendDiseqcMessage(diseqcMessage);
@@ -97,7 +108,10 @@
}
Result LnbClient::close() {
- // TODO: pending aidl interface
+ if (mTunerLnb != NULL) {
+ Status s = mTunerLnb->close();
+ return TunerClient::getServiceSpecificErrorCode(s);
+ }
if (mLnb != NULL) {
return mLnb->close();
@@ -125,6 +139,25 @@
return Void();
}
-/////////////// LnbClient Helper Methods ///////////////////////
+/////////////// TunerLnbCallback ///////////////////////
+TunerLnbCallback::TunerLnbCallback(sp<LnbClientCallback> lnbClientCallback)
+ : mLnbClientCallback(lnbClientCallback) {}
+
+Status TunerLnbCallback::onEvent(int lnbEventType) {
+ if (mLnbClientCallback != NULL) {
+ mLnbClientCallback->onEvent(static_cast<LnbEventType>(lnbEventType));
+ return Status::ok();
+ }
+ return Status::fromServiceSpecificError(static_cast<int32_t>(Result::INVALID_STATE));
+}
+
+Status TunerLnbCallback::onDiseqcMessage(const vector<uint8_t>& diseqcMessage) {
+ if (mLnbClientCallback != NULL) {
+ hidl_vec<uint8_t> msg(begin(diseqcMessage), end(diseqcMessage));
+ mLnbClientCallback->onDiseqcMessage(msg);
+ return Status::ok();
+ }
+ return Status::fromServiceSpecificError(static_cast<int32_t>(Result::INVALID_STATE));
+}
} // namespace android
diff --git a/media/jni/tuner/LnbClient.h b/media/jni/tuner/LnbClient.h
index 533a996..2465120 100644
--- a/media/jni/tuner/LnbClient.h
+++ b/media/jni/tuner/LnbClient.h
@@ -17,14 +17,18 @@
#ifndef _ANDROID_MEDIA_TV_LNB_CLIENT_H_
#define _ANDROID_MEDIA_TV_LNB_CLIENT_H_
-//#include <aidl/android/media/tv/tuner/ITunerLnb.h>
+#include <aidl/android/media/tv/tuner/BnTunerLnbCallback.h>
+#include <aidl/android/media/tv/tuner/ITunerLnb.h>
#include <android/hardware/tv/tuner/1.0/ILnb.h>
#include <android/hardware/tv/tuner/1.0/ILnbCallback.h>
#include <android/hardware/tv/tuner/1.1/types.h>
#include "LnbClientCallback.h"
-//using ::aidl::android::media::tv::tuner::ITunerLnb;
+using Status = ::ndk::ScopedAStatus;
+
+using ::aidl::android::media::tv::tuner::BnTunerLnbCallback;
+using ::aidl::android::media::tv::tuner::ITunerLnb;
using ::android::hardware::Return;
using ::android::hardware::Void;
@@ -42,17 +46,17 @@
namespace android {
// TODO: pending aidl interface
-/*class TunerLnbCallback : public BnTunerLnbCallback {
+class TunerLnbCallback : public BnTunerLnbCallback {
public:
TunerLnbCallback(sp<LnbClientCallback> lnbClientCallback);
Status onEvent(int lnbEventType);
- Status onDiseqcMessage(vector<uint8_t> diseqcMessage);
+ Status onDiseqcMessage(const vector<uint8_t>& diseqcMessage);
private:
sp<LnbClientCallback> mLnbClientCallback;
-};*/
+};
struct HidlLnbCallback : public ILnbCallback {
@@ -68,8 +72,7 @@
struct LnbClient : public RefBase {
public:
- // TODO: add TunerLnb as parameter.
- LnbClient();
+ LnbClient(shared_ptr<ITunerLnb> tunerLnb);
~LnbClient();
// TODO: remove after migration to Tuner Service is done.
@@ -114,8 +117,7 @@
* An AIDL Tuner Lnb Singleton assigned at the first time the Tuner Client
* opens an Lnb. Default null when lnb is not opened.
*/
- // TODO: pending on aidl interface
- //shared_ptr<ITunerLnb> mTunerLnb;
+ shared_ptr<ITunerLnb> mTunerLnb;
/**
* A Lnb HAL interface that is ready before migrating to the TunerLnb.
@@ -124,7 +126,7 @@
*/
sp<ILnb> mLnb;
- //shared_ptr<TunerLnbCallback> mAidlCallback;
+ shared_ptr<TunerLnbCallback> mAidlCallback;
sp<HidlLnbCallback> mHidlCallback;
LnbId mId;
diff --git a/media/jni/tuner/TunerClient.cpp b/media/jni/tuner/TunerClient.cpp
index f5e3524..498ba0e 100644
--- a/media/jni/tuner/TunerClient.cpp
+++ b/media/jni/tuner/TunerClient.cpp
@@ -229,15 +229,15 @@
sp<LnbClient> TunerClient::openLnb(int lnbHandle) {
if (mTunerService != NULL) {
// TODO: handle error code
- /*shared_ptr<ITunerLnb> tunerLnb;
- mTunerService->openLnb(demuxHandle, &tunerLnb);
- return new LnbClient(tunerLnb);*/
+ shared_ptr<ITunerLnb> tunerLnb;
+ mTunerService->openLnb(lnbHandle, &tunerLnb);
+ return new LnbClient(tunerLnb);
}
if (mTuner != NULL) {
int id = getResourceIdFromHandle(lnbHandle, LNB);
// TODO: pending aidl interface
- sp<LnbClient> lnbClient = new LnbClient();
+ sp<LnbClient> lnbClient = new LnbClient(NULL);
sp<ILnb> hidlLnb = openHidlLnbById(id);
if (hidlLnb != NULL) {
lnbClient->setHidlLnb(hidlLnb);
@@ -252,14 +252,14 @@
sp<LnbClient> TunerClient::openLnbByName(string lnbName) {
if (mTunerService != NULL) {
// TODO: handle error code
- /*shared_ptr<ITunerLnb> tunerLnb;
+ shared_ptr<ITunerLnb> tunerLnb;
mTunerService->openLnbByName(lnbName, &tunerLnb);
- return new LnbClient(tunerLnb);*/
+ return new LnbClient(tunerLnb);
}
if (mTuner != NULL) {
// TODO: pending aidl interface
- sp<LnbClient> lnbClient = new LnbClient();
+ sp<LnbClient> lnbClient = new LnbClient(NULL);
LnbId id;
sp<ILnb> hidlLnb = openHidlLnbByName(lnbName, id);
if (hidlLnb != NULL) {
diff --git a/media/jni/tuner/TunerClient.h b/media/jni/tuner/TunerClient.h
index 8a1181a..733ee6b 100644
--- a/media/jni/tuner/TunerClient.h
+++ b/media/jni/tuner/TunerClient.h
@@ -20,6 +20,7 @@
#include <aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.h>
#include <aidl/android/media/tv/tuner/ITunerService.h>
#include <aidl/android/media/tv/tuner/TunerFrontendInfo.h>
+#include <android/binder_parcel_utils.h>
#include <android/hardware/tv/tuner/1.1/ITuner.h>
#include <android/hardware/tv/tuner/1.1/types.h>
@@ -28,6 +29,8 @@
#include "DescramblerClient.h"
#include "LnbClient.h"
+using Status = ::ndk::ScopedAStatus;
+
using ::aidl::android::media::tv::tuner::ITunerService;
using ::aidl::android::media::tv::tuner::TunerFrontendInfo;
using ::aidl::android::media::tv::tunerresourcemanager::ITunerResourceManager;
@@ -132,6 +135,15 @@
*/
int getHalTunerVersion() { return mTunerVersion; }
+ static Result getServiceSpecificErrorCode(Status& s) {
+ if (s.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+ return static_cast<Result>(s.getServiceSpecificError());
+ } else if (s.isOk()) {
+ return Result::SUCCESS;
+ }
+ return Result::UNKNOWN_ERROR;
+ }
+
private:
sp<ITuner> getHidlTuner();
sp<IFrontend> openHidlFrontendById(int id);
diff --git a/packages/CompanionDeviceManager/res/values-de/strings.xml b/packages/CompanionDeviceManager/res/values-de/strings.xml
index ead68e3..b643eb2 100644
--- a/packages/CompanionDeviceManager/res/values-de/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-de/strings.xml
@@ -19,11 +19,9 @@
<string name="app_label" msgid="4470785958457506021">"Begleitgerät-Manager"</string>
<string name="chooser_title" msgid="2262294130493605839">"Gerät (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) auswählen, das von <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> verwaltet werden soll"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"Gerät"</string>
- <!-- no translation found for profile_name_watch (576290739483672360) -->
- <skip />
+ <string name="profile_name_watch" msgid="576290739483672360">"Smartwatch"</string>
<string name="confirmation_title" msgid="4751119145078041732">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> zum Verwalten deines Geräts (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>) festlegen – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string>
- <!-- no translation found for profile_summary (2009764182871566255) -->
- <skip />
+ <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> ist erforderlich, um dein Gerät (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>) zu verwalten. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
<string name="consent_yes" msgid="4055438216605487056">"Ja"</string>
<string name="consent_no" msgid="1335543792857823917">"Nein danke"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-gu/strings.xml b/packages/CompanionDeviceManager/res/values-gu/strings.xml
index e99a3cd..7e41042 100644
--- a/packages/CompanionDeviceManager/res/values-gu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gu/strings.xml
@@ -19,11 +19,9 @@
<string name="app_label" msgid="4470785958457506021">"કમ્પેનિયન ડિવાઇસ મેનેજર"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> દ્વારા મેનેજ કરવા માટે કોઈ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> પસંદ કરો"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ડિવાઇસ"</string>
- <!-- no translation found for profile_name_watch (576290739483672360) -->
- <skip />
+ <string name="profile_name_watch" msgid="576290739483672360">"સ્માર્ટવૉચ"</string>
<string name="confirmation_title" msgid="4751119145078041732">"તમારા <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>ને મેનેજ કરવા માટે <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> સેટ કરો"</string>
- <!-- no translation found for profile_summary (2009764182871566255) -->
- <skip />
+ <string name="profile_summary" msgid="2009764182871566255">"તમારા <xliff:g id="PROFILE_NAME">%2$s</xliff:g>ને મેનેજ કરવા માટે <xliff:g id="APP_NAME">%1$s</xliff:g> જરૂરી છે. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
<string name="consent_yes" msgid="4055438216605487056">"હા"</string>
<string name="consent_no" msgid="1335543792857823917">"ના, આભાર"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-iw/strings.xml b/packages/CompanionDeviceManager/res/values-iw/strings.xml
index 33950eb..8663e56 100644
--- a/packages/CompanionDeviceManager/res/values-iw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-iw/strings.xml
@@ -19,11 +19,9 @@
<string name="app_label" msgid="4470785958457506021">"ניהול מכשיר מותאם"</string>
<string name="chooser_title" msgid="2262294130493605839">"בחירה של <xliff:g id="PROFILE_NAME">%1$s</xliff:g> לניהול באמצעות <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"מכשיר"</string>
- <!-- no translation found for profile_name_watch (576290739483672360) -->
- <skip />
+ <string name="profile_name_watch" msgid="576290739483672360">"שעון"</string>
<string name="confirmation_title" msgid="4751119145078041732">"הגדרה של <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> לניהול <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string>
- <!-- no translation found for profile_summary (2009764182871566255) -->
- <skip />
+ <string name="profile_summary" msgid="2009764182871566255">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> נדרשת לניהול של <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
<string name="consent_yes" msgid="4055438216605487056">"כן"</string>
<string name="consent_no" msgid="1335543792857823917">"לא תודה"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ja/strings.xml b/packages/CompanionDeviceManager/res/values-ja/strings.xml
index b695d9d..ca17336 100644
--- a/packages/CompanionDeviceManager/res/values-ja/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ja/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4470785958457506021">"コンパニオン デバイス マネージャ"</string>
- <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> の管理対象となる <xliff:g id="PROFILE_NAME">%1$s</xliff:g> の選択"</string>
+ <string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> の管理対象となる<xliff:g id="PROFILE_NAME">%1$s</xliff:g>の選択"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"デバイス"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ウォッチ"</string>
<string name="confirmation_title" msgid="4751119145078041732">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> で <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> を管理するよう設定する"</string>
diff --git a/packages/CompanionDeviceManager/res/values-kn/strings.xml b/packages/CompanionDeviceManager/res/values-kn/strings.xml
index f4ae18f..0225166 100644
--- a/packages/CompanionDeviceManager/res/values-kn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kn/strings.xml
@@ -19,11 +19,9 @@
<string name="app_label" msgid="4470785958457506021">"ಕಂಪ್ಯಾನಿಯನ್ ಸಾಧನ ನಿರ್ವಾಹಕರು"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ಮೂಲಕ ನಿರ್ವಹಿಸಬೇಕಾದ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ಸಾಧನ"</string>
- <!-- no translation found for profile_name_watch (576290739483672360) -->
- <skip />
+ <string name="profile_name_watch" msgid="576290739483672360">"ವೀಕ್ಷಿಸಿ"</string>
<string name="confirmation_title" msgid="4751119145078041732">"ನಿಮ್ಮ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> ಅನ್ನು ನಿರ್ವಹಿಸಲು, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ಅನ್ನು ನಿರ್ವಹಿಸಿ"</string>
- <!-- no translation found for profile_summary (2009764182871566255) -->
- <skip />
+ <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> ಅನ್ನು ನಿರ್ವಹಿಸಲು, <xliff:g id="APP_NAME">%1$s</xliff:g> ಅಗತ್ಯವಿದೆ. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
<string name="consent_yes" msgid="4055438216605487056">"ಹೌದು"</string>
<string name="consent_no" msgid="1335543792857823917">"ಬೇಡ, ಧನ್ಯವಾದಗಳು"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-mr/strings.xml b/packages/CompanionDeviceManager/res/values-mr/strings.xml
index 68f9109..144698b 100644
--- a/packages/CompanionDeviceManager/res/values-mr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mr/strings.xml
@@ -19,11 +19,9 @@
<string name="app_label" msgid="4470785958457506021">"सहयोगी डिव्हाइस व्यवस्थापक"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> द्वारे व्यवस्थापित करण्यासाठी <xliff:g id="PROFILE_NAME">%1$s</xliff:g> निवडा"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"डिव्हाइस"</string>
- <!-- no translation found for profile_name_watch (576290739483672360) -->
- <skip />
+ <string name="profile_name_watch" msgid="576290739483672360">"पाहा"</string>
<string name="confirmation_title" msgid="4751119145078041732">"तुमची <xliff:g id="PROFILE_NAME">%2$s</xliff:g> व्यवस्थापित करण्यासाठी <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> सेट करा - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string>
- <!-- no translation found for profile_summary (2009764182871566255) -->
- <skip />
+ <string name="profile_summary" msgid="2009764182871566255">"तुमची <xliff:g id="PROFILE_NAME">%2$s</xliff:g> व्यवस्थापित करण्यासाठी <xliff:g id="APP_NAME">%1$s</xliff:g> आवश्यक आहे. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
<string name="consent_yes" msgid="4055438216605487056">"होय"</string>
<string name="consent_no" msgid="1335543792857823917">"नाही, नको"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ms/strings.xml b/packages/CompanionDeviceManager/res/values-ms/strings.xml
index 1188922..7bea2c9 100644
--- a/packages/CompanionDeviceManager/res/values-ms/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ms/strings.xml
@@ -19,11 +19,9 @@
<string name="app_label" msgid="4470785958457506021">"Pengurus Peranti Rakan"</string>
<string name="chooser_title" msgid="2262294130493605839">"Pilih <xliff:g id="PROFILE_NAME">%1$s</xliff:g> untuk diurus oleh <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"peranti"</string>
- <!-- no translation found for profile_name_watch (576290739483672360) -->
- <skip />
+ <string name="profile_name_watch" msgid="576290739483672360">"jam tangan"</string>
<string name="confirmation_title" msgid="4751119145078041732">"Tetapkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> untuk mengurus <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> anda"</string>
- <!-- no translation found for profile_summary (2009764182871566255) -->
- <skip />
+ <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> diperlukan untuk mengurus <xliff:g id="PROFILE_NAME">%2$s</xliff:g> anda. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
<string name="consent_yes" msgid="4055438216605487056">"Ya"</string>
<string name="consent_no" msgid="1335543792857823917">"Tidak perlu"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-or/strings.xml b/packages/CompanionDeviceManager/res/values-or/strings.xml
index d1aa50b..c8c680f 100644
--- a/packages/CompanionDeviceManager/res/values-or/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-or/strings.xml
@@ -19,11 +19,9 @@
<string name="app_label" msgid="4470785958457506021">"ସହଯୋଗୀ ଡିଭାଇସ୍ ପରିଚାଳକ"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ଦ୍ୱାରା ପରିଚାଳିତ ହେବା ପାଇଁ ଏକ <xliff:g id="PROFILE_NAME">%1$s</xliff:g>କୁ ବାଛନ୍ତୁ"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ଡିଭାଇସ୍"</string>
- <!-- no translation found for profile_name_watch (576290739483672360) -->
- <skip />
+ <string name="profile_name_watch" msgid="576290739483672360">"ୱାଚ୍"</string>
<string name="confirmation_title" msgid="4751119145078041732">"ଆପଣଙ୍କ <xliff:g id="PROFILE_NAME">%2$s</xliff:g>କୁ ପରିଚାଳନା କରିବା ପାଇଁ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>କୁ ସେଟ୍ କରନ୍ତୁ - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string>
- <!-- no translation found for profile_summary (2009764182871566255) -->
- <skip />
+ <string name="profile_summary" msgid="2009764182871566255">"ଆପଣଙ୍କ <xliff:g id="PROFILE_NAME">%2$s</xliff:g>କୁ ପରିଚାଳନା କରିବା ପାଇଁ <xliff:g id="APP_NAME">%1$s</xliff:g> ଆବଶ୍ୟକ। <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
<string name="consent_yes" msgid="4055438216605487056">"ହଁ"</string>
<string name="consent_no" msgid="1335543792857823917">"ନା, ଧନ୍ୟବାଦ"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-pa/strings.xml b/packages/CompanionDeviceManager/res/values-pa/strings.xml
index ff211f2..0da9410 100644
--- a/packages/CompanionDeviceManager/res/values-pa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pa/strings.xml
@@ -19,11 +19,9 @@
<string name="app_label" msgid="4470785958457506021">"ਸੰਬੰਧੀ ਡੀਵਾਈਸ ਪ੍ਰਬੰਧਕ"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ਵੱਲੋਂ ਪ੍ਰਬੰਧਿਤ ਕੀਤੇ ਜਾਣ ਲਈ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ਚੁਣੋ"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"ਡੀਵਾਈਸ"</string>
- <!-- no translation found for profile_name_watch (576290739483672360) -->
- <skip />
+ <string name="profile_name_watch" msgid="576290739483672360">"ਸਮਾਰਟ-ਵਾਚ"</string>
<string name="confirmation_title" msgid="4751119145078041732">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ਨੂੰ ਤੁਹਾਡਾ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਲਈ ਸੈੱਟ ਕਰੋ"</string>
- <!-- no translation found for profile_summary (2009764182871566255) -->
- <skip />
+ <string name="profile_summary" msgid="2009764182871566255">"ਤੁਹਾਡੇ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਲਈ <xliff:g id="APP_NAME">%1$s</xliff:g> ਦੀ ਲੋੜ ਹੈ। <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
<string name="consent_yes" msgid="4055438216605487056">"ਹਾਂ"</string>
<string name="consent_no" msgid="1335543792857823917">"ਨਹੀਂ ਧੰਨਵਾਦ"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-sq/strings.xml b/packages/CompanionDeviceManager/res/values-sq/strings.xml
index 4c308e8..6fa759c 100644
--- a/packages/CompanionDeviceManager/res/values-sq/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sq/strings.xml
@@ -19,11 +19,9 @@
<string name="app_label" msgid="4470785958457506021">"Menaxheri i pajisjes shoqëruese"</string>
<string name="chooser_title" msgid="2262294130493605839">"Zgjidh një profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> që do të menaxhohet nga <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"pajisja"</string>
- <!-- no translation found for profile_name_watch (576290739483672360) -->
- <skip />
+ <string name="profile_name_watch" msgid="576290739483672360">"ora inteligjente"</string>
<string name="confirmation_title" msgid="4751119145078041732">"Cakto <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> që të menaxhojë profilin tënd <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string>
- <!-- no translation found for profile_summary (2009764182871566255) -->
- <skip />
+ <string name="profile_summary" msgid="2009764182871566255">"Nevojitet <xliff:g id="APP_NAME">%1$s</xliff:g> për të menaxhuar profilin tënd të <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
<string name="consent_yes" msgid="4055438216605487056">"Po"</string>
<string name="consent_no" msgid="1335543792857823917">"Jo, faleminderit"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-ur/strings.xml b/packages/CompanionDeviceManager/res/values-ur/strings.xml
index 967b7f9..dce1815 100644
--- a/packages/CompanionDeviceManager/res/values-ur/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ur/strings.xml
@@ -19,11 +19,9 @@
<string name="app_label" msgid="4470785958457506021">"ساتھی آلہ مینیجر"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> کے ذریعے نظم کئے جانے کیلئے <xliff:g id="PROFILE_NAME">%1$s</xliff:g> کو منتخب کریں"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"آلہ"</string>
- <!-- no translation found for profile_name_watch (576290739483672360) -->
- <skip />
+ <string name="profile_name_watch" msgid="576290739483672360">"دیکھیں"</string>
<string name="confirmation_title" msgid="4751119145078041732">"اپنے <xliff:g id="PROFILE_NAME">%2$s</xliff:g> کا نظم کرنے کے لیے <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کو سیٹ کریں - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string>
- <!-- no translation found for profile_summary (2009764182871566255) -->
- <skip />
+ <string name="profile_summary" msgid="2009764182871566255">"آپ کے <xliff:g id="PROFILE_NAME">%2$s</xliff:g> کا نظم کرنے کے لیے <xliff:g id="APP_NAME">%1$s</xliff:g> کی ضرورت ہے۔ <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
<string name="consent_yes" msgid="4055438216605487056">"ہاں"</string>
<string name="consent_no" msgid="1335543792857823917">"نہیں شکریہ"</string>
</resources>
diff --git a/packages/CompanionDeviceManager/res/values-uz/strings.xml b/packages/CompanionDeviceManager/res/values-uz/strings.xml
index 4cce2e8..2ca27b5 100644
--- a/packages/CompanionDeviceManager/res/values-uz/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uz/strings.xml
@@ -19,9 +19,9 @@
<string name="app_label" msgid="4470785958457506021">"Companion Device Manager"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> boshqaradigan <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qurilmasini tanlang"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"qurilma"</string>
- <string name="profile_name_watch" msgid="576290739483672360">"tomosha qilish"</string>
+ <string name="profile_name_watch" msgid="576290739483672360">"soat"</string>
<string name="confirmation_title" msgid="4751119145078041732">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> qurilmalarini boshqarish uchun <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ilovasini sozlang"</string>
- <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi <xliff:g id="PROFILE_NAME">%2$s</xliff:g> qurilmasini boshqarish uchun kerak. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
+ <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> qurilmasini boshqarish uchun <xliff:g id="APP_NAME">%1$s</xliff:g> zarur. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string>
<string name="consent_yes" msgid="4055438216605487056">"Ha"</string>
<string name="consent_no" msgid="1335543792857823917">"Kerak emas"</string>
</resources>
diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoControlsService.kt b/packages/EasterEgg/src/com/android/egg/neko/NekoControlsService.kt
index 56f599a..7efaf0b 100644
--- a/packages/EasterEgg/src/com/android/egg/neko/NekoControlsService.kt
+++ b/packages/EasterEgg/src/com/android/egg/neko/NekoControlsService.kt
@@ -74,6 +74,7 @@
private val controls = HashMap<String, Control>()
private val publishers = ArrayList<UglyPublisher>()
private val rng = Random()
+ private val metricsLogger = MetricsLogger()
private var lastToyIcon: Icon? = null
@@ -184,7 +185,6 @@
return getPendingIntent()
}
-
override fun performControlAction(
controlId: String,
action: ControlAction,
@@ -196,7 +196,7 @@
controls[CONTROL_ID_FOOD] = makeFoodBowlControl(true)
Log.v(TAG, "Bowl refilled. (Registering job.)")
NekoService.registerJob(this, FOOD_SPAWN_CAT_DELAY_MINS)
- MetricsLogger.histogram(this, "egg_neko_offered_food", 11)
+ metricsLogger.histogram("egg_neko_offered_food", 11)
prefs.foodState = 11
}
CONTROL_ID_TOY -> {
diff --git a/packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt b/packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt
index 460fa3a..20527af 100644
--- a/packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt
+++ b/packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt
@@ -47,6 +47,7 @@
) : super(context, attrs, defStyle) {
}
+ @Suppress("DEPRECATION")
override fun onApplyWindowInsets(insets: WindowInsets?): WindowInsets {
var lp = layoutParams as FrameLayout.LayoutParams?
if (lp != null && insets != null) {
diff --git a/packages/EasterEgg/src/com/android/egg/quares/QuaresActivity.kt b/packages/EasterEgg/src/com/android/egg/quares/QuaresActivity.kt
index ce439a9..578de01 100644
--- a/packages/EasterEgg/src/com/android/egg/quares/QuaresActivity.kt
+++ b/packages/EasterEgg/src/com/android/egg/quares/QuaresActivity.kt
@@ -49,6 +49,7 @@
private lateinit var label: Button
private lateinit var grid: GridLayout
+ @Suppress("DEPRECATION")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
diff --git a/packages/InputDevices/res/values-eu/strings.xml b/packages/InputDevices/res/values-eu/strings.xml
index eb95466..0346d74 100644
--- a/packages/InputDevices/res/values-eu/strings.xml
+++ b/packages/InputDevices/res/values-eu/strings.xml
@@ -44,7 +44,7 @@
<string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituaniera"</string>
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espainiera (Latinoamerika)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"Letoniera"</string>
- <string name="keyboard_layout_persian" msgid="3920643161015888527">"Pertsiera"</string>
+ <string name="keyboard_layout_persian" msgid="3920643161015888527">"Persiarra"</string>
<string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerbaijandarra"</string>
<string name="keyboard_layout_polish" msgid="1121588624094925325">"Poloniarra"</string>
<string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Bielorrusiera"</string>
diff --git a/packages/PackageInstaller/res/values-ca/strings.xml b/packages/PackageInstaller/res/values-ca/strings.xml
index 1833329..b25b37b 100644
--- a/packages/PackageInstaller/res/values-ca/strings.xml
+++ b/packages/PackageInstaller/res/values-ca/strings.xml
@@ -80,9 +80,9 @@
<string name="wear_not_allowed_dlg_text" msgid="704615521550939237">"Les accions d\'instal·lar o de desinstal·lar no s\'admeten a Wear."</string>
<string name="message_staging" msgid="8032722385658438567">"S\'està preparant la instal·lació de l\'aplicació…"</string>
<string name="app_name_unknown" msgid="6881210203354323926">"Desconeguda"</string>
- <string name="untrusted_external_source_warning" product="tablet" msgid="6539403649459942547">"Per seguretat, la tauleta no pot instal·lar aplicacions desconegudes d\'aquesta font."</string>
- <string name="untrusted_external_source_warning" product="tv" msgid="1206648674551321364">"Per seguretat, el televisor no pot instal·lar aplicacions desconegudes d\'aquesta font."</string>
- <string name="untrusted_external_source_warning" product="default" msgid="7279739265754475165">"Per seguretat, el telèfon no pot instal·lar aplicacions desconegudes d\'aquesta font."</string>
+ <string name="untrusted_external_source_warning" product="tablet" msgid="6539403649459942547">"Per la teva seguretat, la tauleta no pot instal·lar aplicacions desconegudes d\'aquesta font."</string>
+ <string name="untrusted_external_source_warning" product="tv" msgid="1206648674551321364">"Per la teva seguretat, el televisor no pot instal·lar aplicacions desconegudes d\'aquesta font."</string>
+ <string name="untrusted_external_source_warning" product="default" msgid="7279739265754475165">"Per la teva seguretat, el telèfon no pot instal·lar aplicacions desconegudes d\'aquesta font."</string>
<string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"El telèfon i les dades personals són més vulnerables als atacs d\'aplicacions desconegudes. En instal·lar aquesta aplicació, acceptes que ets responsable de qualsevol dany que es produeixi al telèfon o de la pèrdua de dades que pugui resultar del seu ús."</string>
<string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"La tauleta i les dades personals són més vulnerables als atacs d\'aplicacions desconegudes. En instal·lar aquesta aplicació, acceptes que ets responsable de qualsevol dany que es produeixi a la tauleta o de la pèrdua de dades que pugui resultar del seu ús."</string>
<string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"El televisor i les dades personals són més vulnerables als atacs d\'aplicacions desconegudes. En instal·lar aquesta aplicació, acceptes que ets responsable de qualsevol dany que es produeixi al televisor o de la pèrdua de dades que pugui resultar del seu ús."</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java b/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java
index 02d1c2e..64cb0f1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java
@@ -210,7 +210,8 @@
}
private void checkIfAllSubsystemsRestartsAreDone() {
- if (!mWifiRestartInProgress && !mTelephonyRestartInProgress) {
+ if (!mWifiRestartInProgress && !mTelephonyRestartInProgress
+ && mCurrentRecoveryCallback != null) {
mCurrentRecoveryCallback.onSubsystemRestartOperationEnd();
mCurrentRecoveryCallback = null;
}
@@ -283,8 +284,10 @@
stopTrackingTelephonyRestart();
mWifiRestartInProgress = false;
mTelephonyRestartInProgress = false;
- mCurrentRecoveryCallback.onSubsystemRestartOperationEnd();
- mCurrentRecoveryCallback = null;
+ if (mCurrentRecoveryCallback != null) {
+ mCurrentRecoveryCallback.onSubsystemRestartOperationEnd();
+ mCurrentRecoveryCallback = null;
+ }
}, RESTART_TIMEOUT_MS);
}
});
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/Estimate.kt b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/Estimate.kt
index b2e75ea..cd22247 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/Estimate.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/Estimate.kt
@@ -38,14 +38,13 @@
* @return An [Estimate] object with the latest battery estimates.
*/
@JvmStatic
+ @Suppress("DEPRECATION")
fun getCachedEstimateIfAvailable(context: Context): Estimate? {
// if time > 2 min return null or the estimate otherwise
val resolver = context.contentResolver
- val lastUpdateTime = Instant.ofEpochMilli(
- Settings.Global.getLong(
- resolver, Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME, -1))
+ val lastUpdateTime = getLastCacheUpdateTime(context)
return if (Duration.between(lastUpdateTime,
- Instant.now()).compareTo(Duration.ofMinutes(1)) > 0) {
+ Instant.now()) > Duration.ofMinutes(1)) {
null
} else Estimate(
Settings.Global.getLong(resolver,
@@ -65,6 +64,7 @@
* @param estimate the [Estimate] object to store
*/
@JvmStatic
+ @Suppress("DEPRECATION")
fun storeCachedEstimate(context: Context, estimate: Estimate) {
// store the estimate and update the timestamp
val resolver = context.contentResolver
@@ -82,6 +82,7 @@
* Returns when the estimate was last updated as an Instant
*/
@JvmStatic
+ @Suppress("DEPRECATION")
fun getLastCacheUpdateTime(context: Context): Instant {
return Instant.ofEpochMilli(
Settings.Global.getLong(
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index edb5506..9de7630 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -297,6 +297,24 @@
Settings.System.getCloneFromParentOnValueSettings(sSystemCloneFromParentOnDependency);
}
+ private static final Set<String> sAllSecureSettings = new ArraySet<>();
+ private static final Set<String> sReadableSecureSettings = new ArraySet<>();
+ static {
+ Settings.Secure.getPublicSettings(sAllSecureSettings, sReadableSecureSettings);
+ }
+
+ private static final Set<String> sAllSystemSettings = new ArraySet<>();
+ private static final Set<String> sReadableSystemSettings = new ArraySet<>();
+ static {
+ Settings.System.getPublicSettings(sAllSystemSettings, sReadableSystemSettings);
+ }
+
+ private static final Set<String> sAllGlobalSettings = new ArraySet<>();
+ private static final Set<String> sReadableGlobalSettings = new ArraySet<>();
+ static {
+ Settings.Global.getPublicSettings(sAllGlobalSettings, sReadableGlobalSettings);
+ }
+
private final Object mLock = new Object();
@GuardedBy("mLock")
@@ -1919,6 +1937,7 @@
if (UserHandle.getAppId(Binder.getCallingUid()) < Process.FIRST_APPLICATION_UID) {
return;
}
+ checkReadableAnnotation(settingsType, settingName);
ApplicationInfo ai = getCallingApplicationInfoOrThrow();
if (!ai.isInstantApp()) {
return;
@@ -1932,6 +1951,41 @@
}
}
+ /**
+ * Check if the target settings key is readable. Reject if the caller app is trying to access a
+ * settings key defined in the Settings.Secure, Settings.System or Settings.Global and is not
+ * annotated as @Readable.
+ * Notice that a key string that is not defined in any of the Settings.* classes will still be
+ * regarded as readable.
+ */
+ private void checkReadableAnnotation(int settingsType, String settingName) {
+ final Set<String> allFields;
+ final Set<String> readableFields;
+ switch (settingsType) {
+ case SETTINGS_TYPE_GLOBAL:
+ allFields = sAllGlobalSettings;
+ readableFields = sReadableGlobalSettings;
+ break;
+ case SETTINGS_TYPE_SYSTEM:
+ allFields = sAllSystemSettings;
+ readableFields = sReadableSystemSettings;
+ break;
+ case SETTINGS_TYPE_SECURE:
+ allFields = sAllSecureSettings;
+ readableFields = sReadableSecureSettings;
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid settings type: " + settingsType);
+ }
+
+ if (allFields.contains(settingName) && !readableFields.contains(settingName)) {
+ throw new SecurityException(
+ "Settings key: <" + settingName + "> is not readable. From S+, new public "
+ + "settings keys need to be annotated with @Readable unless they are "
+ + "annotated with @hide.");
+ }
+ }
+
private ApplicationInfo getCallingApplicationInfoOrThrow() {
// We always use the callingUid for this lookup. This means that if hypothetically an
// app was installed in user A with cross user and in user B as an Instant App
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 86b5d0d..ca9dcd6 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -433,6 +433,15 @@
android:excludeFromRecents="true">
</activity>
+ <!-- started from SensoryPrivacyService -->
+ <activity android:name=".sensorprivacy.SensorUseStartedActivity"
+ android:exported="true"
+ android:permission="android.permission.MANAGE_SENSOR_PRIVACY"
+ android:theme="@style/Theme.SystemUI.Dialog.Alert"
+ android:finishOnCloseSystemDialogs="true">
+ </activity>
+
+
<!-- started from UsbDeviceSettingsManager -->
<activity android:name=".usb.UsbAccessoryUriActivity"
android:exported="true"
diff --git a/packages/SystemUI/res-keyguard/drawable/ic_keyboard_tab_36dp.xml b/packages/SystemUI/res-keyguard/drawable/ic_keyboard_tab_36dp.xml
index 21c9051..b844515 100644
--- a/packages/SystemUI/res-keyguard/drawable/ic_keyboard_tab_36dp.xml
+++ b/packages/SystemUI/res-keyguard/drawable/ic_keyboard_tab_36dp.xml
@@ -13,8 +13,13 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<vector android:height="36sp" android:viewportHeight="36"
- android:viewportWidth="36" android:width="36sp" xmlns:android="http://schemas.android.com/apk/res/android">
- <path android:fillColor="?android:attr/colorAccent" android:pathData="M18,18m-18,0a18,18 0,1 1,36 0a18,18 0,1 1,-36 0"/>
- <path android:fillColor="?android:attr/textColorPrimaryInverse" android:pathData="M17.59,13.41L21.17,17H7v2h14.17l-3.59,3.59L19,24l6,-6l-6,-6L17.59,13.41zM26,12v12h2V12H26z"/>
-</vector>
\ No newline at end of file
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="36sp"
+ android:viewportHeight="36"
+ android:viewportWidth="36"
+ android:width="36sp">
+ <path android:fillColor="?android:attr/colorBackground"
+ android:pathData="M17.59,13.41L21.17,17H7v2h14.17l-3.59,3.59L19,24l6,-6l-6,-6L17.59,
+ 13.41zM26,12v12h2V12H26z"/>
+</vector>
diff --git a/packages/SystemUI/res-keyguard/drawable/num_pad_key_background.xml b/packages/SystemUI/res-keyguard/drawable/num_pad_key_background.xml
new file mode 100644
index 0000000..b7a9fafd
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/num_pad_key_background.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* 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.
+*/
+-->
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <solid android:color="?android:attr/colorBackground" />
+ <corners android:radius="10dp" />
+</shape>
diff --git a/packages/SystemUI/res-keyguard/drawable/ripple_drawable_pin.xml b/packages/SystemUI/res-keyguard/drawable/ripple_drawable_pin.xml
deleted file mode 100644
index 51c442a..0000000
--- a/packages/SystemUI/res-keyguard/drawable/ripple_drawable_pin.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2018 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
- -->
-
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="?android:attr/colorControlHighlight"
- android:radius="40dp"/>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_num_pad_key.xml b/packages/SystemUI/res-keyguard/layout/keyguard_num_pad_key.xml
index 72591d46..411fea5 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_num_pad_key.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_num_pad_key.xml
@@ -17,15 +17,18 @@
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:id="@+id/digit_text"
- style="@style/Widget.TextView.NumPadKey"
+ style="@style/Widget.TextView.NumPadKey.Digit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
+ <!-- b/172360102: Setting visibility to gone for now, in order to see if there are many
+ issues with removing the alpha characters. -->
<TextView
android:id="@+id/klondike_text"
style="@style/Widget.TextView.NumPadKey.Klondike"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:visibility="gone"
/>
</merge>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
index 87c98d2..aa14645a 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
@@ -24,7 +24,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
androidprv:layout_maxWidth="@dimen/keyguard_security_width"
- androidprv:layout_maxHeight="@dimen/keyguard_security_max_height"
android:orientation="vertical"
>
<LinearLayout
@@ -34,37 +33,34 @@
android:orientation="vertical"
android:layout_weight="1"
android:layoutDirection="ltr"
+ android:layout_marginBottom="8dp"
>
- <com.android.keyguard.AlphaOptimizedRelativeLayout
- android:id="@+id/row0"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:paddingBottom="16dp"
- >
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ />
+ <com.android.keyguard.AlphaOptimizedRelativeLayout
+ android:id="@+id/row0"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="16dp"
+ >
<com.android.keyguard.PasswordTextView
android:id="@+id/pinEntry"
android:layout_width="@dimen/keyguard_security_width"
- android:layout_height="match_parent"
+ android:layout_height="@dimen/keyguard_password_height"
style="@style/Widget.TextView.Password"
android:layout_centerHorizontal="true"
android:layout_marginRight="72dp"
androidprv:scaledTextSize="@integer/scaled_password_text_size"
android:contentDescription="@string/keyguard_accessibility_pin_area"
/>
- <View
- android:id="@+id/divider"
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:layout_alignParentBottom="true"
- android:background="@drawable/pin_divider"
- />
</com.android.keyguard.AlphaOptimizedRelativeLayout>
<LinearLayout
android:id="@+id/row1"
android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
+ android:layout_height="wrap_content"
android:orientation="horizontal"
>
<com.android.keyguard.NumPadKey
@@ -95,8 +91,7 @@
<LinearLayout
android:id="@+id/row2"
android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
+ android:layout_height="wrap_content"
android:orientation="horizontal"
>
<com.android.keyguard.NumPadKey
@@ -127,9 +122,8 @@
<LinearLayout
android:id="@+id/row3"
android:layout_width="match_parent"
- android:layout_height="0dp"
+ android:layout_height="wrap_content"
android:orientation="horizontal"
- android:layout_weight="1"
>
<com.android.keyguard.NumPadKey
android:id="@+id/key7"
@@ -159,18 +153,16 @@
<LinearLayout
android:id="@+id/row4"
android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
+ android:layout_height="wrap_content"
android:orientation="horizontal"
>
- <com.android.keyguard.AlphaOptimizedImageButton
+ <com.android.keyguard.NumPadButton
android:id="@+id/delete_button"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
- android:background="@drawable/ripple_drawable_pin"
android:contentDescription="@string/keyboardview_keycode_delete"
- style="@style/Keyguard.ImageButton.NumPadDelete"
+ style="@style/NumPadKey.Delete"
/>
<com.android.keyguard.NumPadKey
android:id="@+id/key0"
@@ -180,13 +172,12 @@
androidprv:textView="@+id/pinEntry"
androidprv:digit="0"
/>
- <com.android.keyguard.AlphaOptimizedImageButton
+ <com.android.keyguard.NumPadButton
android:id="@+id/key_enter"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
- style="@style/Keyguard.ImageButton.NumPadEnter"
- android:background="@drawable/ripple_drawable_pin"
+ style="@style/NumPadKey.Enter"
android:contentDescription="@string/keyboardview_keycode_enter"
/>
</LinearLayout>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
index 912d7bb..64ccefd 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
@@ -25,9 +25,14 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
androidprv:layout_maxWidth="@dimen/keyguard_security_width"
- androidprv:layout_maxHeight="@dimen/keyguard_security_max_height"
android:gravity="center_horizontal">
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ />
+
<ImageView
android:id="@+id/keyguard_sim"
android:layout_width="match_parent"
@@ -37,10 +42,9 @@
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="0dp"
+ android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
- android:layout_weight="1"
android:layoutDirection="ltr"
>
<include layout="@layout/keyguard_esim_area"
@@ -52,32 +56,23 @@
<RelativeLayout
android:id="@+id/row0"
android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
+ android:layout_height="wrap_content"
android:paddingBottom="16dp"
>
<com.android.keyguard.PasswordTextView
android:id="@+id/simPinEntry"
android:layout_width="@dimen/keyguard_security_width"
- android:layout_height="match_parent"
+ android:layout_height="@dimen/keyguard_password_height"
android:gravity="center"
android:layout_centerHorizontal="true"
android:layout_marginRight="72dp"
androidprv:scaledTextSize="@integer/scaled_password_text_size"
android:contentDescription="@string/keyguard_accessibility_sim_pin_area"
/>
- <View
- android:id="@+id/divider"
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:layout_alignParentBottom="true"
- android:background="@drawable/pin_divider"
- />
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
+ android:layout_height="wrap_content"
android:orientation="horizontal"
>
<com.android.keyguard.NumPadKey
@@ -107,8 +102,7 @@
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
+ android:layout_height="wrap_content"
android:orientation="horizontal"
>
<com.android.keyguard.NumPadKey
@@ -138,9 +132,8 @@
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="0dp"
+ android:layout_height="wrap_content"
android:orientation="horizontal"
- android:layout_weight="1"
>
<com.android.keyguard.NumPadKey
android:id="@+id/key7"
@@ -169,18 +162,16 @@
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
+ android:layout_height="wrap_content"
android:orientation="horizontal"
>
- <com.android.keyguard.AlphaOptimizedImageButton
+ <com.android.keyguard.NumPadButton
android:id="@+id/delete_button"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
- android:background="@drawable/ripple_drawable_pin"
android:contentDescription="@string/keyboardview_keycode_delete"
- style="@style/Keyguard.ImageButton.NumPadDelete"
+ style="@style/NumPadKey.Delete"
/>
<com.android.keyguard.NumPadKey
android:id="@+id/key0"
@@ -190,13 +181,12 @@
androidprv:textView="@+id/simPinEntry"
androidprv:digit="0"
/>
- <com.android.keyguard.AlphaOptimizedImageButton
+ <com.android.keyguard.NumPadButton
android:id="@+id/key_enter"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
- style="@style/Keyguard.ImageButton.NumPadEnter"
- android:background="@drawable/ripple_drawable_pin"
+ style="@style/NumPadKey.Enter"
android:contentDescription="@string/keyboardview_keycode_enter"
/>
</LinearLayout>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
index 81b4964..dc77bd3 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
@@ -26,9 +26,14 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
androidprv:layout_maxWidth="@dimen/keyguard_security_width"
- androidprv:layout_maxHeight="@dimen/keyguard_security_max_height"
android:gravity="center_horizontal">
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ />
+
<ImageView
android:id="@+id/keyguard_sim"
android:layout_width="match_parent"
@@ -38,7 +43,7 @@
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="0dp"
+ android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
android:layout_weight="1"
@@ -53,32 +58,23 @@
<RelativeLayout
android:id="@+id/row0"
android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
+ android:layout_height="wrap_content"
android:paddingBottom="16dp"
>
<com.android.keyguard.PasswordTextView
android:id="@+id/pukEntry"
android:layout_width="@dimen/keyguard_security_width"
- android:layout_height="match_parent"
+ android:layout_height="@dimen/keyguard_password_height"
android:gravity="center"
android:layout_centerHorizontal="true"
android:layout_marginRight="72dp"
androidprv:scaledTextSize="@integer/scaled_password_text_size"
android:contentDescription="@string/keyguard_accessibility_sim_puk_area"
/>
- <View
- android:id="@+id/divider"
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:layout_alignParentBottom="true"
- android:background="@drawable/pin_divider"
- />
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
+ android:layout_height="wrap_content"
android:orientation="horizontal"
>
<com.android.keyguard.NumPadKey
@@ -108,8 +104,7 @@
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
+ android:layout_height="wrap_content"
android:orientation="horizontal"
>
<com.android.keyguard.NumPadKey
@@ -139,9 +134,8 @@
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="0dp"
+ android:layout_height="wrap_content"
android:orientation="horizontal"
- android:layout_weight="1"
>
<com.android.keyguard.NumPadKey
android:id="@+id/key7"
@@ -170,18 +164,16 @@
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
+ android:layout_height="wrap_content"
android:orientation="horizontal"
>
- <com.android.keyguard.AlphaOptimizedImageButton
+ <com.android.keyguard.NumPadButton
android:id="@+id/delete_button"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
- android:background="@drawable/ripple_drawable_pin"
android:contentDescription="@string/keyboardview_keycode_delete"
- style="@style/Keyguard.ImageButton.NumPadDelete"
+ style="@style/NumPadKey.Delete"
/>
<com.android.keyguard.NumPadKey
android:id="@+id/key0"
@@ -191,13 +183,12 @@
androidprv:textView="@+id/pukEntry"
androidprv:digit="0"
/>
- <com.android.keyguard.AlphaOptimizedImageButton
+ <com.android.keyguard.NumPadButton
android:id="@+id/key_enter"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
- style="@style/Keyguard.ImageButton.NumPadEnter"
- android:background="@drawable/ripple_drawable_pin"
+ style="@style/NumPadKey.Enter"
android:contentDescription="@string/keyboardview_keycode_enter"
/>
</LinearLayout>
diff --git a/packages/SystemUI/res-keyguard/values/attrs.xml b/packages/SystemUI/res-keyguard/values/attrs.xml
index bfcc56c..eb7a1f7 100644
--- a/packages/SystemUI/res-keyguard/values/attrs.xml
+++ b/packages/SystemUI/res-keyguard/values/attrs.xml
@@ -40,6 +40,8 @@
<attr name="passwordStyle" format="reference" />
+ <attr name="numPadKeyStyle" format="reference" />
+
<declare-styleable name="AnimatableClockView">
<attr name="dozeWeight" format="integer" />
<attr name="lockScreenWeight" format="integer" />
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index f9389ce..aa87107 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -33,6 +33,9 @@
(includes 2x keyguard_security_view_top_margin) -->
<dimen name="keyguard_security_max_height">450dp</dimen>
+ <!-- pin/password field max height -->
+ <dimen name="keyguard_password_height">80dp</dimen>
+
<!-- Margin around the various security views -->
<dimen name="keyguard_security_view_top_margin">8dp</dimen>
<dimen name="keyguard_security_view_lateral_margin">36dp</dimen>
@@ -81,4 +84,7 @@
<!-- The translation for disappearing security views after having solved them. -->
<dimen name="disappear_y_translation">-32dp</dimen>
+
+ <!-- Spacing around each button used for PIN view -->
+ <dimen name="num_pad_key_margin">2dp</dimen>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index 71a1cc2..2e99dea 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -30,7 +30,13 @@
<item name="android:paddingLeft">12dp</item>
<item name="android:paddingRight">12dp</item>
</style>
- <style name="Widget.TextView.NumPadKey" parent="@android:style/Widget.DeviceDefault.TextView">
+ <style name="NumPadKey" parent="Theme.SystemUI">
+ <item name="android:colorControlNormal">?android:attr/colorBackground</item>
+ <item name="android:colorControlHighlight">?android:attr/colorAccent</item>
+ <item name="android:background">@drawable/num_pad_key_background</item>
+ </style>
+ <style name="Widget.TextView.NumPadKey.Digit"
+ parent="@android:style/Widget.DeviceDefault.TextView">
<item name="android:singleLine">true</item>
<item name="android:gravity">center_horizontal|center_vertical</item>
<item name="android:background">@null</item>
@@ -38,26 +44,25 @@
<item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:paddingBottom">-16dp</item>
- <item name="android:colorControlHighlight">?android:attr/textColorPrimary</item>
</style>
<style name="Widget.TextView.Password" parent="@android:style/Widget.TextView">
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:gravity">center</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
- <style name="Keyguard.ImageButton.NumPadDelete" parent="@android:style/Widget.DeviceDefault.ImageButton">
+ <style name="NumPadKey.Delete">
<item name="android:src">@drawable/ic_backspace_black_24dp</item>
- <item name="android:paddingBottom">11sp</item>
<item name="android:tint">?android:attr/textColorSecondary</item>
<item name="android:tintMode">src_in</item>
- <item name="android:src">@drawable/ic_backspace_black_24dp</item>
</style>
- <style name="Keyguard.ImageButton.NumPadEnter" parent="@android:style/Widget.DeviceDefault.ImageButton">
- <item name="android:src">@drawable/ic_keyboard_tab_36dp</item>
- <item name="android:paddingBottom">11sp</item>
+ <style name="NumPadKey.Enter">
+ <item name="android:colorControlNormal">?android:attr/textColorSecondary</item>
+ <item name="android:src">@drawable/ic_keyboard_tab_36dp</item>
</style>
- <style name="Widget.TextView.NumPadKey.Klondike">
+ <style name="Widget.TextView.NumPadKey.Klondike"
+ parent="@android:style/Widget.DeviceDefault.TextView">
<item name="android:textSize">12sp</item>
+ <item name="android:background">@null</item>
<item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
<item name="android:textColor">?android:attr/textColorSecondary</item>
<item name="android:paddingBottom">0dp</item>
diff --git a/packages/SystemUI/res-keyguard/drawable/pin_divider.xml b/packages/SystemUI/res/drawable/qs_background_primary.xml
similarity index 64%
rename from packages/SystemUI/res-keyguard/drawable/pin_divider.xml
rename to packages/SystemUI/res/drawable/qs_background_primary.xml
index 39104b5..0a3afc5 100644
--- a/packages/SystemUI/res-keyguard/drawable/pin_divider.xml
+++ b/packages/SystemUI/res/drawable/qs_background_primary.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2017 The Android Open Source Project
+ ~ Copyright (C) 2021 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -12,9 +12,11 @@
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
- ~ limitations under the License
+ ~ limitations under the License.
-->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <solid android:color="@color/pin_divider_color" />
-</shape>
\ No newline at end of file
+<inset xmlns:android="http://schemas.android.com/apk/res/android">
+ <shape>
+ <solid android:color="?android:attr/colorBackground"/>
+ <corners android:radius="@dimen/notification_corner_radius" />
+ </shape>
+</inset>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 387f2f2..77f1743 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -25,7 +25,8 @@
<View
android:id="@+id/quick_settings_background"
android:layout_width="match_parent"
- android:layout_height="0dp" />
+ android:layout_height="0dp"
+ android:background="@drawable/qs_background_primary" />
<com.android.systemui.qs.NonInterceptingScrollView
android:id="@+id/expanded_qs_scroll_view"
diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml
index f984100..1630244 100644
--- a/packages/SystemUI/res/layout/super_notification_shade.xml
+++ b/packages/SystemUI/res/layout/super_notification_shade.xml
@@ -43,12 +43,6 @@
android:visibility="invisible" />
</com.android.systemui.statusbar.BackDropView>
- <com.android.systemui.statusbar.LightRevealScrim
- android:id="@+id/light_reveal_scrim"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="gone" />
-
<com.android.systemui.statusbar.ScrimView
android:id="@+id/scrim_behind"
android:layout_width="match_parent"
@@ -57,6 +51,12 @@
sysui:ignoreRightInset="true"
/>
+ <com.android.systemui.statusbar.LightRevealScrim
+ android:id="@+id/light_reveal_scrim"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone" />
+
<include layout="@layout/status_bar_expanded"
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index ba39d1e..e70930a 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nuwe gebruiker"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Vliegtuigveilig"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Netwerke is beskikbaar"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Netwerke is nie beskikbaar nie"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nie gekoppel nie"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Geen netwerk nie"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi af"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index a193bbb..a5ca6e7 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"አዲስ ተጠቃሚ"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"በይነመረብ"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"አውሮፕላን-ደህንነቱ የተጠበቀ"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"አውታረ መረቦች ይገኛሉ"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"አውታረ መረቦች አይገኙም"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"አልተገናኘም"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"ምንም አውታረ መረብ የለም"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi ጠፍቷል"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index a634281dc..97fcbd6d 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -362,12 +362,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"مستخدم جديد"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"الإنترنت"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"آمنة في الطائرة"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"الشبكات متوفرة"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"الشبكات غير متوفرة"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"ليست متصلة"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"لا تتوفر شبكة"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"إيقاف Wi-Fi"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 1151644..6ad6b08 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"নতুন ব্যৱহাৰকাৰী"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"ৱাই-ফাই"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"ইণ্টাৰনেট"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"এয়াৰপ্লে’নত ব্যৱহাৰৰ বাবে সুৰক্ষিত"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"নেটৱৰ্ক উপলব্ধ"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"নেটৱৰ্ক উপলব্ধ নহয়"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"সংযোগ হৈ থকা নাই"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"নেটৱৰ্ক নাই"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"ৱাই-ফাই অফ"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 146add2f..a9441db 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Yeni istifadəçi"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"İnternet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Təyyarə üçün güvənli şəbəkə"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Şəbəkələr əlçatandır"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Şəbəkələr əlçatan deyil"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Bağlantı yoxdur"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Şəbəkə yoxdur"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi sönülüdür"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 77b101c..aebd1e2 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -359,12 +359,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Novi korisnik"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"WiFi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Bezbedno za avion"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Mreže su dostupne"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Mreže nisu dostupne"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Veza nije uspostavljena"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Nema mreže"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"WiFi je isključen"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 5977d04..f115f3f 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -360,12 +360,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Новы карыстальнік"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Інтэрнэт"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Бяспечныя ў самалёце"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Сеткі даступныя"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Сеткі недаступныя"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Няма падключэння"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Няма сеткi"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi адключаны"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 53eeac8..ae94f58 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Нов потребител"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Интернет"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Безопасно в самолети"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Налице са мрежи"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Няма достъпни мрежи"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Няма връзка"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Няма мрежа"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi е изключен"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 7717c65..7ed6937 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -359,7 +359,7 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Novi korisnik"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"WiFi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Sigurno za rad u zrakoplovu"</string>
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Sigurno za korištenje u avionu"</string>
<string name="quick_settings_networks_available" msgid="1875138606855420438">"Mreže su dostupne"</string>
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Mreže nisu dostupne"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nije povezano"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index f648bc6..80c4d28 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Usuari nou"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Mode d\'avió"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Xarxes disponibles"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Xarxes no disponibles"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Desconnectat"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"No hi ha cap xarxa"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi desconnectada"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 4d14d2b..e266b20 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -360,12 +360,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nový uživatel"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Použitelné v letadle"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Dostupné sítě"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Nedostupné sítě"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nepřipojeno"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Žádná síť"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi vypnuta"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 95b1a55..ba8b1e8 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Ny bruger"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Kan bruges i fly"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Tilgængelige netværk"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Ingen tilgængelige netværk"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Ikke forbundet"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Intet netværk"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi slået fra"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index e6acd87..7b69260 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Neuer Nutzer"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"WLAN"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Flugsicher"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Netzwerke verfügbar"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Netzwerke nicht verfügbar"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nicht verbunden"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Kein Netz"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"WLAN aus"</string>
@@ -938,7 +935,7 @@
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
<string name="wifi_is_off" msgid="5389597396308001471">"WLAN ist deaktiviert"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth ist deaktiviert"</string>
- <string name="dnd_is_off" msgid="3185706903793094463">"\"Bitte nicht stören\" ist deaktiviert"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"„Bitte nicht stören“ ist deaktiviert"</string>
<string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"\"Bitte nicht stören\" wurde von einer automatischen Regel aktiviert (<xliff:g id="ID_1">%s</xliff:g>)."</string>
<string name="qs_dnd_prompt_app" msgid="4027984447935396820">"\"Bitte nicht stören\" wurde von einer App aktiviert (<xliff:g id="ID_1">%s</xliff:g>)."</string>
<string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"\"Bitte nicht stören\" wurde von einer automatischen Regel oder einer App aktiviert."</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 185af57..1fa6b11 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -344,10 +344,8 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Input Method"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Location Off"</string>
- <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
- <skip />
- <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
- <skip />
+ <string name="quick_settings_camera_label" msgid="1367149596242401934">"Block camera"</string>
+ <string name="quick_settings_mic_label" msgid="8245831073612564953">"Mute microphone"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Media device"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Emergency Calls Only"</string>
@@ -358,12 +356,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"New user"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Aeroplane-safe"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Networks available"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Networks unavailable"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Not Connected"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"No Network"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi Off"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 3517f87..1c1bd89 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -344,10 +344,8 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Input Method"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Location Off"</string>
- <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
- <skip />
- <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
- <skip />
+ <string name="quick_settings_camera_label" msgid="1367149596242401934">"Block camera"</string>
+ <string name="quick_settings_mic_label" msgid="8245831073612564953">"Mute microphone"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Media device"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Emergency Calls Only"</string>
@@ -358,12 +356,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"New user"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Aeroplane-safe"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Networks available"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Networks unavailable"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Not Connected"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"No Network"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi Off"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 185af57..1fa6b11 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -344,10 +344,8 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Input Method"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Location Off"</string>
- <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
- <skip />
- <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
- <skip />
+ <string name="quick_settings_camera_label" msgid="1367149596242401934">"Block camera"</string>
+ <string name="quick_settings_mic_label" msgid="8245831073612564953">"Mute microphone"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Media device"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Emergency Calls Only"</string>
@@ -358,12 +356,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"New user"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Aeroplane-safe"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Networks available"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Networks unavailable"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Not Connected"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"No Network"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi Off"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 185af57..1fa6b11 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -344,10 +344,8 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Input Method"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Location Off"</string>
- <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
- <skip />
- <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
- <skip />
+ <string name="quick_settings_camera_label" msgid="1367149596242401934">"Block camera"</string>
+ <string name="quick_settings_mic_label" msgid="8245831073612564953">"Mute microphone"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Media device"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Emergency Calls Only"</string>
@@ -358,12 +356,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"New user"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Aeroplane-safe"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Networks available"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Networks unavailable"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Not Connected"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"No Network"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi Off"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 306116c..791d75a 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -344,10 +344,8 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Input Method"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Location Off"</string>
- <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
- <skip />
- <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
- <skip />
+ <string name="quick_settings_camera_label" msgid="1367149596242401934">"Block Camera"</string>
+ <string name="quick_settings_mic_label" msgid="8245831073612564953">"Mute Microphone"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Media device"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Emergency Calls Only"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 27c424b..9d7a4be 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -344,10 +344,8 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Método de introducción"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Ubicación"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Ubicación desactivada"</string>
- <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
- <skip />
- <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
- <skip />
+ <string name="quick_settings_camera_label" msgid="1367149596242401934">"Bloquear cámara"</string>
+ <string name="quick_settings_mic_label" msgid="8245831073612564953">"Silenciar micrófono"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Dispositivo multimedia"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Solo emergencia"</string>
@@ -358,12 +356,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Usuario nuevo"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Seguro para aviones"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Redes disponibles"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Redes no disponible"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Sin conexión"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Sin red"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi desactivada"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index ab5d0d2..fcec044 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nuevo usuario"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Modo avión"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Redes disponibles"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Redes no disponibles"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"No conectado"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"No hay red."</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi desactivado"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 6c7e19a..f8745ee 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Uus kasutaja"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"WiFi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Lennukikindel"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Võrgud on saadaval"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Võrgud pole saadaval"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Ühendus puudub"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Võrku pole"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"WiFi-ühendus on väljas"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index da7733c..d6569f8 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Erabiltzaile berria"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wifia"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Hegaldietarako segurua"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Erabilgarri daude sareak"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Ez dago sarerik erabilgarri"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Konektatu gabe"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ez dago sarerik"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi konexioa desaktibatuta"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 28708b9..c186b6e 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Uusi käyttäjä"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Lentokoneturvallinen"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Verkkoja käytettävissä"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Ei verkkoja käytettävissä"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Ei yhteyttä"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ei verkkoa"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi-yhteys pois käytöstä"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 50a3cfb..5b55fbd 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nouvel utilisateur"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Acceptés dans les avions"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Réseaux disponibles"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Réseaux non disponibles"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Non connecté"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Aucun réseau"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi désactivé"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 4c6a53e..70505f8 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Novo usuario"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wifi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Redes seguras para os avións"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Redes dispoñibles"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Non hai redes dispoñibles"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Non conectada"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Non hai rede"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wifi desactivada"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index add1ef5..11c35db 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"નવો વપરાશકર્તા"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"વાઇ-ફાઇ"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"ઇન્ટરનેટ"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"એરપ્લેન મોડમાં ઉપયોગ માટે સુરક્ષિત"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"નેટવર્ક ઉપલબ્ધ છે"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"નેટવર્ક અનુપલબ્ધ છે"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"કનેક્ટ થયેલ નથી"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"કોઈ નેટવર્ક નથી"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"વાઇ-ફાઇ બંધ"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index b4d61bb..0a34f6f 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -360,12 +360,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"नया उपयोगकर्ता"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"वाई-फ़ाई"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"इंटरनेट"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"हवाई जहाज़ मोड पर, काम करने वाले सुरक्षित नेटवर्क"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"नेटवर्क उपलब्ध हैं"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"नेटवर्क उपलब्ध नहीं हैं"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"कनेक्ट नहीं है"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"कोई नेटवर्क नहीं"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"वाई-फ़ाई बंद"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 958e25f6..f62de80 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Új felhasználó"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Repülőgépen használható"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Használhatók hálózatok"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Nem használhatók hálózatok"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nincs kapcsolat"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Nincs hálózat"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi kikapcsolva"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 4fd1abe..49f3eb2 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -358,7 +358,7 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Նոր օգտատեր"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Ինտերնետ"</string>
- <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Ցանցեր, որոնք անվտանգ են ինքնաթիռում"</string>
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Ինքնաթիռում անվտանգ"</string>
<string name="quick_settings_networks_available" msgid="1875138606855420438">"Հասանելի ցանցեր"</string>
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Անհասանելի ցանցեր"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Միացված չէ"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 4136ead..29b9797 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Pengguna baru"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Aman di pesawat"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Jaringan tersedia"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Jaringan tidak tersedia"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Tidak Terhubung"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Tidak Ada Jaringan"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi Mati"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 15c07e4..9cd2379 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nýr notandi"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Öruggt í flugi"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Net í boði"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Net er ekki tiltækt"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Engin tenging"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ekkert net"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Slökkt á Wi-Fi"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 299824b..b08406f 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nuovo utente"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Utilizzabili in aereo"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Reti disponibili"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Reti non disponibili"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Non connessa"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Nessuna rete"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi disattivato"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index e8cc8bf..368d9ee 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -360,12 +360,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"משתמש חדש"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"אינטרנט"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"רשתות בטוחות לטיסה"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"רשתות זמינות"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"אין רשתות זמינות"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"אין חיבור"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"אין רשת"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi כבוי"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 459b520..c3dfec9 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"新しいユーザー"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"インターネット"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"機内モードで利用可能"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"ネットワークが利用できます"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"ネットワークは利用できません"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"接続されていません"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"ネットワークなし"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi OFF"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 65f3032..205ec76 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Жаңа пайдаланушы"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Интернет"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Ұшақта пайдалануға болатын"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Желілер қолжетімді."</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Желілер қолжетімді емес."</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Жалғанбаған"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Желі жоқ"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi өшірулі"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index a4f6e0a..1a4b525 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"អ្នកប្រើថ្មី"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"អ៊ីនធឺណិត"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"សុវត្ថិភាពពេលជិះយន្តហោះ"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"បណ្ដាញដែលអាចប្រើបាន"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"មិនអាចប្រើបណ្តាញបានទេ"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"មិនបានតភ្ជាប់"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"គ្មានបណ្ដាញ"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"វ៉ាយហ្វាយបានបិទ"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index e02ed5a..db5b319 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"ಹೊಸ ಬಳಕೆದಾರರು"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"ವೈ-ಫೈ"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"ಇಂಟರ್ನೆಟ್"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"ಏರ್ಪ್ಲೇನ್ ಮೋಡ್ನಲ್ಲಿ ಬಳಸಲು ಸುರಕ್ಷಿತವಾಗಿದೆ"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"ನೆಟ್ವರ್ಕ್ಗಳು ಲಭ್ಯವಿವೆ"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"ನೆಟ್ವರ್ಕ್ಗಳು ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"ಸಂಪರ್ಕಗೊಂಡಿಲ್ಲ"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"ನೆಟ್ವರ್ಕ್ ಇಲ್ಲ"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"ವೈ-ಫೈ ಆಫ್"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index e9d33fa..9c0b27c 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"신규 사용자"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"인터넷"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"항공 안전"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"네트워크 사용 가능"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"네트워크 사용 불가"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"연결되어 있지 않음"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"네트워크가 연결되지 않음"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi 꺼짐"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index f4191d4..b7ee71f 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -360,12 +360,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Жаңы колдонуучу"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Интернет"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Учак режимине ылайыктуу"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Тармактар жеткиликтүү"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Тармактар жеткиликсиз"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Байланышкан жок"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Желе жок"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi өчүк"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 8d9051d..74e1ef7 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -360,12 +360,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Naujas naudotojas"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internetas"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Saugu naudotis lėktuvuose"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Tinklai pasiekiami"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Tinklai nepasiekiami"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Neprisijungta"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Tinklo nėra"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"„Wi-Fi“ išjungta"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 1cde532..1de72c5 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -359,12 +359,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Jauns lietotājs"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internets"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Var izmantot lidojuma režīmā"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Tīkli ir pieejami"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Tīkli nav pieejami"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nav izveidots savienojums"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Nav tīkla"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi ir izslēgts"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index a006bc9..f17e096 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Нов корисник"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Интернет"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Безбедно за во авион"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Мрежите се достапни"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Мрежите се недостапни"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Не е поврзано"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Нема мрежа"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi е исклучено"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 4d2898f..996562e 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"പുതിയ ഉപയോക്താവ്"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"വൈഫൈ"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"ഇന്റർനെറ്റ്"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"വിമാന-സുരക്ഷിതം"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"നെറ്റ്വർക്കുകൾ ലഭ്യമാണ്"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"നെറ്റ്വർക്കുകൾ ലഭ്യമല്ല"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"കണക്റ്റ് ചെയ്തിട്ടില്ല"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"നെറ്റ്വർക്ക് ഒന്നുമില്ല"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"വൈഫൈ ഓഫുചെയ്യുക"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 8845b07..efbbb80 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Шинэ хэрэглэгч"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Интернэт"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Аюулгүй нислэг"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Сүлжээ боломжтой"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Сүлжээ боломжгүй"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Холбогдоогүй"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Сүлжээгүй"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi унтарсан"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 48498b7..b2041df 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"नवीन वापरकर्ता"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"वाय-फाय"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"इंटरनेट"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"विमानासाठी सुरक्षित"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"नेटवर्क उपलब्ध आहेत"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"नेटवर्क उपलब्ध नाहीत"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"कनेक्ट केले नाही"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"नेटवर्क नाही"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"वाय-फाय बंद"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 4204417..db7d3ce 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Pengguna baharu"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Selamat pesawat"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Rangkaian tersedia"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Rangkaian tidak tersedia"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Tidak Disambungkan"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Tiada Rangkaian"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi Dimatikan"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 9b7488e..4dfdcf3 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"အသုံးပြုသူ အသစ်"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"အင်တာနက်"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"လေယာဉ်ပျံလုံခြုံရေး"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"ကွန်ရက်များ ရနိုင်သည်"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"ကွန်ရက်များ မရနိုင်ပါ"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"ချိတ်ဆက်မထားပါ"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"ကွန်ရက်မရှိပါ"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"ဝိုင်ဖိုင်ပိတ်ရန်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 490ba99..398631e 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Ny bruker"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internett"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Trygg på fly"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Nettverk er tilgjengelige"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Nettverk er utilgjengelige"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Ikke tilkoblet"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ingen nettverk"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi er av"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index cf267fd..6c70a7f 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"नयाँ प्रयोगकर्ता"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"इन्टरनेट"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"हवाइजहाज मोडमा काम गर्ने सुरक्षित नेटवर्क"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"उपलब्ध नेटवर्कहरू"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"नेटवर्क उपलब्ध छैन"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"जोडिएको छैन"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"नेटवर्क छैन"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi बन्द"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index ddb9abc..b9a25832 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nieuwe gebruiker"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wifi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Geschikt voor vliegtuigen"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Netwerken beschikbaar"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Netwerken niet beschikbaar"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Niet verbonden"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Geen netwerk"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wifi uit"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index ce6723e..40d5c3e 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"ନୂଆ ଉପଯୋଗକର୍ତ୍ତା"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"ୱାଇ-ଫାଇ"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"ଇଣ୍ଟରନେଟ୍"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"ଏୟାରପ୍ଲେନ୍-ସେଫ୍"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"ନେଟୱାର୍କଗୁଡ଼ିକ ଉପଲବ୍ଧ"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"ନେଟୱାର୍କ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"ସଂଯୁକ୍ତ ହୋଇନାହିଁ"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"ନେଟ୍ୱର୍କ ନାହିଁ"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"ୱାଇ-ଫାଇ ଅଫ୍"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index ad40d6c..4aece95 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"ਨਵਾਂ ਵਰਤੋਂਕਾਰ"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"ਵਾਈ-ਫਾਈ"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"ਇੰਟਰਨੈੱਟ"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"ਹਵਾਈ-ਜਹਾਜ਼ ਸੁਰੱਖਿਅਤ ਮੋਡ"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"ਨੈੱਟਵਰਕ ਉਪਲਬਧ ਹਨ"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"ਨੈੱਟਵਰਕ ਉਪਲਬਧ ਨਹੀਂ ਹਨ"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"ਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"ਕੋਈ ਨੈੱਟਵਰਕ ਨਹੀਂ"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"ਵਾਈ-ਫਾਈ ਬੰਦ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 75abfda..fbbbf11 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -360,12 +360,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nowy użytkownik"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Bezpieczne w trybie samolotowym"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Sieci dostępne"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Sieci niedostępne"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Brak połączenia"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Brak sieci"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi wyłączone"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 1ab1002..a29cf03 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -344,10 +344,8 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Método de entrada"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Localização"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Localização desativada"</string>
- <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
- <skip />
- <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
- <skip />
+ <string name="quick_settings_camera_label" msgid="1367149596242401934">"Bloquear câmera"</string>
+ <string name="quick_settings_mic_label" msgid="8245831073612564953">"Desativar microfone"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Dispositivo de mídia"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Chamadas de emergência"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 06b67fb..478d1ee 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -344,10 +344,8 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Método de Introdução"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Localização"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Localização Desativada"</string>
- <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
- <skip />
- <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
- <skip />
+ <string name="quick_settings_camera_label" msgid="1367149596242401934">"Bloquear a câmara"</string>
+ <string name="quick_settings_mic_label" msgid="8245831073612564953">"Desativar o som do microfone"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Dispositivo multimédia"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Apenas chamadas de emergência"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 1ab1002..a29cf03 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -344,10 +344,8 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Método de entrada"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Localização"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Localização desativada"</string>
- <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
- <skip />
- <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
- <skip />
+ <string name="quick_settings_camera_label" msgid="1367149596242401934">"Bloquear câmera"</string>
+ <string name="quick_settings_mic_label" msgid="8245831073612564953">"Desativar microfone"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Dispositivo de mídia"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Chamadas de emergência"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 54d53af..f78a95a 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -359,12 +359,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Utilizator nou"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Sigur pentru avion"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Sunt disponibile rețele"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Nu sunt disponibile rețele"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Neconectată"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Nicio rețea"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi deconectat"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index b6c2812..2ae6f0d 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -360,12 +360,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Новый пользователь"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Интернет"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Безопасные в самолете"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Сети доступны"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Сети недоступны"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Нет соединения"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Нет сети"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi выкл."</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index c1ba12b..fe92a8d 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -344,10 +344,8 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"ආදාන ක්රමය"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"ස්ථානය"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"ස්ථානය අක්රියයි"</string>
- <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
- <skip />
- <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
- <skip />
+ <string name="quick_settings_camera_label" msgid="1367149596242401934">"කැමරාව අවහිර කරන්න"</string>
+ <string name="quick_settings_mic_label" msgid="8245831073612564953">"මයික්රෆෝනය නිහඬ කරන්න"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"මාධ්ය උපාංගය"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"හදිසි ඇමතුම් පමණි"</string>
@@ -358,12 +356,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"නව පරිශීලකයා"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"අන්තර්ජාලය"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"ගුවන් යානා-ආරක්ෂිත"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"ජාල තිබේ"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"ජාල නොමැත"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"සම්බන්ධ වී නොමැත"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"ජාලයක් නැත"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi අක්රියයි"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index dfa371b..9aeaef8 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -360,12 +360,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nový používateľ"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi‑Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Bezpečné v lietadle"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Siete sú k dispozícii"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Siete nie sú k dispozícii"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nepripojené"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Žiadna sieť"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Sieť Wi‑Fi je vypnutá"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 5f5ee65..e27c03d 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -360,12 +360,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nov uporabnik"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Varna uporaba v letalu"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Omrežja so na voljo"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Omrežja niso na voljo"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Povezava ni vzpostavljena"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ni omrežja"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi izklopljen"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index e1ca274..a5a7de7 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Përdorues i ri"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Të sigurta për në aeroplan"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Ofrohen rrjete"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Rrjetet nuk ofrohen"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nuk është i lidhur"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Nuk ka rrjet"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi është i çaktivizuar"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index d7bc5a1..7f7c483 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -359,12 +359,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Нови корисник"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"WiFi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Интернет"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Безбедно за авион"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Мреже су доступне"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Мреже нису доступне"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Веза није успостављена"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Нема мреже"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"WiFi је искључен"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 3e38bdd..577719d 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Ny användare"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Flygplanssäker"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Nätverk är tillgängliga"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Inga nätverk är tillgängliga"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Ej ansluten"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Inget nätverk"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi av"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index ebb7fa6..ec45b06 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"புதியவர்"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"வைஃபை"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"இணையம்"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"விமானப் பாதுகாப்பு நெட்வொர்க்குகள்"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"நெட்வொர்க்குகள் கிடைக்கின்றன"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"நெட்வொர்க்குகள் கிடைக்கவில்லை"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"இணைக்கப்படவில்லை"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"நெட்வொர்க் இல்லை"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"வைஃபையை முடக்கு"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 1456a8c..a62accb0 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -52,7 +52,7 @@
<string name="usb_device_confirm_prompt" msgid="4091711472439910809">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>ని నిర్వహించడానికి <xliff:g id="APPLICATION">%1$s</xliff:g>ని తెరవాలా?"</string>
<string name="usb_device_confirm_prompt_warn" msgid="990208659736311769">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>ని హ్యాండిల్ చేయడానికి <xliff:g id="APPLICATION">%1$s</xliff:g>ను తెరవాలా?\nఈ యాప్కు రికార్డ్ చేసే అనుమతి మంజూరు కాలేదు, అయినా ఈ USB పరికరం ద్వారా ఆడియోను క్యాప్చర్ చేయగలదు."</string>
<string name="usb_accessory_confirm_prompt" msgid="5728408382798643421">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>ని నిర్వహించడానికి <xliff:g id="APPLICATION">%1$s</xliff:g>ని తెరవాలా?"</string>
- <string name="usb_accessory_uri_prompt" msgid="6756649383432542382">"ఈ USB ఉపకరణంతో ఇన్స్టాల్ చేయబడిన అనువర్తనాలు ఏవీ పని చేయవు. ఈ ఉపకరణం గురించి <xliff:g id="URL">%1$s</xliff:g>లో మరింత తెలుసుకోండి"</string>
+ <string name="usb_accessory_uri_prompt" msgid="6756649383432542382">"ఈ USB ఉపకరణంతో ఇన్స్టాల్ చేయబడిన యాప్లు ఏవీ పని చేయవు. ఈ ఉపకరణం గురించి <xliff:g id="URL">%1$s</xliff:g>లో మరింత తెలుసుకోండి"</string>
<string name="title_usb_accessory" msgid="1236358027511638648">"USB ఉపకరణం"</string>
<string name="label_view" msgid="6815442985276363364">"వీక్షించండి"</string>
<string name="always_use_device" msgid="210535878779644679">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> కనెక్ట్ అయి ఉన్న ఎల్లప్పుడూ <xliff:g id="APPLICATION">%1$s</xliff:g>ని తెరవండి"</string>
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"కొత్త వినియోగదారు"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"ఇంటర్నెట్"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"విమాన-సురక్షితం"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"నెట్వర్క్లు అందుబాటులో ఉన్నాయి"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"నెట్వర్క్లు అందుబాటులో లేవు"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"కనెక్ట్ చేయబడలేదు"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"నెట్వర్క్ లేదు"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi ఆఫ్లో ఉంది"</string>
@@ -466,14 +463,14 @@
<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="2034481024623462357">"గెస్ట్ సెషన్ను ముగించాలా?"</string>
- <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ఈ సెషన్లోని అన్ని అనువర్తనాలు మరియు డేటా తొలగించబడతాయి."</string>
+ <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ఈ సెషన్లోని అన్ని యాప్లు మరియు డేటా తొలగించబడతాయి."</string>
<string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"సెషన్ను ముగించు"</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>
<string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"అవును, కొనసాగించు"</string>
<string name="guest_notification_title" msgid="4434456703930764167">"అతిథి వినియోగదారు"</string>
- <string name="guest_notification_text" msgid="4202692942089571351">"అనువర్తనాలు, డేటా తొలగించేందుకు అతిథి వినియోగదారు తీసివేయండి"</string>
+ <string name="guest_notification_text" msgid="4202692942089571351">"యాప్లు, డేటా తొలగించేందుకు అతిథి వినియోగదారు తీసివేయండి"</string>
<string name="guest_notification_remove_action" msgid="4153019027696868099">"అతిథిని తీసివేయి"</string>
<string name="user_logout_notification_title" msgid="3644848998053832589">"వినియోగదారుని లాగ్ అవుట్ చేయండి"</string>
<string name="user_logout_notification_text" msgid="7441286737342997991">"ప్రస్తుత వినియోగదారును లాగ్ అవుట్ చేయండి"</string>
@@ -486,7 +483,7 @@
<item quantity="one">ఒక్క వినియోగదారుని మాత్రమే సృష్టించవచ్చు.</item>
</plurals>
<string name="user_remove_user_title" msgid="9124124694835811874">"వినియోగదారుని తీసివేయాలా?"</string>
- <string name="user_remove_user_message" msgid="6702834122128031833">"ఈ వినియోగదారుకు సంబంధించిన అన్ని అనువర్తనాలు మరియు డేటా తొలగించబడతాయి."</string>
+ <string name="user_remove_user_message" msgid="6702834122128031833">"ఈ వినియోగదారుకు సంబంధించిన అన్ని యాప్లు మరియు డేటా తొలగించబడతాయి."</string>
<string name="user_remove_user_remove" msgid="8387386066949061256">"తీసివేయి"</string>
<string name="battery_saver_notification_title" msgid="8419266546034372562">"బ్యాటరీ సేవర్ ఆన్లో ఉంది"</string>
<string name="battery_saver_notification_text" msgid="2617841636449016951">"పనితీరుని మరియు నేపథ్య డేటాను తగ్గిస్తుంది"</string>
@@ -542,30 +539,30 @@
<string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"మీ కార్యాలయ ప్రొఫైల్లో మీ సంస్థ ఒక ప్రమాణపత్ర అధికారాన్ని ఇన్స్టాల్ చేసింది. మీ సురక్షిత నెట్వర్క్ ట్రాఫిక్ పర్యవేక్షించబడవచ్చు లేదా సవరించబడవచ్చు."</string>
<string name="monitoring_description_ca_certificate" msgid="448923057059097497">"ఈ పరికరంలో ప్రమాణపత్ర అధికారం ఇన్స్టాల్ చేయబడింది. మీ సురక్షిత నెట్వర్క్ ట్రాఫిక్ పర్యవేక్షించబడవచ్చు లేదా సవరించబడవచ్చు."</string>
<string name="monitoring_description_management_network_logging" msgid="216983105036994771">"మీ నిర్వాహకులు మీ పరికరంలోని ట్రాఫిక్ని పర్యవేక్షించగల నెట్వర్క్ లాగింగ్ని ఆన్ చేసారు."</string>
- <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"మీరు <xliff:g id="VPN_APP">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్లు, అనువర్తనాలు మరియు వెబ్సైట్లతో సహా మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
- <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"మీరు ఇమెయిల్లు, అనువర్తనాలు మరియు వెబ్సైట్లతో సహా మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="VPN_APP_0">%1$s</xliff:g> మరియు <xliff:g id="VPN_APP_1">%2$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు."</string>
- <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"మీ కార్యాలయ ప్రొఫైల్ ఇమెయిల్లు, అనువర్తనాలు మరియు వెబ్సైట్లతో సహా మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="VPN_APP">%1$s</xliff:g>కి కనెక్ట్ చేయబడింది."</string>
- <string name="monitoring_description_personal_profile_named_vpn" msgid="8179722332380953673">"మీ వ్యక్తిగత ప్రొఫైల్ ఇమెయిల్లు, అనువర్తనాలు మరియు వెబ్సైట్లతో సహా మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="VPN_APP">%1$s</xliff:g>కి కనెక్ట్ చేయబడింది."</string>
+ <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"మీరు <xliff:g id="VPN_APP">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
+ <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"మీరు ఇమెయిల్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="VPN_APP_0">%1$s</xliff:g> మరియు <xliff:g id="VPN_APP_1">%2$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు."</string>
+ <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"మీ కార్యాలయ ప్రొఫైల్ ఇమెయిల్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="VPN_APP">%1$s</xliff:g>కి కనెక్ట్ చేయబడింది."</string>
+ <string name="monitoring_description_personal_profile_named_vpn" msgid="8179722332380953673">"మీ వ్యక్తిగత ప్రొఫైల్ ఇమెయిల్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="VPN_APP">%1$s</xliff:g>కి కనెక్ట్ చేయబడింది."</string>
<string name="monitoring_description_do_header_generic" msgid="6130190408164834986">"మీ పరికరం <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> ద్వారా నిర్వహించబడుతోంది."</string>
<string name="monitoring_description_do_header_with_name" msgid="2696255132542779511">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> మీ పరికరాన్ని నిర్వహించడానికి <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>ని ఉపయోగిస్తుంది."</string>
<string name="monitoring_description_do_body" msgid="7700878065625769970">"మీ పరికరంతో అనుబంధించబడిన సెట్టింగ్లు, కార్పొరేట్ యాక్సెస్, యాప్లు, డేటా మరియు మీ పరికరం యొక్క స్థాన సమాచారాన్ని మీ నిర్వాహకులు పర్యవేక్షించగలరు మరియు నిర్వహించగలరు."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="1467280496376492558">" "</string>
<string name="monitoring_description_do_learn_more" msgid="645149183455573790">"మరింత తెలుసుకోండి"</string>
- <string name="monitoring_description_do_body_vpn" msgid="7699280130070502303">"మీరు <xliff:g id="VPN_APP">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్లు, అనువర్తనాలు మరియు వెబ్సైట్లతో సహా మీ వ్యక్తిగత నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
+ <string name="monitoring_description_do_body_vpn" msgid="7699280130070502303">"మీరు <xliff:g id="VPN_APP">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ వ్యక్తిగత నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="8292589617720435430">" "</string>
<string name="monitoring_description_vpn_settings" msgid="5264167033247632071">"VPN సెట్టింగ్లను తెరవండి"</string>
<string name="monitoring_description_ca_cert_settings_separator" msgid="7107390013344435439">" "</string>
<string name="monitoring_description_ca_cert_settings" msgid="8329781950135541003">"విశ్వసనీయ ఆధారాలను తెరువు"</string>
<string name="monitoring_description_network_logging" msgid="577305979174002252">"మీ నిర్వాహకులు మీ పరికరంలోని ట్రాఫిక్ని పర్యవేక్షించగల నెట్వర్క్ లాగింగ్ని ఆన్ చేసారు.\n\nమరింత సమాచారం కావాలంటే, మీ నిర్వాహకులను సంప్రదించండి."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"మీరు VPN కనెక్షన్ సెటప్ చేయడానికి ఒక యాప్నకు అనుమతి ఇచ్చారు.\n\nఈ యాప్ ఇమెయిల్లు,యాప్లు మరియు వెబ్సైట్లతో సహా మీ డివైజ్ మరియు నెట్వర్క్ కార్యకలాపాన్ని పర్యవేక్షించగలదు."</string>
- <string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> ద్వారా మీ కార్యాలయ ప్రొఫైల్ నిర్వహించబడుతోంది.\n\nఇమెయిల్లు, అనువర్తనాలు మరియు వెబ్సైట్లతో సహా మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల సామర్థ్యం మీ నిర్వాహకులకు ఉంది.\n\nమరింత సమాచారం కావాలంటే, మీ నిర్వాహకులను సంప్రదించండి.\n\nమీరు VPNకి కూడా కనెక్ట్ అయ్యారు, ఇది మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
+ <string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> ద్వారా మీ కార్యాలయ ప్రొఫైల్ నిర్వహించబడుతోంది.\n\nఇమెయిల్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల సామర్థ్యం మీ నిర్వాహకులకు ఉంది.\n\nమరింత సమాచారం కావాలంటే, మీ నిర్వాహకులను సంప్రదించండి.\n\nమీరు VPNకి కూడా కనెక్ట్ అయ్యారు, ఇది మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ఈ పరికరాన్ని మీ తల్లి/తండ్రి మేనేజ్ చేస్తున్నారు. మీ తల్లి/తండ్రి, మీరు ఉపయోగించే యాప్లు, మీ లొకేషన్, అలాగే మీ పరికర వినియోగ వ్యవధి వంటి సమాచారాన్ని చూడగలరు, మేనేజ్ చేయగలరు."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
- <string name="monitoring_description_app" msgid="376868879287922929">"మీరు ఇమెయిల్లు, అనువర్తనాలు మరియు వెబ్సైట్లతో సహా మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు."</string>
- <string name="monitoring_description_app_personal" msgid="1970094872688265987">"మీరు <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్లు, అనువర్తనాలు మరియు వెబ్సైట్లతో సహా మీ వ్యక్తిగత నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
- <string name="branded_monitoring_description_app_personal" msgid="1703511985892688885">"మీరు <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్లు, అనువర్తనాలు మరియు వెబ్సైట్లతో సహా మీ వ్యక్తిగత నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
- <string name="monitoring_description_app_work" msgid="3713084153786663662">"మీ కార్యాలయ ప్రొఫైల్ <xliff:g id="ORGANIZATION">%1$s</xliff:g> నిర్వహణలో ఉంది. ఇమెయిల్లు, అనువర్తనాలు మరియు వెబ్సైట్లతో సహా మీ కార్యాలయ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="APPLICATION">%2$s</xliff:g>కి ప్రొఫైల్ కనెక్ట్ చేయబడింది.\n\nమరింత సమాచారం కోసం, మీ నిర్వాహకులను సంప్రదించండి."</string>
- <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"మీ కార్యాలయ ప్రొఫైల్ <xliff:g id="ORGANIZATION">%1$s</xliff:g> నిర్వహణలో ఉంది. ఇమెయిల్లు, అనువర్తనాలు మరియు వెబ్సైట్లతో సహా మీ కార్యాలయ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>కి ప్రొఫైల్ కనెక్ట్ చేయబడింది.\n\nమీ వ్యక్తిగత నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>కి కూడా మీరు కనెక్ట్ చేయబడ్డారు."</string>
+ <string name="monitoring_description_app" msgid="376868879287922929">"మీరు ఇమెయిల్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు."</string>
+ <string name="monitoring_description_app_personal" msgid="1970094872688265987">"మీరు <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ వ్యక్తిగత నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
+ <string name="branded_monitoring_description_app_personal" msgid="1703511985892688885">"మీరు <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ వ్యక్తిగత నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
+ <string name="monitoring_description_app_work" msgid="3713084153786663662">"మీ కార్యాలయ ప్రొఫైల్ <xliff:g id="ORGANIZATION">%1$s</xliff:g> నిర్వహణలో ఉంది. ఇమెయిల్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ కార్యాలయ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="APPLICATION">%2$s</xliff:g>కి ప్రొఫైల్ కనెక్ట్ చేయబడింది.\n\nమరింత సమాచారం కోసం, మీ నిర్వాహకులను సంప్రదించండి."</string>
+ <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"మీ కార్యాలయ ప్రొఫైల్ <xliff:g id="ORGANIZATION">%1$s</xliff:g> నిర్వహణలో ఉంది. ఇమెయిల్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ కార్యాలయ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>కి ప్రొఫైల్ కనెక్ట్ చేయబడింది.\n\nమీ వ్యక్తిగత నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>కి కూడా మీరు కనెక్ట్ చేయబడ్డారు."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent ద్వారా అన్లాక్ చేయబడింది"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"మీరు మాన్యువల్గా అన్లాక్ చేస్తే మినహా పరికరం లాక్ చేయబడి ఉంటుంది"</string>
<string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
@@ -898,7 +895,7 @@
<string name="tuner_lock_screen" msgid="2267383813241144544">"లాక్ స్క్రీన్"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"వేడెక్కినందుకు ఫోన్ ఆఫ్ చేయబడింది"</string>
<string name="thermal_shutdown_message" msgid="6142269839066172984">"మీ ఫోన్ ఇప్పుడు సాధారణంగా పని చేస్తోంది.\nమరింత సమాచారం కోసం ట్యాప్ చేయండి"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"మీ ఫోన్ చాలా వేడిగా ఉంది, కనుక చల్లబర్చడానికి ఆఫ్ చేయబడింది. మీ ఫోన్ ఇప్పుడు సాధారణంగా పని చేస్తుంది.\n\nమీరు ఇలా చేస్తే మీ ఫోన్ చాలా వేడెక్కవచ్చు:\n • వనరు-ఆధారిత అనువర్తనాలు (గేమింగ్, వీడియో లేదా నావిగేషన్ వంటి అనువర్తనాలు) ఉపయోగించడం\n • పెద్ద ఫైల్లను డౌన్లోడ్ లేదా అప్లోడ్ చేయడం\n • అధిక ఉష్ణోగ్రతలలో మీ ఫోన్ని ఉపయోగించడం"</string>
+ <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"మీ ఫోన్ చాలా వేడిగా ఉంది, కనుక చల్లబర్చడానికి ఆఫ్ చేయబడింది. మీ ఫోన్ ఇప్పుడు సాధారణంగా పని చేస్తుంది.\n\nమీరు ఇలా చేస్తే మీ ఫోన్ చాలా వేడెక్కవచ్చు:\n • వనరు-ఆధారిత యాప్లు (గేమింగ్, వీడియో లేదా నావిగేషన్ వంటి యాప్లు) ఉపయోగించడం\n • పెద్ద ఫైల్లను డౌన్లోడ్ లేదా అప్లోడ్ చేయడం\n • అధిక ఉష్ణోగ్రతలలో మీ ఫోన్ని ఉపయోగించడం"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"తీసుకోవాల్సిన జాగ్రత్తలు ఏమిటో చూడండి"</string>
<string name="high_temp_title" msgid="2218333576838496100">"ఫోన్ వేడెక్కుతోంది"</string>
<string name="high_temp_notif_message" msgid="1277346543068257549">"ఫోన్ను చల్లబరిచే క్రమంలో కొన్ని ఫీచర్లు పరిమితం చేయబడ్డాయి.\nమరింత సమాచారం కోసం ట్యాప్ చేయండి"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 65ee106..03bb4c4 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"ผู้ใช้ใหม่"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"อินเทอร์เน็ต"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"ใช้บนเครื่องบินได้อย่างปลอดภัย"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"เครือข่ายที่พร้อมใช้งาน"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"ใช้งานเครือข่ายไม่ได้"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"ไม่ได้เชื่อมต่อ"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"ไม่มีเครือข่าย"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"ปิด WiFi"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 9eab088..f037fd5d 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Bagong user"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Ligtas gamitin sa eroplano"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Available ang mga network"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Hindi available ang mga network"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Hindi Nakakonekta"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Walang Network"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Naka-off ang Wi-Fi"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 921cce8..ca4434b 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Yeni kullanıcı"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Kablosuz"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"İnternet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Uçakta kullanımı güvenli"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Kullanılabilir ağlar"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Kullanılamayan ağlar"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Bağlı Değil"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ağ yok"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Kablosuz Kapalı"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 66a8cfb..4bbd062 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -360,12 +360,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Новий користувач"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Інтернет"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Безпечні в літаку"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Доступні мережі"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Недоступні мережі"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Не під’єднано."</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Немає мережі"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi вимкнено"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 3865bc0..28b28c4 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"نیا صارف"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"انٹرنیٹ"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"ہوائی جہاز کیلئے محفوظ"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"نیٹ ورکس دستیاب ہیں"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"نیٹ ورکس دستیاب نہیں ہیں"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"مربوط نہیں ہے"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"کوئی نیٹ ورک نہیں ہے"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi آف ہے"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index d6061a6..315ed75 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -344,10 +344,8 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Kiritish usuli"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Joylashuv"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Joylashuvni aniqlash xizmati yoqilmagan"</string>
- <!-- no translation found for quick_settings_camera_label (1367149596242401934) -->
- <skip />
- <!-- no translation found for quick_settings_mic_label (8245831073612564953) -->
- <skip />
+ <string name="quick_settings_camera_label" msgid="1367149596242401934">"Kamerani bloklash"</string>
+ <string name="quick_settings_mic_label" msgid="8245831073612564953">"Mikrofonni oʻchirish"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Media qurilma"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"Favqulodda chaqiruvlar"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 23e72c1..f0d1a90 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Người dùng mới"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"An toàn với máy bay"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Có mạng"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Không có mạng"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Chưa được kết nối"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Không có mạng nào"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Tắt Wi-Fi"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 55b524e..a18a426 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"新用户"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"WLAN"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"互联网"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"可在飞机上安全使用"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"有可用的网络"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"没有可用的网络"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"未连接"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"无网络"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"WLAN:关闭"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 701f32d..1268ced 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"新使用者"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"互聯網"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"飛行安全"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"有可用的網絡"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"網絡無法使用"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"未連線"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"沒有網絡"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi 關閉"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 4210ec1..e11013f 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"新使用者"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"網際網路"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"飛航安全"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"有可用的網路"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"沒有網路"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"未連線"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"沒有網路"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi 已關閉"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 940fc19..b022aca 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -358,12 +358,9 @@
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Umsebenzisi omusha"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"I-Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"I-inthanethi"</string>
- <!-- no translation found for quick_settings_airplane_safe_label (2665758539772645899) -->
- <skip />
- <!-- no translation found for quick_settings_networks_available (1875138606855420438) -->
- <skip />
- <!-- no translation found for quick_settings_networks_unavailable (1167847013337940082) -->
- <skip />
+ <string name="quick_settings_airplane_safe_label" msgid="2665758539772645899">"Indiza ephephile"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Amanethiwekhi ayatholakala"</string>
+ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Amanethiwekhi awatholakali"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Akuxhunyiwe"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ayikho inethiwekhi"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"I-Wi-Fi icimile"</string>
diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml
index db8bfec..de2db98 100644
--- a/packages/SystemUI/res/values/flags.xml
+++ b/packages/SystemUI/res/values/flags.xml
@@ -20,6 +20,7 @@
<bool name="flag_notification_pipeline2">false</bool>
<bool name="flag_notification_pipeline2_rendering">false</bool>
+ <bool name="flag_shade_is_opaque">true</bool>
<!-- b/171917882 -->
<bool name="flag_notification_twocolumn">false</bool>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index ac2e342..6e9c5dc 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -974,6 +974,11 @@
<!-- QuickSettings: Text to prompt the user to stop an ongoing recording [CHAR LIMIT=20] -->
<string name="quick_settings_screen_record_stop">Stop</string>
+ <!--- Content of dialog triggered if the microphone is disabled but an app tried to access it. [CHAR LIMIT=NONE] -->
+ <string name="sensor_privacy_start_use_mic_dialog_content">To continue, <b><xliff:g id="app" example="Gmail">%s</xliff:g></b> needs access to your device microphone.</string>
+ <!--- Content of dialog triggered if the camera is disabled but an app tried to access it. [CHAR LIMIT=NONE] -->
+ <string name="sensor_privacy_start_use_camera_dialog_content">To continue, <b><xliff:g id="app" example="Gmail">%s</xliff:g></b> needs access to your device’s camera.</string>
+
<!-- Default name for the media device shown in the output switcher when the name is not available [CHAR LIMIT=30] -->
<string name="media_seamless_remote_device">Device</string>
@@ -1039,6 +1044,9 @@
<!-- Message shown when face authentication fails and the pin pad is visible. [CHAR LIMIT=60] -->
<string name="keyguard_retry">Swipe up to try again</string>
+ <!-- Message shown when notifying user to unlock in order to use NFC. [CHAR LIMIT=60] -->
+ <string name="require_unlock_for_nfc">Unlock to use NFC</string>
+
<!-- Text on keyguard screen and in Quick Settings footer indicating that the user's device belongs to their organization. [CHAR LIMIT=60] -->
<string name="do_disclosure_generic">This device belongs to your organization</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index d706ec2..db260ce 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -319,6 +319,7 @@
<item name="android:colorControlHighlight">@*android:color/primary_text_material_dark</item>
<item name="*android:lockPatternStyle">@style/LockPatternStyle</item>
<item name="passwordStyle">@style/PasswordTheme</item>
+ <item name="numPadKeyStyle">@style/NumPadKey</item>
<item name="backgroundProtectedStyle">@style/BackgroundProtectedStyle</item>
<item name="android:homeAsUpIndicator">@drawable/ic_arrow_back</item>
<item name="shadowRadius">@dimen/keyguard_shadow_radius</item>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index 57a4dab..388eeb6 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -24,7 +24,6 @@
import android.graphics.Rect;
import android.os.Bundle;
import android.view.MotionEvent;
-import android.window.TransitionFilter;
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
import com.android.systemui.shared.recents.model.Task;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index 4ddfccb2..6a6b964 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -27,10 +27,8 @@
import android.content.res.ColorStateList;
import android.graphics.Rect;
import android.util.AttributeSet;
-import android.view.ContextThemeWrapper;
import android.view.KeyEvent;
import android.view.View;
-import android.widget.ImageButton;
import com.android.internal.widget.LockscreenCredential;
import com.android.settingslib.Utils;
@@ -42,10 +40,9 @@
public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView {
protected PasswordTextView mPasswordEntry;
- private View mOkButton;
- private ImageButton mDeleteButton;
+ private NumPadButton mOkButton;
+ private NumPadButton mDeleteButton;
private NumPadKey[] mButtons = new NumPadKey[10];
- private View mDivider;
public KeyguardPinBasedInputView(Context context) {
this(context, null);
@@ -152,7 +149,6 @@
mDeleteButton = findViewById(R.id.delete_button);
mDeleteButton.setVisibility(View.VISIBLE);
- mDivider = findViewById(R.id.divider);
mButtons[0] = findViewById(R.id.key0);
mButtons[1] = findViewById(R.id.key1);
@@ -181,12 +177,9 @@
int deleteColor = Utils.getColorAttr(getContext(), android.R.attr.textColorSecondary)
.getDefaultColor();
mDeleteButton.setImageTintList(ColorStateList.valueOf(deleteColor));
- mDivider.setBackground(getContext().getDrawable(R.drawable.pin_divider));
- ContextThemeWrapper themedContext = new ContextThemeWrapper(mContext,
- R.style.Widget_TextView_NumPadKey);
- mDeleteButton.setBackground(themedContext.getDrawable(R.drawable.ripple_drawable_pin));
- mOkButton.setBackground(themedContext.getDrawable(R.drawable.ripple_drawable_pin));
+ mDeleteButton.reloadColors();
+ mOkButton.reloadColors();
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 826020c..973b493 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -27,6 +27,7 @@
import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
+import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.NotificationIconContainer;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -53,8 +54,9 @@
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final ConfigurationController mConfigurationController;
private final NotificationIconAreaController mNotificationIconAreaController;
+ private final DozeParameters mDozeParameters;
- private boolean mKeyguardStatusViewAnimating;
+ private boolean mKeyguardStatusViewVisibilityAnimating;
private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
@Inject
@@ -65,7 +67,8 @@
KeyguardStateController keyguardStateController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
ConfigurationController configurationController,
- NotificationIconAreaController notificationIconAreaController) {
+ NotificationIconAreaController notificationIconAreaController,
+ DozeParameters dozeParameters) {
super(keyguardStatusView);
mKeyguardSliceViewController = keyguardSliceViewController;
mKeyguardClockSwitchController = keyguardClockSwitchController;
@@ -73,6 +76,7 @@
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mConfigurationController = configurationController;
mNotificationIconAreaController = notificationIconAreaController;
+ mDozeParameters = dozeParameters;
}
@Override
@@ -140,7 +144,7 @@
* Set keyguard status view alpha.
*/
public void setAlpha(float alpha) {
- if (!mKeyguardStatusViewAnimating) {
+ if (!mKeyguardStatusViewVisibilityAnimating) {
mView.setAlpha(alpha);
}
}
@@ -194,8 +198,12 @@
* Update position of the view with an optional animation
*/
public void updatePosition(int x, int y, float scale, boolean animate) {
- PropertyAnimator.setProperty(mView, AnimatableProperty.Y, y, CLOCK_ANIMATION_PROPERTIES,
- animate);
+ // We animate the status view visible/invisible using Y translation, so don't change it
+ // while the animation is running.
+ if (!mKeyguardStatusViewVisibilityAnimating) {
+ PropertyAnimator.setProperty(mView, AnimatableProperty.Y, y, CLOCK_ANIMATION_PROPERTIES,
+ animate);
+ }
if (mLockScreenMode == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1) {
// reset any prior movement
@@ -223,10 +231,10 @@
boolean goingToFullShade,
int oldStatusBarState) {
mView.animate().cancel();
- mKeyguardStatusViewAnimating = false;
+ mKeyguardStatusViewVisibilityAnimating = false;
if ((!keyguardFadingAway && oldStatusBarState == KEYGUARD
&& statusBarState != KEYGUARD) || goingToFullShade) {
- mKeyguardStatusViewAnimating = true;
+ mKeyguardStatusViewVisibilityAnimating = true;
mView.animate()
.alpha(0f)
.setStartDelay(0)
@@ -242,7 +250,7 @@
}
} else if (oldStatusBarState == StatusBarState.SHADE_LOCKED && statusBarState == KEYGUARD) {
mView.setVisibility(View.VISIBLE);
- mKeyguardStatusViewAnimating = true;
+ mKeyguardStatusViewVisibilityAnimating = true;
mView.setAlpha(0f);
mView.animate()
.alpha(1f)
@@ -252,7 +260,7 @@
.withEndAction(mAnimateKeyguardStatusViewVisibleEndRunnable);
} else if (statusBarState == KEYGUARD) {
if (keyguardFadingAway) {
- mKeyguardStatusViewAnimating = true;
+ mKeyguardStatusViewVisibilityAnimating = true;
mView.animate()
.alpha(0)
.translationYBy(-getHeight() * 0.05f)
@@ -261,6 +269,22 @@
.setStartDelay(0)
.withEndAction(mAnimateKeyguardStatusViewInvisibleEndRunnable)
.start();
+ } else if (mDozeParameters.shouldControlUnlockedScreenOff()) {
+ mKeyguardStatusViewVisibilityAnimating = true;
+
+ mView.setVisibility(View.VISIBLE);
+ mView.setAlpha(0f);
+
+ float curTranslationY = mView.getTranslationY();
+ mView.setTranslationY(curTranslationY - getHeight() * 0.1f);
+ mView.animate()
+ .setStartDelay((int) (StackStateAnimator.ANIMATION_DURATION_WAKEUP * .6f))
+ .setDuration(StackStateAnimator.ANIMATION_DURATION_WAKEUP)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .alpha(1f)
+ .translationY(curTranslationY)
+ .withEndAction(mAnimateKeyguardStatusViewVisibleEndRunnable)
+ .start();
} else {
mView.setVisibility(View.VISIBLE);
mView.setAlpha(1f);
@@ -367,17 +391,17 @@
};
private final Runnable mAnimateKeyguardStatusViewInvisibleEndRunnable = () -> {
- mKeyguardStatusViewAnimating = false;
+ mKeyguardStatusViewVisibilityAnimating = false;
mView.setVisibility(View.INVISIBLE);
};
private final Runnable mAnimateKeyguardStatusViewGoneEndRunnable = () -> {
- mKeyguardStatusViewAnimating = false;
+ mKeyguardStatusViewVisibilityAnimating = false;
mView.setVisibility(View.GONE);
};
private final Runnable mAnimateKeyguardStatusViewVisibleEndRunnable = () -> {
- mKeyguardStatusViewAnimating = false;
+ mKeyguardStatusViewVisibilityAnimating = false;
};
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index b43496c..e59769b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -60,6 +60,7 @@
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
+import android.nfc.NfcAdapter;
import android.os.Build;
import android.os.CancellationSignal;
import android.os.Handler;
@@ -183,6 +184,7 @@
private static final int MSG_KEYGUARD_GOING_AWAY = 342;
private static final int MSG_LOCK_SCREEN_MODE = 343;
private static final int MSG_TIME_FORMAT_UPDATE = 344;
+ private static final int MSG_REQUIRE_NFC_UNLOCK = 345;
public static final int LOCK_SCREEN_MODE_NORMAL = 0;
public static final int LOCK_SCREEN_MODE_LAYOUT_1 = 1;
@@ -1259,6 +1261,8 @@
} else if (ACTION_USER_REMOVED.equals(action)) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_REMOVED,
intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1), 0));
+ } else if (NfcAdapter.ACTION_REQUIRE_UNLOCK_FOR_NFC.equals(action)) {
+ mHandler.sendEmptyMessage(MSG_REQUIRE_NFC_UNLOCK);
}
}
};
@@ -1314,6 +1318,16 @@
public void onAuthenticationAcquired(int acquireInfo) {
handleFingerprintAcquired(acquireInfo);
}
+
+ @Override
+ public void onUdfpsPointerDown(int sensorId) {
+ Log.d(TAG, "onUdfpsPointerDown, sensorId: " + sensorId);
+ }
+
+ @Override
+ public void onUdfpsPointerUp(int sensorId) {
+ Log.d(TAG, "onUdfpsPointerUp, sensorId: " + sensorId);
+ }
};
private final FaceManager.FaceDetectionCallback mFaceDetectionCallback
@@ -1725,6 +1739,8 @@
break;
case MSG_TIME_FORMAT_UPDATE:
handleTimeFormatUpdate((String) msg.obj);
+ case MSG_REQUIRE_NFC_UNLOCK:
+ handleRequireUnlockForNfc();
break;
default:
super.handleMessage(msg);
@@ -1787,6 +1803,7 @@
allUserFilter.addAction(ACTION_USER_UNLOCKED);
allUserFilter.addAction(ACTION_USER_STOPPED);
allUserFilter.addAction(ACTION_USER_REMOVED);
+ allUserFilter.addAction(NfcAdapter.ACTION_REQUIRE_UNLOCK_FOR_NFC);
mBroadcastDispatcher.registerReceiverWithHandler(mBroadcastAllReceiver, allUserFilter,
mHandler, UserHandle.ALL);
@@ -2690,6 +2707,19 @@
}
/**
+ * Handle {@link #MSG_REQUIRE_NFC_UNLOCK}
+ */
+ private void handleRequireUnlockForNfc() {
+ Assert.isMainThread();
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onRequireUnlockForNfc();
+ }
+ }
+ }
+
+ /**
* Handle {@link #MSG_REPORT_EMERGENCY_CALL_ACTION}
*/
private void handleReportEmergencyCallAction() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 36617c2..e561a5a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -328,4 +328,9 @@
*/
public void onLockScreenModeChanged(int mode) { }
+ /**
+ * Called when notifying user to unlock in order to use NFC.
+ */
+ public void onRequireUnlockForNfc() { }
+
}
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
new file mode 100644
index 0000000..cdf9858
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard;
+
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.GradientDrawable;
+import android.view.ContextThemeWrapper;
+import android.view.ViewGroup;
+
+import androidx.annotation.StyleRes;
+
+import com.android.internal.graphics.ColorUtils;
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+
+/**
+ * Provides background color and radius animations for key pad buttons.
+ */
+class NumPadAnimator {
+ private ValueAnimator mAnimator;
+ private GradientDrawable mBackground;
+ private int mMargin;
+ private int mNormalColor;
+ private int mHighlightColor;
+ private int mStyle;
+
+ NumPadAnimator(Context context, final GradientDrawable background, @StyleRes int style) {
+ mBackground = (GradientDrawable) background.mutate();
+ mStyle = style;
+
+ reloadColors(context);
+
+ mMargin = context.getResources().getDimensionPixelSize(R.dimen.num_pad_key_margin);
+
+ // Actual values will be updated later, usually during an onLayout() call
+ mAnimator = ValueAnimator.ofFloat(0f);
+ mAnimator.setDuration(250);
+ mAnimator.setInterpolator(Interpolators.LINEAR);
+ mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ public void onAnimationUpdate(ValueAnimator anim) {
+ mBackground.setCornerRadius((float) anim.getAnimatedValue());
+ mBackground.setColor(ColorUtils.blendARGB(mHighlightColor, mNormalColor,
+ anim.getAnimatedFraction()));
+ }
+ });
+
+ }
+
+ void updateMargin(ViewGroup.MarginLayoutParams lp) {
+ lp.setMargins(mMargin, mMargin, mMargin, mMargin);
+ }
+
+ void onLayout(int height) {
+ float startRadius = height / 10f;
+ float endRadius = height / 2f;
+ mBackground.setCornerRadius(endRadius);
+ mAnimator.setFloatValues(startRadius, endRadius);
+ }
+
+ void start() {
+ mAnimator.cancel();
+ mAnimator.start();
+ }
+
+ /**
+ * Reload colors from resources.
+ **/
+ void reloadColors(Context context) {
+ int[] customAttrs = {android.R.attr.colorControlNormal,
+ android.R.attr.colorControlHighlight};
+
+ ContextThemeWrapper ctw = new ContextThemeWrapper(context, mStyle);
+ TypedArray a = ctw.obtainStyledAttributes(customAttrs);
+ mNormalColor = a.getColor(0, 0);
+ mHighlightColor = a.getColor(1, 0);
+ a.recycle();
+
+ mBackground.setColor(mNormalColor);
+ }
+}
+
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
new file mode 100644
index 0000000..3728106
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
@@ -0,0 +1,67 @@
+/*
+ * 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.keyguard;
+
+import android.content.Context;
+import android.graphics.drawable.GradientDrawable;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.ViewGroup;
+
+/**
+ * Similar to the {@link NumPadKey}, but displays an image.
+ */
+public class NumPadButton extends AlphaOptimizedImageButton {
+
+ private final NumPadAnimator mAnimator;
+
+ public NumPadButton(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ mAnimator = new NumPadAnimator(context, (GradientDrawable) getBackground(),
+ attrs.getStyleAttribute());
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ mAnimator.updateMargin((ViewGroup.MarginLayoutParams) getLayoutParams());
+
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ // Set width/height to the same value to ensure a smooth circle for the bg
+ setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth());
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+
+ mAnimator.onLayout(b - t);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ mAnimator.start();
+ return super.onTouchEvent(event);
+ }
+
+ /**
+ * Reload colors from resources.
+ **/
+ public void reloadColors() {
+ mAnimator.reloadColors(getContext());
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index a518205..8ebcb20 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -18,11 +18,10 @@
import android.content.Context;
import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
import android.os.PowerManager;
import android.os.SystemClock;
import android.util.AttributeSet;
-import android.view.ContextThemeWrapper;
import android.view.HapticFeedbackConstants;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -48,6 +47,8 @@
private int mTextViewResId;
private PasswordTextView mTextView;
+ private final NumPadAnimator mAnimator;
+
private View.OnClickListener mListener = new View.OnClickListener() {
@Override
public void onClick(View thisView) {
@@ -73,7 +74,7 @@
}
public NumPadKey(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
+ this(context, attrs, R.attr.numPadKeyStyle);
}
public NumPadKey(Context context, AttributeSet attrs, int defStyle) {
@@ -84,7 +85,8 @@
super(context, attrs, defStyle);
setFocusable(true);
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NumPadKey);
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NumPadKey, defStyle,
+ contentResource);
try {
mDigit = a.getInt(R.styleable.NumPadKey_digit, mDigit);
@@ -116,20 +118,16 @@
final int len = klondike.length();
if (len > 0) {
mKlondikeText.setText(klondike);
- } else {
+ } else if (mKlondikeText.getVisibility() != View.GONE) {
mKlondikeText.setVisibility(View.INVISIBLE);
}
}
}
- a = context.obtainStyledAttributes(attrs, android.R.styleable.View);
- if (!a.hasValueOrEmpty(android.R.styleable.View_background)) {
- Drawable rippleDrawable = new ContextThemeWrapper(mContext,
- R.style.Widget_TextView_NumPadKey).getDrawable(R.drawable.ripple_drawable_pin);
- setBackground(rippleDrawable);
- }
- a.recycle();
setContentDescription(mDigitText.getText().toString());
+
+ mAnimator = new NumPadAnimator(context, (GradientDrawable) getBackground(),
+ R.style.NumPadKey);
}
/**
@@ -142,9 +140,8 @@
.getDefaultColor();
mDigitText.setTextColor(textColor);
mKlondikeText.setTextColor(klondikeColor);
- Drawable rippleDrawable = new ContextThemeWrapper(mContext,
- R.style.Widget_TextView_NumPadKey).getDrawable(R.drawable.ripple_drawable_pin);
- setBackground(rippleDrawable);
+
+ mAnimator.reloadColors(getContext());
}
@Override
@@ -152,13 +149,21 @@
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
doHapticKeyClick();
}
+
+ mAnimator.start();
+
return super.onTouchEvent(event);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ mAnimator.updateMargin((ViewGroup.MarginLayoutParams) getLayoutParams());
+
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
measureChildren(widthMeasureSpec, heightMeasureSpec);
+
+ // Set width/height to the same value to ensure a smooth circle for the bg
+ setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth());
}
@Override
@@ -176,6 +181,8 @@
left = centerX - mKlondikeText.getMeasuredWidth() / 2;
mKlondikeText.layout(left, top, left + mKlondikeText.getMeasuredWidth(), bottom);
+
+ mAnimator.onLayout(b - t);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender.java
deleted file mode 100644
index c0f8cae..0000000
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui;
-
-import android.annotation.NonNull;
-import android.app.Notification;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.ArraySet;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.statusbar.NotificationInteractionTracker;
-import com.android.systemui.statusbar.NotificationLifetimeExtender;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.util.time.SystemClock;
-
-import javax.inject.Inject;
-
-/**
- * Extends the lifetime of foreground notification services such that they show for at least
- * five seconds
- */
-public class ForegroundServiceLifetimeExtender implements NotificationLifetimeExtender {
-
- private static final String TAG = "FGSLifetimeExtender";
- @VisibleForTesting
- static final int MIN_FGS_TIME_MS = 5000;
-
- private NotificationSafeToRemoveCallback mNotificationSafeToRemoveCallback;
- private ArraySet<NotificationEntry> mManagedEntries = new ArraySet<>();
- private Handler mHandler = new Handler(Looper.getMainLooper());
- private final SystemClock mSystemClock;
- private final NotificationInteractionTracker mInteractionTracker;
-
- @Inject
- public ForegroundServiceLifetimeExtender(
- NotificationInteractionTracker interactionTracker,
- SystemClock systemClock) {
- mSystemClock = systemClock;
- mInteractionTracker = interactionTracker;
- }
-
- @Override
- public void setCallback(@NonNull NotificationSafeToRemoveCallback callback) {
- mNotificationSafeToRemoveCallback = callback;
- }
-
- @Override
- public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) {
- if ((entry.getSbn().getNotification().flags
- & Notification.FLAG_FOREGROUND_SERVICE) == 0) {
- return false;
- }
-
- // Entry has triggered a HUN or some other interruption, therefore it has been seen and the
- // interrupter might be retaining it anyway.
- if (entry.hasInterrupted()) {
- return false;
- }
-
- boolean hasInteracted = mInteractionTracker.hasUserInteractedWith(entry.getKey());
- long aliveTime = mSystemClock.uptimeMillis() - entry.getCreationTime();
- return aliveTime < MIN_FGS_TIME_MS && !hasInteracted;
- }
-
- @Override
- public boolean shouldExtendLifetimeForPendingNotification(
- @NonNull NotificationEntry entry) {
- return shouldExtendLifetime(entry);
- }
-
- @Override
- public void setShouldManageLifetime(
- @NonNull NotificationEntry entry, boolean shouldManage) {
- if (!shouldManage) {
- mManagedEntries.remove(entry);
- return;
- }
-
- mManagedEntries.add(entry);
-
- Runnable r = () -> {
- if (mManagedEntries.contains(entry)) {
- mManagedEntries.remove(entry);
- if (mNotificationSafeToRemoveCallback != null) {
- mNotificationSafeToRemoveCallback.onSafeToRemove(entry.getKey());
- }
- }
- };
- long delayAmt = MIN_FGS_TIME_MS
- - (mSystemClock.uptimeMillis() - entry.getCreationTime());
- mHandler.postDelayed(r, delayAmt);
- }
-}
-
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
index d6cb114..04e26d3 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
@@ -50,7 +50,6 @@
ForegroundServiceController foregroundServiceController,
NotificationEntryManager notificationEntryManager,
NotifPipeline notifPipeline,
- ForegroundServiceLifetimeExtender fgsLifetimeExtender,
SystemClock systemClock) {
mContext = context;
mForegroundServiceController = foregroundServiceController;
@@ -78,7 +77,6 @@
removeNotification(entry.getSbn());
}
});
- mEntryManager.addNotificationLifetimeExtender(fgsLifetimeExtender);
notifPipeline.addCollectionListener(new NotifCollectionListener() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
index c2f80d4..033a355 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
@@ -35,11 +35,12 @@
import android.util.AttributeSet;
import android.util.Log;
import android.util.MathUtils;
-import android.util.TypedValue;
import android.view.Surface;
import android.view.View;
import android.view.ViewTreeObserver;
+import com.android.internal.graphics.ColorUtils;
+import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.doze.DozeReceiver;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -157,16 +158,16 @@
@Override
public void dozeTimeTick() {
- updateAodPosition();
+ updateAodPositionAndColor();
}
@Override
public void onDozeAmountChanged(float linear, float eased) {
mInterpolatedDarkAmount = eased;
- updateAodPosition();
+ updateAodPositionAndColor();
}
- private void updateAodPosition() {
+ private void updateAodPositionAndColor() {
mBurnInOffsetX = MathUtils.lerp(0f,
getBurnInOffset(mMaxBurnInOffsetX * 2, true /* xAxis */)
- mMaxBurnInOffsetX,
@@ -175,6 +176,7 @@
getBurnInOffset(mMaxBurnInOffsetY * 2, false /* xAxis */)
- 0.5f * mMaxBurnInOffsetY,
mInterpolatedDarkAmount);
+ updateColor();
postInvalidate();
}
@@ -231,21 +233,23 @@
Log.v(TAG, "onAttachedToWindow");
// Retrieve the colors each time, since it depends on day/night mode
- final TypedValue tv = new TypedValue();
- mContext.getTheme().resolveAttribute(R.attr.wallpaperTextColor, tv, true);
- final int authIconColor = mContext.getResources()
- .getColor(tv.resourceId, mContext.getTheme());
- final int enrollIconColor = mContext.getColor(R.color.udfps_enroll_icon);
-
- if (mShowReason == IUdfpsOverlayController.REASON_AUTH) {
- mFingerprintDrawable.setTint(authIconColor);
- } else if (mShowReason == IUdfpsOverlayController.REASON_ENROLL) {
- mFingerprintDrawable.setTint(enrollIconColor);
- }
+ updateColor();
getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsListener);
}
+ private void updateColor() {
+ if (mShowReason == IUdfpsOverlayController.REASON_AUTH) {
+ final int lockScreenIconColor = Utils.getColorAttrDefaultColor(mContext,
+ com.android.systemui.R.attr.wallpaperTextColor);
+ final int ambientDisplayIconColor = Color.WHITE;
+ mFingerprintDrawable.setTint(ColorUtils.blendARGB(lockScreenIconColor,
+ ambientDisplayIconColor, mInterpolatedDarkAmount));
+ } else if (mShowReason == IUdfpsOverlayController.REASON_ENROLL) {
+ mFingerprintDrawable.setTint(mContext.getColor(R.color.udfps_enroll_icon));
+ }
+ }
+
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index 0fdaae8..5c8c9f2 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -96,7 +96,9 @@
*/
private void updateAnimateScreenOff() {
if (mCanAnimateTransition) {
- final boolean controlScreenOff = mDozeParameters.getAlwaysOn() && mKeyguardShowing
+ final boolean controlScreenOff =
+ mDozeParameters.getAlwaysOn()
+ && (mKeyguardShowing || mDozeParameters.shouldControlUnlockedScreenOff())
&& !mHost.isPowerSaveActive();
mDozeParameters.setControlScreenOffAnimation(controlScreenOff);
mHost.setAnimateScreenOff(controlScreenOff);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardLifecyclesDispatcher.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardLifecyclesDispatcher.java
index f527775..5019e65 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardLifecyclesDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardLifecyclesDispatcher.java
@@ -18,6 +18,7 @@
import android.os.Handler;
import android.os.Message;
+import android.os.PowerManager;
import com.android.systemui.dagger.SysUISingleton;
@@ -53,6 +54,17 @@
mHandler.obtainMessage(what).sendToTarget();
}
+ /**
+ * @param what Message to send.
+ * @param pmReason Reason this message was triggered - this should be a value from either
+ * {@link PowerManager.WakeReason} or {@link PowerManager.GoToSleepReason}.
+ */
+ void dispatch(int what, int pmReason) {
+ final Message message = mHandler.obtainMessage(what);
+ message.arg1 = pmReason;
+ message.sendToTarget();
+ }
+
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
@@ -70,13 +82,13 @@
mScreenLifecycle.dispatchScreenTurnedOff();
break;
case STARTED_WAKING_UP:
- mWakefulnessLifecycle.dispatchStartedWakingUp();
+ mWakefulnessLifecycle.dispatchStartedWakingUp(msg.arg1 /* pmReason */);
break;
case FINISHED_WAKING_UP:
mWakefulnessLifecycle.dispatchFinishedWakingUp();
break;
case STARTED_GOING_TO_SLEEP:
- mWakefulnessLifecycle.dispatchStartedGoingToSleep();
+ mWakefulnessLifecycle.dispatchStartedGoingToSleep(msg.arg1 /* pmReason */);
break;
case FINISHED_GOING_TO_SLEEP:
mWakefulnessLifecycle.dispatchFinishedGoingToSleep();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index cb83656..1b033e9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -24,9 +24,11 @@
import android.os.Bundle;
import android.os.Debug;
import android.os.IBinder;
+import android.os.PowerManager;
import android.os.Process;
import android.os.Trace;
import android.util.Log;
+import android.view.WindowManagerPolicyConstants;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IKeyguardDrawnCallback;
@@ -117,27 +119,32 @@
}
@Override // Binder interface
- public void onStartedGoingToSleep(int reason) {
+ public void onStartedGoingToSleep(@PowerManager.GoToSleepReason int pmSleepReason) {
checkPermission();
- mKeyguardViewMediator.onStartedGoingToSleep(reason);
+ mKeyguardViewMediator.onStartedGoingToSleep(
+ WindowManagerPolicyConstants.translateSleepReasonToOffReason(pmSleepReason));
mKeyguardLifecyclesDispatcher.dispatch(
- KeyguardLifecyclesDispatcher.STARTED_GOING_TO_SLEEP);
+ KeyguardLifecyclesDispatcher.STARTED_GOING_TO_SLEEP, pmSleepReason);
}
@Override // Binder interface
- public void onFinishedGoingToSleep(int reason, boolean cameraGestureTriggered) {
+ public void onFinishedGoingToSleep(
+ @PowerManager.GoToSleepReason int pmSleepReason, boolean cameraGestureTriggered) {
checkPermission();
- mKeyguardViewMediator.onFinishedGoingToSleep(reason, cameraGestureTriggered);
+ mKeyguardViewMediator.onFinishedGoingToSleep(
+ WindowManagerPolicyConstants.translateSleepReasonToOffReason(pmSleepReason),
+ cameraGestureTriggered);
mKeyguardLifecyclesDispatcher.dispatch(
KeyguardLifecyclesDispatcher.FINISHED_GOING_TO_SLEEP);
}
@Override // Binder interface
- public void onStartedWakingUp() {
+ public void onStartedWakingUp(@PowerManager.WakeReason int pmWakeReason) {
Trace.beginSection("KeyguardService.mBinder#onStartedWakingUp");
checkPermission();
mKeyguardViewMediator.onStartedWakingUp();
- mKeyguardLifecyclesDispatcher.dispatch(KeyguardLifecyclesDispatcher.STARTED_WAKING_UP);
+ mKeyguardLifecyclesDispatcher.dispatch(
+ KeyguardLifecyclesDispatcher.STARTED_WAKING_UP, pmWakeReason);
Trace.endSection();
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index f79b991..e732669 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -85,17 +85,17 @@
import com.android.keyguard.KeyguardViewController;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.Dumpable;
-import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.keyguard.KeyguardService;
import com.android.systemui.keyguard.dagger.KeyguardModule;
import com.android.systemui.navigationbar.NavigationModeController;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
+import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -149,7 +149,8 @@
* directly to the keyguard UI is posted to a {@link android.os.Handler} to ensure it is taken on the UI
* thread of the keyguard.
*/
-public class KeyguardViewMediator extends SystemUI implements Dumpable {
+public class KeyguardViewMediator extends SystemUI implements Dumpable,
+ StatusBarStateController.StateListener {
private static final int KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000;
private static final long KEYGUARD_DONE_PENDING_TIMEOUT_MS = 3000;
@@ -223,6 +224,7 @@
private boolean mBootSendUserPresent;
private boolean mShuttingDown;
private boolean mDozing;
+ private boolean mAnimatingScreenOff;
private final FalsingCollector mFalsingCollector;
/** High level access to the power manager for WakeLocks */
@@ -709,6 +711,7 @@
};
private DeviceConfigProxy mDeviceConfig;
+ private DozeParameters mDozeParameters;
/**
* Injected constructor. See {@link KeyguardModule}.
@@ -725,7 +728,9 @@
TrustManager trustManager,
DeviceConfigProxy deviceConfig,
NavigationModeController navigationModeController,
- KeyguardDisplayManager keyguardDisplayManager) {
+ KeyguardDisplayManager keyguardDisplayManager,
+ DozeParameters dozeParameters,
+ StatusBarStateController statusBarStateController) {
super(context);
mFalsingCollector = falsingCollector;
mLockPatternUtils = lockPatternUtils;
@@ -751,6 +756,8 @@
QuickStepContract.isGesturalMode(navigationModeController.addListener(mode -> {
mInGestureNavigationMode = QuickStepContract.isGesturalMode(mode);
}));
+ mDozeParameters = dozeParameters;
+ statusBarStateController.addCallback(this);
}
public void userActivity() {
@@ -863,11 +870,11 @@
/**
* Called to let us know the screen was turned off.
- * @param why either {@link WindowManagerPolicyConstants#OFF_BECAUSE_OF_USER} or
- * {@link WindowManagerPolicyConstants#OFF_BECAUSE_OF_TIMEOUT}.
+ * @param offReason either {@link WindowManagerPolicyConstants#OFF_BECAUSE_OF_USER} or
+ * {@link WindowManagerPolicyConstants#OFF_BECAUSE_OF_TIMEOUT}.
*/
- public void onStartedGoingToSleep(int why) {
- if (DEBUG) Log.d(TAG, "onStartedGoingToSleep(" + why + ")");
+ public void onStartedGoingToSleep(@WindowManagerPolicyConstants.OffReason int offReason) {
+ if (DEBUG) Log.d(TAG, "onStartedGoingToSleep(" + offReason + ")");
synchronized (this) {
mDeviceInteractive = false;
mGoingToSleep = true;
@@ -900,8 +907,11 @@
}
} else if (mShowing) {
mPendingReset = true;
- } else if ((why == WindowManagerPolicyConstants.OFF_BECAUSE_OF_TIMEOUT && timeout > 0)
- || (why == WindowManagerPolicyConstants.OFF_BECAUSE_OF_USER && !lockImmediately)) {
+ } else if (
+ (offReason == WindowManagerPolicyConstants.OFF_BECAUSE_OF_TIMEOUT
+ && timeout > 0)
+ || (offReason == WindowManagerPolicyConstants.OFF_BECAUSE_OF_USER
+ && !lockImmediately)) {
doKeyguardLaterLocked(timeout);
mLockLater = true;
} else if (!mLockPatternUtils.isLockScreenDisabled(currentUser)) {
@@ -912,16 +922,23 @@
playSounds(true);
}
}
- mUpdateMonitor.dispatchStartedGoingToSleep(why);
+ mUpdateMonitor.dispatchStartedGoingToSleep(offReason);
notifyStartedGoingToSleep();
}
- public void onFinishedGoingToSleep(int why, boolean cameraGestureTriggered) {
- if (DEBUG) Log.d(TAG, "onFinishedGoingToSleep(" + why + ")");
+ /**
+ * Called to let us know the screen finished turning off.
+ * @param offReason either {@link WindowManagerPolicyConstants#OFF_BECAUSE_OF_USER} or
+ * {@link WindowManagerPolicyConstants#OFF_BECAUSE_OF_TIMEOUT}.
+ */
+ public void onFinishedGoingToSleep(
+ @WindowManagerPolicyConstants.OffReason int offReason, boolean cameraGestureTriggered) {
+ if (DEBUG) Log.d(TAG, "onFinishedGoingToSleep(" + offReason + ")");
synchronized (this) {
mDeviceInteractive = false;
mGoingToSleep = false;
mWakeAndUnlocking = false;
+ mAnimatingScreenOff = mDozeParameters.shouldControlUnlockedScreenOff();
resetKeyguardDonePendingLocked();
mHideAnimationRun = false;
@@ -957,7 +974,7 @@
}
}
- mUpdateMonitor.dispatchFinishedGoingToSleep(why);
+ mUpdateMonitor.dispatchFinishedGoingToSleep(offReason);
}
private boolean isKeyguardServiceEnabled() {
@@ -1074,6 +1091,7 @@
// TODO: Rename all screen off/on references to interactive/sleeping
synchronized (this) {
mDeviceInteractive = true;
+ mAnimatingScreenOff = false;
cancelDoKeyguardLaterLocked();
cancelDoKeyguardForChildProfilesLocked();
if (DEBUG) Log.d(TAG, "onStartedWakingUp, seq = " + mDelayedShowingSequence);
@@ -1287,6 +1305,10 @@
return mHiding;
}
+ public boolean isAnimatingScreenOff() {
+ return mAnimatingScreenOff;
+ }
+
/**
* Handles SET_OCCLUDED message sent by setOccluded()
*/
@@ -2259,6 +2281,16 @@
setShowingLocked(mShowing);
}
+ @Override
+ public void onDozeAmountChanged(float linear, float interpolated) {
+ // If we were animating the screen off, and we've completed the doze animation (doze amount
+ // is 1f), then show the activity lock screen.
+ if (mAnimatingScreenOff && mDozing && linear == 1f) {
+ mAnimatingScreenOff = false;
+ setShowingLocked(mShowing);
+ }
+ }
+
/**
* @param pulsing true when device temporarily wakes up to display an incoming notification.
*/
@@ -2289,7 +2321,14 @@
mAodShowing = aodShowing;
if (notifyDefaultDisplayCallbacks) {
notifyDefaultDisplayCallbacks(showing);
- updateActivityLockScreenState(showing, aodShowing);
+
+ if (!showing || !mAnimatingScreenOff) {
+ // Update the activity lock screen state unless we're animating in the keyguard
+ // for a screen off animation. In that case, we want the activity to remain visible
+ // until the animation completes. setShowingLocked is called again when the
+ // animation ends, so the activity lock screen will be shown at that time.
+ updateActivityLockScreenState(showing, aodShowing);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java b/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java
index 5161deb..de00d50 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java
@@ -17,6 +17,7 @@
package com.android.systemui.keyguard;
import android.annotation.IntDef;
+import android.os.PowerManager;
import android.os.Trace;
import com.android.systemui.Dumpable;
@@ -51,6 +52,9 @@
public static final int WAKEFULNESS_GOING_TO_SLEEP = 3;
private int mWakefulness = WAKEFULNESS_ASLEEP;
+ private @PowerManager.WakeReason int mLastWakeReason = PowerManager.WAKE_REASON_UNKNOWN;
+ private @PowerManager.GoToSleepReason int mLastSleepReason =
+ PowerManager.GO_TO_SLEEP_REASON_MIN;
@Inject
public WakefulnessLifecycle() {
@@ -60,11 +64,27 @@
return mWakefulness;
}
- public void dispatchStartedWakingUp() {
+ /**
+ * Returns the most recent reason the device woke up. This is one of PowerManager.WAKE_REASON_*.
+ */
+ public @PowerManager.WakeReason int getLastWakeReason() {
+ return mLastWakeReason;
+ }
+
+ /**
+ * Returns the most recent reason the device went to sleep up. This is one of
+ * PowerManager.GO_TO_SLEEP_REASON_*.
+ */
+ public @PowerManager.GoToSleepReason int getLastSleepReason() {
+ return mLastSleepReason;
+ }
+
+ public void dispatchStartedWakingUp(@PowerManager.WakeReason int pmWakeReason) {
if (getWakefulness() == WAKEFULNESS_WAKING) {
return;
}
setWakefulness(WAKEFULNESS_WAKING);
+ mLastWakeReason = pmWakeReason;
dispatch(Observer::onStartedWakingUp);
}
@@ -76,11 +96,12 @@
dispatch(Observer::onFinishedWakingUp);
}
- public void dispatchStartedGoingToSleep() {
+ public void dispatchStartedGoingToSleep(@PowerManager.GoToSleepReason int pmSleepReason) {
if (getWakefulness() == WAKEFULNESS_GOING_TO_SLEEP) {
return;
}
setWakefulness(WAKEFULNESS_GOING_TO_SLEEP);
+ mLastSleepReason = pmSleepReason;
dispatch(Observer::onStartedGoingToSleep);
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index 626abfc..76281d8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -43,6 +43,7 @@
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.KeyguardLiftController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.util.DeviceConfigProxy;
@@ -82,7 +83,9 @@
@UiBackground Executor uiBgExecutor,
DeviceConfigProxy deviceConfig,
NavigationModeController navigationModeController,
- KeyguardDisplayManager keyguardDisplayManager) {
+ KeyguardDisplayManager keyguardDisplayManager,
+ DozeParameters dozeParameters,
+ StatusBarStateController statusBarStateController) {
return new KeyguardViewMediator(
context,
falsingCollector,
@@ -97,7 +100,9 @@
trustManager,
deviceConfig,
navigationModeController,
- keyguardDisplayManager
+ keyguardDisplayManager,
+ dozeParameters,
+ statusBarStateController
);
}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
index b2c2aa3..1e04516 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
@@ -46,7 +46,7 @@
class PrivacyItemController @Inject constructor(
private val appOpsController: AppOpsController,
@Main uiExecutor: DelayableExecutor,
- @Background private val bgExecutor: Executor,
+ @Background private val bgExecutor: DelayableExecutor,
private val deviceConfigProxy: DeviceConfigProxy,
private val userTracker: UserTracker,
private val logger: PrivacyLogger,
@@ -75,6 +75,7 @@
private const val DEFAULT_ALL_INDICATORS = false
private const val DEFAULT_MIC_CAMERA = true
private const val DEFAULT_LOCATION = false
+ const val TIME_TO_HOLD_INDICATORS = 5000L
}
@VisibleForTesting
@@ -87,9 +88,9 @@
ALL_INDICATORS, DEFAULT_ALL_INDICATORS)
}
- // TODO(b/168209929) Remove hardcode
private fun isMicCameraEnabled(): Boolean {
- return true
+ return deviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
+ MIC_CAMERA, DEFAULT_MIC_CAMERA)
}
private fun isLocationEnabled(): Boolean {
@@ -101,6 +102,8 @@
private var listening = false
private val callbacks = mutableListOf<WeakReference<Callback>>()
private val internalUiExecutor = MyExecutor(uiExecutor)
+ private var holdingIndicators = false
+ private var holdIndicatorsCancelled: Runnable? = null
private val notifyChanges = Runnable {
val list = privacyList
@@ -112,6 +115,11 @@
uiExecutor.execute(notifyChanges)
}
+ private val stopHoldingAndNotifyChanges = Runnable {
+ updatePrivacyList(true)
+ uiExecutor.execute(notifyChanges)
+ }
+
var allIndicatorsAvailable = isAllIndicatorsEnabled()
private set
var micCameraAvailable = isMicCameraEnabled()
@@ -132,11 +140,12 @@
DEFAULT_ALL_INDICATORS)
callbacks.forEach { it.get()?.onFlagAllChanged(allIndicatorsAvailable) }
}
- // TODO(b/168209929) Uncomment
-// if (properties.keyset.contains(MIC_CAMERA)) {
-// micCameraAvailable = properties.getBoolean(MIC_CAMERA, DEFAULT_MIC_CAMERA)
-// callbacks.forEach { it.get()?.onFlagMicCameraChanged(micCameraAvailable) }
-// }
+
+ if (properties.keyset.contains(MIC_CAMERA)) {
+ micCameraAvailable = properties.getBoolean(MIC_CAMERA, DEFAULT_MIC_CAMERA)
+ callbacks.forEach { it.get()?.onFlagMicCameraChanged(micCameraAvailable) }
+ }
+
if (properties.keyset.contains(LOCATION)) {
locationAvailable = properties.getBoolean(LOCATION, DEFAULT_LOCATION)
callbacks.forEach { it.get()?.onFlagLocationChanged(locationAvailable) }
@@ -193,6 +202,14 @@
userTracker.addCallback(userTrackerCallback, bgExecutor)
}
+ private fun setHoldTimer() {
+ holdIndicatorsCancelled?.run()
+ holdingIndicators = true
+ holdIndicatorsCancelled = bgExecutor.executeDelayed({
+ stopHoldingAndNotifyChanges.run()
+ }, TIME_TO_HOLD_INDICATORS)
+ }
+
private fun update(updateUsers: Boolean) {
bgExecutor.execute {
if (updateUsers) {
@@ -257,9 +274,14 @@
removeCallback(WeakReference(callback))
}
- private fun updatePrivacyList() {
+ private fun updatePrivacyList(stopHolding: Boolean = false) {
if (!listening) {
privacyList = emptyList()
+ if (holdingIndicators) {
+ holdIndicatorsCancelled?.run()
+ logger.cancelIndicatorsHold()
+ holdingIndicators = false
+ }
return
}
val list = appOpsController.getActiveAppOpsForUser(UserHandle.USER_ALL).filter {
@@ -267,9 +289,43 @@
it.code == AppOpsManager.OP_PHONE_CALL_MICROPHONE ||
it.code == AppOpsManager.OP_PHONE_CALL_CAMERA
}.mapNotNull { toPrivacyItem(it) }.distinct()
- logger.logUpdatedPrivacyItemsList(
- list.joinToString(separator = ", ", transform = PrivacyItem::toLog))
- privacyList = list
+ processNewList(list, stopHolding)
+ }
+
+ /**
+ * The controller will only go from indicators to no indicators (and notify its listeners), if
+ * [TIME_TO_HOLD_INDICATORS] has passed since it received an empty list from [AppOpsController].
+ *
+ * If holding the last list (in the [TIME_TO_HOLD_INDICATORS] period) and a new non-empty list
+ * is retrieved from [AppOpsController], it will stop holding and notify about the new list.
+ */
+ private fun processNewList(list: List<PrivacyItem>, stopHolding: Boolean) {
+ if (list.isNotEmpty()) {
+ // The new elements is not empty, so regardless of whether we are holding or not, we
+ // clear the holding flag and cancel the delayed runnable.
+ if (holdingIndicators) {
+ holdIndicatorsCancelled?.run()
+ logger.cancelIndicatorsHold()
+ holdingIndicators = false
+ }
+ logger.logUpdatedPrivacyItemsList(
+ list.joinToString(separator = ", ", transform = PrivacyItem::toLog))
+ privacyList = list
+ } else if (holdingIndicators && stopHolding) {
+ // We are holding indicators, received an empty list and were told to stop holding.
+ logger.finishIndicatorsHold()
+ logger.logUpdatedPrivacyItemsList("")
+ holdingIndicators = false
+ privacyList = list
+ } else if (holdingIndicators && !stopHolding) {
+ // Empty list while we are holding. Ignore
+ } else if (!holdingIndicators && privacyList.isNotEmpty()) {
+ // We are not holding, we were showing some indicators but now we should show nothing.
+ // Start holding.
+ logger.startIndicatorsHold(TIME_TO_HOLD_INDICATORS)
+ setHoldTimer()
+ }
+ // Else. We are not holding, we were not showing anything and the new list is empty. Ignore.
}
private fun toPrivacyItem(appOpItem: AppOpItem): PrivacyItem? {
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt b/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt
index c88676e..f3b8d2e 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt
@@ -47,6 +47,26 @@
})
}
+ fun startIndicatorsHold(time: Long) {
+ log(LogLevel.DEBUG, {
+ int1 = time.toInt() / 1000
+ }, {
+ "Starting privacy indicators hold for $int1 seconds"
+ })
+ }
+
+ fun cancelIndicatorsHold() {
+ log(LogLevel.VERBOSE, {}, {
+ "Cancel privacy indicators hold"
+ })
+ }
+
+ fun finishIndicatorsHold() {
+ log(LogLevel.DEBUG, {}, {
+ "Finish privacy indicators hold"
+ })
+ }
+
fun logCurrentProfilesChanged(profiles: List<Int>) {
log(LogLevel.INFO, {
str1 = profiles.toString()
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index 16e9590..e8976d3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -67,6 +67,7 @@
private int mSideMargins;
private boolean mQsDisabled;
+ private boolean mBackgroundVisible;
private int mContentPadding = -1;
private boolean mAnimateBottomOnNextLayout;
@@ -122,6 +123,14 @@
return true;
}
+ /**
+ * If QS should have a solid or transparent background.
+ */
+ public void setBackgroundVisible(boolean visible) {
+ mBackgroundVisible = visible;
+ updateBackgroundVisibility();
+ }
+
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// QSPanel will show as many rows as it can (up to TileLayout.MAX_ROWS) such that the
@@ -174,7 +183,11 @@
final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0;
if (disabled == mQsDisabled) return;
mQsDisabled = disabled;
- mBackground.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
+ updateBackgroundVisibility();
+ }
+
+ private void updateBackgroundVisibility() {
+ mBackground.setVisibility(mQsDisabled || !mBackgroundVisible ? GONE : VISIBLE);
}
void updateResources(QSPanelController qsPanelController,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index dbdd04a..ed308ae 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -44,6 +44,7 @@
import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.dagger.QSFragmentComponent;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
@@ -105,6 +106,7 @@
private QSPanelController mQSPanelController;
private QuickQSPanelController mQuickQSPanelController;
private QSCustomizerController mQSCustomizerController;
+ private FeatureFlags mFeatureFlags;
@Inject
public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler,
@@ -112,7 +114,7 @@
StatusBarStateController statusBarStateController, CommandQueue commandQueue,
QSDetailDisplayer qsDetailDisplayer, @Named(QS_PANEL) MediaHost qsMediaHost,
@Named(QUICK_QS_PANEL) MediaHost qqsMediaHost,
- QSFragmentComponent.Factory qsComponentFactory) {
+ QSFragmentComponent.Factory qsComponentFactory, FeatureFlags featureFlags) {
mRemoteInputQuickSettingsDisabler = remoteInputQsDisabler;
mInjectionInflater = injectionInflater;
mCommandQueue = commandQueue;
@@ -122,6 +124,7 @@
mQsComponentFactory = qsComponentFactory;
commandQueue.observe(getLifecycle(), this);
mHost = qsTileHost;
+ mFeatureFlags = featureFlags;
mStatusBarStateController = statusBarStateController;
}
@@ -163,6 +166,7 @@
mQSContainerImplController = qsFragmentComponent.getQSContainerImplController();
mQSContainerImplController.init();
mContainer = mQSContainerImplController.getView();
+ mContainer.setBackgroundVisible(!mFeatureFlags.isShadeOpaque());
mQSDetail.setQsPanel(mQSPanelController, mHeader, mFooter);
mQSAnimator = qsFragmentComponent.getQSAnimator();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
index 98740a2..b6e07b1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
@@ -20,7 +20,6 @@
import static com.android.systemui.DejankUtils.whitelistIpcs;
-import android.annotation.StringRes;
import android.os.Handler;
import android.os.Looper;
import android.provider.DeviceConfig;
@@ -65,7 +64,7 @@
@Override
public @DrawableRes int getIconRes() {
- return R.drawable.ic_camera_blocked;
+ return com.android.internal.R.drawable.ic_camera_blocked;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index a6c3221..1dddc45 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -274,7 +274,8 @@
NetworkController.IconState qsIcon, boolean activityIn, boolean activityOut,
String description, boolean isTransient, String statusLabel) {
// statusIcon.visible has the connected status information
- boolean enabledAndConnected = enabled && qsIcon.visible;
+ boolean enabledAndConnected =
+ enabled && (qsIcon == null ? false : qsIcon.visible);
if (enabledAndConnected != mWifiConnected) {
mWifiConnected = enabledAndConnected;
// Hotspot is not connected, so changes here should update
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
index 8cc0d7b..9cc6f09 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
@@ -63,7 +63,7 @@
@Override
public @DrawableRes int getIconRes() {
- return R.drawable.ic_mic_blocked;
+ return com.android.internal.R.drawable.ic_mic_blocked;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
index f77431a..8fc2830 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
@@ -35,6 +35,8 @@
import androidx.concurrent.futures.CallbackToFutureAdapter;
import androidx.exifinterface.media.ExifInterface;
+import com.android.internal.annotations.VisibleForTesting;
+
import com.google.common.util.concurrent.ListenableFuture;
import java.io.File;
@@ -45,6 +47,7 @@
import java.time.Instant;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
+import java.util.UUID;
import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -72,7 +75,7 @@
private static final String EXIF_WRITE_EXCEPTION =
"ExifInterface threw an exception writing to the file descriptor.";
private static final String RESOLVER_UPDATE_ZERO_ROWS =
- "Failed to publishEntry. ContentResolver#update reported no rows updated.";
+ "Failed to publish entry. ContentResolver#update reported no rows updated.";
private static final String IMAGE_COMPRESS_RETURNED_FALSE =
"Bitmap.compress returned false. (Failure unknown)";
@@ -114,8 +117,8 @@
*
* @return a listenable future result
*/
- ListenableFuture<Uri> export(Executor executor, Bitmap bitmap) {
- return export(executor, bitmap, ZonedDateTime.now());
+ ListenableFuture<Result> export(Executor executor, UUID requestId, Bitmap bitmap) {
+ return export(executor, requestId, bitmap, ZonedDateTime.now());
}
/**
@@ -126,8 +129,10 @@
*
* @return a listenable future result
*/
- ListenableFuture<Uri> export(Executor executor, Bitmap bitmap, ZonedDateTime captureTime) {
- final Task task = new Task(mResolver, bitmap, captureTime, mCompressFormat, mQuality);
+ ListenableFuture<Result> export(Executor executor, UUID requestId, Bitmap bitmap,
+ ZonedDateTime captureTime) {
+ final Task task =
+ new Task(mResolver, requestId, bitmap, captureTime, mCompressFormat, mQuality);
return CallbackToFutureAdapter.getFuture(
(completer) -> {
executor.execute(() -> {
@@ -142,42 +147,62 @@
);
}
+ static class Result {
+ UUID requestId;
+ String fileName;
+ long timestamp;
+ Uri uri;
+ CompressFormat format;
+ }
+
private static class Task {
private final ContentResolver mResolver;
+ private final UUID mRequestId;
+ private final Bitmap mBitmap;
private final ZonedDateTime mCaptureTime;
private final CompressFormat mFormat;
private final int mQuality;
- private final Bitmap mBitmap;
+ private final String mFileName;
- Task(ContentResolver resolver, Bitmap bitmap, ZonedDateTime captureTime,
+ Task(ContentResolver resolver, UUID requestId, Bitmap bitmap, ZonedDateTime captureTime,
CompressFormat format, int quality) {
mResolver = resolver;
+ mRequestId = requestId;
mBitmap = bitmap;
mCaptureTime = captureTime;
mFormat = format;
mQuality = quality;
+ mFileName = createFilename(mCaptureTime, mFormat);
}
- public Uri execute() throws ImageExportException, InterruptedException {
+ public Result execute() throws ImageExportException, InterruptedException {
Trace.beginSection("ImageExporter_execute");
Uri uri = null;
Instant start = null;
+ Result result = new Result();
try {
if (LogConfig.DEBUG_STORAGE) {
Log.d(TAG, "image export started");
start = Instant.now();
}
- uri = createEntry(mFormat, mCaptureTime);
+
+ uri = createEntry(mFormat, mCaptureTime, mFileName);
throwIfInterrupted();
writeImage(mBitmap, mFormat, mQuality, uri);
throwIfInterrupted();
- writeExif(uri, mBitmap.getWidth(), mBitmap.getHeight(), mCaptureTime);
+ writeExif(uri, mRequestId, mBitmap.getWidth(), mBitmap.getHeight(), mCaptureTime);
throwIfInterrupted();
publishEntry(uri);
+ result.timestamp = mCaptureTime.toInstant().toEpochMilli();
+ result.requestId = mRequestId;
+ result.uri = uri;
+ result.fileName = mFileName;
+ result.format = mFormat;
+
if (LogConfig.DEBUG_STORAGE) {
Log.d(TAG, "image export completed: "
+ Duration.between(start, Instant.now()).toMillis() + " ms");
@@ -190,13 +215,15 @@
} finally {
Trace.endSection();
}
- return uri;
+ return result;
}
- Uri createEntry(CompressFormat format, ZonedDateTime time) throws ImageExportException {
+ Uri createEntry(CompressFormat format, ZonedDateTime time, String fileName)
+ throws ImageExportException {
Trace.beginSection("ImageExporter_createEntry");
try {
- final ContentValues values = createMetadata(time, format);
+ final ContentValues values = createMetadata(time, format, fileName);
+
Uri uri = mResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
if (uri == null) {
throw new ImageExportException(RESOLVER_INSERT_RETURNED_NULL);
@@ -225,7 +252,7 @@
}
}
- void writeExif(Uri uri, int width, int height, ZonedDateTime captureTime)
+ void writeExif(Uri uri, UUID requestId, int width, int height, ZonedDateTime captureTime)
throws ImageExportException {
Trace.beginSection("ImageExporter_writeExif");
ParcelFileDescriptor pfd = null;
@@ -241,7 +268,7 @@
throw new ImageExportException(EXIF_READ_EXCEPTION, e);
}
- updateExifAttributes(exif, width, height, captureTime);
+ updateExifAttributes(exif, requestId, width, height, captureTime);
try {
exif.saveAttributes();
} catch (IOException e) {
@@ -276,14 +303,16 @@
}
}
+ @VisibleForTesting
static String createFilename(ZonedDateTime time, CompressFormat format) {
return String.format(FILENAME_PATTERN, time, fileExtension(format));
}
- static ContentValues createMetadata(ZonedDateTime captureTime, CompressFormat format) {
+ static ContentValues createMetadata(ZonedDateTime captureTime, CompressFormat format,
+ String fileName) {
ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.RELATIVE_PATH, SCREENSHOTS_PATH);
- values.put(MediaStore.MediaColumns.DISPLAY_NAME, createFilename(captureTime, format));
+ values.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName);
values.put(MediaStore.MediaColumns.MIME_TYPE, getMimeType(format));
values.put(MediaStore.MediaColumns.DATE_ADDED, captureTime.toEpochSecond());
values.put(MediaStore.MediaColumns.DATE_MODIFIED, captureTime.toEpochSecond());
@@ -293,8 +322,10 @@
return values;
}
- static void updateExifAttributes(ExifInterface exif, int width, int height,
+ static void updateExifAttributes(ExifInterface exif, UUID uniqueId, int width, int height,
ZonedDateTime captureTime) {
+ exif.setAttribute(ExifInterface.TAG_IMAGE_UNIQUE_ID, uniqueId.toString());
+
exif.setAttribute(ExifInterface.TAG_SOFTWARE, "Android " + Build.DISPLAY);
exif.setAttribute(ExifInterface.TAG_IMAGE_WIDTH, Integer.toString(width));
exif.setAttribute(ExifInterface.TAG_IMAGE_LENGTH, Integer.toString(height));
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
index 9dce191..0106f43 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
@@ -29,6 +29,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.Icon;
@@ -49,8 +50,9 @@
import com.android.systemui.SystemUIFactory;
import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ActionTransition;
+import com.google.common.util.concurrent.ListenableFuture;
+
import java.text.DateFormat;
-import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@@ -65,7 +67,6 @@
class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
private static final String TAG = logTag(SaveImageInBackgroundTask.class);
- private static final String SCREENSHOT_FILE_NAME_TEMPLATE = "Screenshot_%s.png";
private static final String SCREENSHOT_ID_TEMPLATE = "Screenshot_%s";
private static final String SCREENSHOT_SHARE_SUBJECT_TEMPLATE = "Screenshot (%s)";
@@ -73,14 +74,14 @@
private final ScreenshotSmartActions mScreenshotSmartActions;
private final ScreenshotController.SaveImageInBackgroundData mParams;
private final ScreenshotController.SavedImageData mImageData;
- private final String mImageFileName;
- private final long mImageTime;
+
private final ScreenshotNotificationSmartActionsProvider mSmartActionsProvider;
- private final String mScreenshotId;
+ private String mScreenshotId;
private final boolean mSmartActionsEnabled;
private final Random mRandom = new Random();
private final Supplier<ActionTransition> mSharedElementTransition;
private final ImageExporter mImageExporter;
+ private long mImageTime;
SaveImageInBackgroundTask(Context context, ImageExporter exporter,
ScreenshotSmartActions screenshotSmartActions,
@@ -94,10 +95,6 @@
// Prepare all the output metadata
mParams = data;
- mImageTime = System.currentTimeMillis();
- String imageDate = new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date(mImageTime));
- mImageFileName = String.format(SCREENSHOT_FILE_NAME_TEMPLATE, imageDate);
- mScreenshotId = String.format(SCREENSHOT_ID_TEMPLATE, UUID.randomUUID());
// Initialize screenshot notification smart actions provider.
mSmartActionsEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
@@ -121,18 +118,26 @@
}
return null;
}
+ // TODO: move to constructor / from ScreenshotRequest
+ final UUID requestId = UUID.randomUUID();
+ final UserHandle user = getUserHandleOfForegroundApplication(mContext);
+
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
Bitmap image = mParams.image;
-
+ mScreenshotId = String.format(SCREENSHOT_ID_TEMPLATE, requestId);
try {
// Call synchronously here since already on a background thread.
- Uri uri = mImageExporter.export(Runnable::run, image).get();
+ ListenableFuture<ImageExporter.Result> future =
+ mImageExporter.export(Runnable::run, requestId, image);
+ ImageExporter.Result result = future.get();
+ final Uri uri = result.uri;
+ mImageTime = result.timestamp;
CompletableFuture<List<Notification.Action>> smartActionsFuture =
mScreenshotSmartActions.getSmartActionsFuture(
mScreenshotId, uri, image, mSmartActionsProvider,
- mSmartActionsEnabled, getUserHandle(mContext));
+ mSmartActionsEnabled, user);
List<Notification.Action> smartActions = new ArrayList<>();
if (mSmartActionsEnabled) {
@@ -336,22 +341,21 @@
return deleteActionBuilder.build();
}
- private int getUserHandleOfForegroundApplication(Context context) {
+ private UserHandle getUserHandleOfForegroundApplication(Context context) {
+ UserManager manager = UserManager.get(context);
+ int result;
// This logic matches
// com.android.systemui.statusbar.phone.PhoneStatusBarPolicy#updateManagedProfile
try {
- return ActivityTaskManager.getService().getLastResumedActivityUserId();
+ result = ActivityTaskManager.getService().getLastResumedActivityUserId();
} catch (RemoteException e) {
if (DEBUG_ACTIONS) {
Log.d(TAG, "Failed to get UserHandle of foreground app: ", e);
}
- return context.getUserId();
+ result = context.getUserId();
}
- }
-
- private UserHandle getUserHandle(Context context) {
- UserManager manager = UserManager.get(context);
- return manager.getUserInfo(getUserHandleOfForegroundApplication(context)).getUserHandle();
+ UserInfo userInfo = manager.getUserInfo(result);
+ return userInfo.getUserHandle();
}
private List<Notification.Action> buildSmartActions(
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index d77d1ea..8801b25 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -55,6 +55,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.util.DisplayMetrics;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
index c75efbc..54b1b2c 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
@@ -29,6 +29,8 @@
import com.google.common.util.concurrent.ListenableFuture;
+import java.time.ZonedDateTime;
+import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -52,6 +54,9 @@
private final ImageExporter mImageExporter;
private final ImageTileSet mImageTileSet;
+ private ZonedDateTime mCaptureTime;
+ private UUID mRequestId;
+
public ScrollCaptureController(Context context, Connection connection, Executor uiExecutor,
Executor bgExecutor, ImageExporter exporter) {
mContext = context;
@@ -68,6 +73,8 @@
* @param after action to take after the flow is complete
*/
public void run(final Runnable after) {
+ mCaptureTime = ZonedDateTime.now();
+ mRequestId = UUID.randomUUID();
mConnection.start((session) -> startCapture(session, after));
}
@@ -109,11 +116,12 @@
void exportToFile(Bitmap bitmap, Session session, Runnable afterEnd) {
mImageExporter.setFormat(Bitmap.CompressFormat.PNG);
mImageExporter.setQuality(6);
- ListenableFuture<Uri> future =
- mImageExporter.export(mBgExecutor, bitmap);
+ ListenableFuture<ImageExporter.Result> future =
+ mImageExporter.export(mBgExecutor, mRequestId, bitmap, mCaptureTime);
future.addListener(() -> {
try {
- launchViewer(future.get());
+ ImageExporter.Result result = future.get();
+ launchViewer(result.uri);
} catch (InterruptedException | ExecutionException e) {
Toast.makeText(mContext, "Failed to write image", Toast.LENGTH_SHORT).show();
Log.e(TAG, "Error storing screenshot to media store", e.getCause());
diff --git a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt
new file mode 100644
index 0000000..c1161f1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt
@@ -0,0 +1,123 @@
+/*
+ * 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
+
+import android.app.AppOpsManager
+import android.content.DialogInterface
+import android.content.Intent.EXTRA_PACKAGE_NAME
+import android.content.pm.PackageManager
+import android.content.res.Resources
+import android.hardware.SensorPrivacyManager
+import android.hardware.SensorPrivacyManager.*
+import android.os.Bundle
+import android.text.Html
+import com.android.internal.app.AlertActivity
+import com.android.systemui.R
+
+/**
+ * Dialog to be shown on top of apps that are attempting to use a sensor (e.g. microphone) which is
+ * currently in "sensor privacy mode", aka. muted.
+ *
+ * <p>The dialog is started for the user the app is running for which might be a secondary users.
+ */
+class SensorUseStartedActivity : AlertActivity(), DialogInterface.OnClickListener {
+ private var sensor = -1
+ private lateinit var sensorUsePackageName: String
+
+ private lateinit var sensorPrivacyManager: SensorPrivacyManager
+ private lateinit var appOpsManager: AppOpsManager
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ setResult(RESULT_CANCELED)
+ sensorPrivacyManager = getSystemService(SensorPrivacyManager::class.java)!!
+ appOpsManager = getSystemService(AppOpsManager::class.java)!!
+
+ sensorUsePackageName = intent.getStringExtra(EXTRA_PACKAGE_NAME) ?: return
+ sensor = intent.getIntExtra(EXTRA_SENSOR, -1).also {
+ if (it == -1) {
+ finish()
+ return
+ }
+ }
+
+ sensorPrivacyManager.addSensorPrivacyListener(sensor) { isBlocked ->
+ if (!isBlocked) {
+ dismiss()
+ }
+ }
+ if (!sensorPrivacyManager.isIndividualSensorPrivacyEnabled(sensor)) {
+ finish()
+ return
+ }
+
+ mAlertParams.apply {
+ try {
+ mMessage = Html.fromHtml(getString(when (sensor) {
+ INDIVIDUAL_SENSOR_MICROPHONE ->
+ R.string.sensor_privacy_start_use_mic_dialog_content
+ INDIVIDUAL_SENSOR_CAMERA ->
+ R.string.sensor_privacy_start_use_camera_dialog_content
+ else -> Resources.ID_NULL
+ }, packageManager.getApplicationInfo(sensorUsePackageName, 0)
+ .loadLabel(packageManager)), 0)
+ } catch (e: PackageManager.NameNotFoundException) {
+ finish()
+ return
+ }
+
+ mIconId = when (sensor) {
+ INDIVIDUAL_SENSOR_MICROPHONE ->
+ com.android.internal.R.drawable.perm_group_microphone
+ INDIVIDUAL_SENSOR_CAMERA -> com.android.internal.R.drawable.perm_group_camera
+ else -> Resources.ID_NULL
+ }
+
+ mPositiveButtonText = getString(
+ com.android.internal.R.string.sensor_privacy_start_use_dialog_turn_on_button)
+ mNegativeButtonText = getString(android.R.string.cancel)
+ mPositiveButtonListener = this@SensorUseStartedActivity
+ mNegativeButtonListener = this@SensorUseStartedActivity
+ }
+
+ setupAlert()
+ }
+
+ override fun onStart() {
+ super.onStart()
+
+ sensorPrivacyManager.suppressIndividualSensorPrivacyReminders(sensorUsePackageName, true)
+ }
+
+ override fun onClick(dialog: DialogInterface?, which: Int) {
+ when (which) {
+ BUTTON_POSITIVE -> {
+ sensorPrivacyManager.setIndividualSensorPrivacyForProfileGroup(sensor, false)
+ setResult(RESULT_OK)
+ }
+ }
+
+ dismiss()
+ }
+
+ override fun onStop() {
+ super.onDestroy()
+
+ sensorPrivacyManager.suppressIndividualSensorPrivacyReminders(sensorUsePackageName, false)
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
index 964c499..d6db736 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
@@ -44,6 +44,10 @@
return mFlagReader.isEnabled(R.bool.flag_notification_pipeline2_rendering);
}
+ public boolean isShadeOpaque() {
+ return mFlagReader.isEnabled(R.bool.flag_shade_is_opaque);
+ }
+
/** b/171917882 */
public boolean isTwoColumnNotificationShadeEnabled() {
return mFlagReader.isEnabled(R.bool.flag_notification_twocolumn);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 5259aa9..c816784 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -855,5 +855,13 @@
updateIndication(false);
}
}
+
+ @Override
+ public void onRequireUnlockForNfc() {
+ showTransientIndication(mContext.getString(R.string.require_unlock_for_nfc),
+ false /* isError */, false /* hideOnScreenOff */);
+ hideTransientIndicationDelayed(HIDE_DELAY_MS);
+ }
+
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
index 86377fb..2f0f90d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
@@ -86,6 +86,35 @@
}
}
+class PowerButtonReveal(
+ /** Approximate Y-value of the center of the power button on the physical device. */
+ val powerButtonY: Float
+) : LightRevealEffect {
+
+ private val OVAL_INITIAL_HEIGHT = 50f
+
+ private val WIDTH_INCREASE_MULTIPLIER = 1.25f
+
+ override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) {
+ val interpolatedAmount = Interpolators.FAST_OUT_SLOW_IN_REVERSE.getInterpolation(amount)
+ val fadeAmount =
+ LightRevealEffect.getPercentPastThreshold(interpolatedAmount, 0.5f)
+
+ with(scrim) {
+ revealGradientEndColorAlpha = 1f - fadeAmount
+ setRevealGradientBounds(
+ width -
+ width * WIDTH_INCREASE_MULTIPLIER * interpolatedAmount,
+ powerButtonY - (OVAL_INITIAL_HEIGHT / 2f) -
+ height * interpolatedAmount,
+ width * WIDTH_INCREASE_MULTIPLIER +
+ width * WIDTH_INCREASE_MULTIPLIER * interpolatedAmount,
+ powerButtonY + (OVAL_INITIAL_HEIGHT / 2f) +
+ height * interpolatedAmount)
+ }
+ }
+}
+
/**
* Scrim view that partially reveals the content underneath it using a [RadialGradient] with a
* transparent center. The center position, size, and stops of the gradient can be manipulated to
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 20efa32..4a80572 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -205,6 +205,30 @@
}
/**
+ * @return whether to clip bottom of given view
+ */
+ private boolean shouldClipBottom(ExpandableView view) {
+ final boolean showShelf = ((ShelfState) getViewState()).hasItemsInStableShelf;
+ if (showShelf) {
+ if (mAmbientState.isShadeOpening()) {
+ final float viewEnd = view.getTranslationY()
+ + view.getActualHeight()
+ + mPaddingBetweenElements;
+ final float finalShelfStart = mMaxLayoutHeight - getIntrinsicHeight();
+ // While the shade is opening, only clip view if it overlaps with shelf;
+ // otherwise leave view unclipped.
+ if (viewEnd < finalShelfStart) {
+ return false;
+ }
+ }
+ // Clip for scrolling.
+ return true;
+ }
+ // Don't clip since we have enough space to show all views.
+ return false;
+ }
+
+ /**
* Update the shelf appearance based on the other notifications around it. This transforms
* the icons from the notification area into the shelf.
*/
@@ -345,7 +369,9 @@
clipTransientViews();
setClipTopAmount(clipTopAmount);
- boolean isHidden = getViewState().hidden || clipTopAmount >= getIntrinsicHeight();
+ boolean isHidden = getViewState().hidden
+ || clipTopAmount >= getIntrinsicHeight()
+ || mAmbientState.isShadeOpening();
if (mShowNotificationShelf) {
setVisibility(isHidden ? View.INVISIBLE : View.VISIBLE);
}
@@ -468,7 +494,8 @@
} else {
shouldClipOwnTop = view.showingPulsing();
}
- if (viewEnd > notificationClipEnd && !shouldClipOwnTop
+ if (shouldClipBottom(view)
+ && viewEnd > notificationClipEnd && !shouldClipOwnTop
&& (mAmbientState.isShadeExpanded() || !isPinned)) {
int clipBottomAmount = (int) (viewEnd - notificationClipEnd);
if (isPinned) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index 1326d92..e391250 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -96,6 +96,8 @@
}
}
+ private var animatingScreenOff = false
+
private var collapsedEnoughToHide: Boolean = false
var pulsing: Boolean = false
@@ -232,9 +234,14 @@
}
override fun onDozeAmountChanged(linear: Float, eased: Float) {
- if (updateDozeAmountIfBypass()) {
+ if (overrideDozeAmountIfBypass()) {
return
}
+
+ if (overrideDozeAmountIfAnimatingScreenOff(linear)) {
+ return
+ }
+
if (linear != 1.0f && linear != 0.0f &&
(mLinearDozeAmount == 0.0f || mLinearDozeAmount == 1.0f)) {
// Let's notify the scroller that an animation started
@@ -257,7 +264,7 @@
}
override fun onStateChanged(newState: Int) {
- updateDozeAmountIfBypass()
+ overrideDozeAmountIfBypass()
if (bypassController.bypassEnabled &&
newState == StatusBarState.KEYGUARD && state == StatusBarState.SHADE_LOCKED &&
(!statusBarStateController.isDozing || shouldAnimateVisibility())) {
@@ -265,6 +272,14 @@
setNotificationsVisible(visible = true, increaseSpeed = false, animate = false)
setNotificationsVisible(visible = false, increaseSpeed = false, animate = true)
}
+
+ // If we want to control the screen off animation, check whether we are going from SHADE to
+ // KEYGUARD.
+ if (dozeParameters.shouldControlUnlockedScreenOff()) {
+ animatingScreenOff =
+ state == StatusBarState.SHADE && newState == StatusBarState.KEYGUARD
+ }
+
this.state = newState
}
@@ -280,7 +295,11 @@
}
}
- private fun updateDozeAmountIfBypass(): Boolean {
+ /**
+ * @return Whether the doze amount was overridden because bypass is enabled. If true, the
+ * original doze amount should be ignored.
+ */
+ private fun overrideDozeAmountIfBypass(): Boolean {
if (bypassController.bypassEnabled) {
var amount = 1.0f
if (statusBarStateController.state == StatusBarState.SHADE ||
@@ -293,6 +312,28 @@
return false
}
+ /**
+ * If we're playing the screen off animation, force the notification doze amount to be 1f (fully
+ * dozing). This is needed so that the notifications aren't briefly visible as the screen turns
+ * off and dozeAmount goes from 1f to 0f.
+ *
+ * @return Whether the doze amount was overridden because we are playing the screen off
+ * animation. If true, the original doze amount should be ignored.
+ */
+ private fun overrideDozeAmountIfAnimatingScreenOff(linearDozeAmount: Float): Boolean {
+ if (animatingScreenOff) {
+ if (linearDozeAmount == 1f) {
+ animatingScreenOff = false
+ return false
+ }
+
+ setDozeAmount(1f, 1f)
+ return true
+ }
+
+ return false
+ }
+
private fun startVisibilityAnimation(increaseSpeed: Boolean) {
if (mNotificationVisibleAmount == 0f || mNotificationVisibleAmount == 1f) {
mVisibilityInterpolator = if (mNotificationsVisible)
@@ -345,6 +386,8 @@
override fun onDozingChanged(isDozing: Boolean) {
if (isDozing) {
setNotificationsVisible(visible = false, animate = false, increaseSpeed = false)
+ } else {
+ animatingScreenOff = false
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index 789e78e..bafa4a25 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -938,6 +938,7 @@
/** Whether or not the icon for this notification is visible in the shelf. */
public void setShelfIconVisible(boolean shelfIconVisible) {
+ if (row == null) return;
mShelfIconVisible = shelfIconVisible;
updateShelfIconVisibility();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
index c7ac403..998ae9e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
@@ -30,12 +30,8 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
-import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
import com.android.systemui.util.concurrency.DelayableExecutor;
-import java.util.HashMap;
-import java.util.Map;
-
import javax.inject.Inject;
/**
@@ -75,9 +71,6 @@
public void attach(NotifPipeline pipeline) {
mNotifPipeline = pipeline;
- // extend the lifetime of foreground notification services to show for at least 5 seconds
- mNotifPipeline.addNotificationLifetimeExtender(mForegroundLifetimeExtender);
-
// filter out foreground service notifications that aren't necessary anymore
mNotifPipeline.addPreGroupFilter(mNotifFilter);
@@ -119,64 +112,6 @@
};
/**
- * Extends the lifetime of foreground notification services such that they show for at least
- * five seconds
- */
- private final NotifLifetimeExtender mForegroundLifetimeExtender =
- new NotifLifetimeExtender() {
- private static final int MIN_FGS_TIME_MS = 5000;
- private OnEndLifetimeExtensionCallback mEndCallback;
- private Map<NotificationEntry, Runnable> mEndRunnables = new HashMap<>();
-
- @Override
- public String getName() {
- return TAG;
- }
-
- @Override
- public void setCallback(OnEndLifetimeExtensionCallback callback) {
- mEndCallback = callback;
- }
-
- @Override
- public boolean shouldExtendLifetime(NotificationEntry entry, int reason) {
- if ((entry.getSbn().getNotification().flags
- & Notification.FLAG_FOREGROUND_SERVICE) == 0) {
- return false;
- }
-
- final long currTime = System.currentTimeMillis();
- final boolean extendLife = currTime - entry.getSbn().getPostTime() < MIN_FGS_TIME_MS;
-
- if (extendLife) {
- if (!mEndRunnables.containsKey(entry)) {
- final Runnable endExtensionRunnable = () -> {
- mEndRunnables.remove(entry);
- mEndCallback.onEndLifetimeExtension(
- mForegroundLifetimeExtender,
- entry);
- };
-
- final Runnable cancelRunnable = mMainExecutor.executeDelayed(
- endExtensionRunnable,
- MIN_FGS_TIME_MS - (currTime - entry.getSbn().getPostTime()));
- mEndRunnables.put(entry, cancelRunnable);
- }
- }
-
- return extendLife;
- }
-
- @Override
- public void cancelLifetimeExtension(NotificationEntry entry) {
- Runnable cancelRunnable = mEndRunnables.remove(entry);
- if (cancelRunnable != null) {
- cancelRunnable.run();
- }
- }
- };
-
- /**
* Puts foreground service notifications into its own section.
*/
private final NotifSectioner mNotifSectioner = new NotifSectioner("ForegroundService") {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index ba03d01..92b381e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -614,6 +614,12 @@
}
}
+ public void setShouldFadeForShadeOpen(boolean shouldFade) {
+ if (!mViewState.gone) {
+ mViewState.setShouldFadeForShadeOpen(shouldFade);
+ }
+ }
+
/**
* @return whether the current view doesn't add height to the overall content. This means that
* if it is added to a list of items, its content will still have the same height.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java
index 628c4e2..21b6863 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java
@@ -88,6 +88,12 @@
public boolean hideSensitive;
public boolean belowSpeedBump;
public boolean inShelf;
+ public boolean shouldFadeForShadeOpen;
+
+ @Override
+ boolean shouldAnimateAlpha() {
+ return shouldFadeForShadeOpen;
+ }
/**
* A state indicating whether a headsup is currently fully visible, even when not scrolled.
@@ -171,6 +177,10 @@
}
}
+ public void setShouldFadeForShadeOpen(boolean shouldFade) {
+ shouldFadeForShadeOpen = shouldFade;
+ }
+
@Override
public void animateTo(View child, AnimationProperties properties) {
super.animateTo(child, properties);
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 f07d874..a2ce9e1 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
@@ -3947,6 +3947,7 @@
int numChildren = getChildCount();
for (int i = 0; i < numChildren; i++) {
ExpandableView child = (ExpandableView) getChildAt(i);
+ child.setShouldFadeForShadeOpen(mAmbientState.isShadeOpening());
child.applyViewState();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index e6efba7..4bf7be3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -568,11 +568,14 @@
// Add padding before sections for overscroll effect.
childViewState.yTranslation += ambientState.getSectionPadding();
}
- if (childViewState.yTranslation >= shelfStart) {
- childViewState.hidden = !child.isExpandAnimationRunning() && !child.hasExpandingChild();
- childViewState.inShelf = true;
- childViewState.headsUpIsVisible = false;
- }
+ boolean show = childViewState.yTranslation < shelfStart
+ && !ambientState.isAppearing();
+ childViewState.hidden = !show
+ && !child.isExpandAnimationRunning()
+ && !child.hasExpandingChild();
+ childViewState.inShelf = !show;
+ childViewState.headsUpIsVisible = show;
+ childViewState.alpha = show ? 1f : 0f;
}
protected int getMaxAllowedChildHeight(View child) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
index 66a48f1..43f1f43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
@@ -45,6 +45,7 @@
public static final int ANIMATION_DURATION_CORNER_RADIUS = 200;
public static final int ANIMATION_DURATION_WAKEUP = 500;
public static final int ANIMATION_DURATION_GO_TO_FULL_SHADE = 448;
+ public static final int ANIMATION_DURATION_FADE_IN = 700;
public static final int ANIMATION_DURATION_APPEAR_DISAPPEAR = 464;
public static final int ANIMATION_DURATION_SWIPE = 260;
public static final int ANIMATION_DURATION_DIMMED_ACTIVATED = 220;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
index 3da4e321..abe5c69 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification.stack;
+import static com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_FADE_IN;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
@@ -56,6 +58,16 @@
return mAnimationFilter;
}
};
+
+ protected static final AnimationProperties ANIMATE_ALPHA = new AnimationProperties() {
+ AnimationFilter mAnimationFilter = new AnimationFilter();
+ @Override
+ public AnimationFilter getAnimationFilter() {
+ mAnimationFilter.animateAlpha();
+ return mAnimationFilter;
+ }
+ }.setDuration(ANIMATION_DURATION_FADE_IN);
+
private static final int TAG_ANIMATOR_TRANSLATION_X = R.id.translation_x_animator_tag;
private static final int TAG_ANIMATOR_TRANSLATION_Y = R.id.translation_y_animator_tag;
private static final int TAG_ANIMATOR_TRANSLATION_Z = R.id.translation_z_animator_tag;
@@ -148,6 +160,10 @@
scaleY = view.getScaleY();
}
+ boolean shouldAnimateAlpha() {
+ return false;
+ }
+
/**
* Applies a {@link ViewState} to a normal view.
*/
@@ -200,24 +216,26 @@
int oldVisibility = view.getVisibility();
boolean becomesInvisible = this.alpha == 0.0f
|| (this.hidden && (!isAnimating(view) || oldVisibility != View.VISIBLE));
- boolean animatingAlpha = isAnimating(view, TAG_ANIMATOR_ALPHA);
- if (animatingAlpha) {
- updateAlphaAnimation(view);
+ if (isAnimating(view, TAG_ANIMATOR_ALPHA)) {
+ startAlphaAnimation(view, NO_NEW_ANIMATIONS);
} else if (view.getAlpha() != this.alpha) {
- // apply layer type
- boolean becomesFullyVisible = this.alpha == 1.0f;
- boolean newLayerTypeIsHardware = !becomesInvisible && !becomesFullyVisible
- && view.hasOverlappingRendering();
- int layerType = view.getLayerType();
- int newLayerType = newLayerTypeIsHardware
- ? View.LAYER_TYPE_HARDWARE
- : View.LAYER_TYPE_NONE;
- if (layerType != newLayerType) {
- view.setLayerType(newLayerType, null);
+ if (shouldAnimateAlpha()) {
+ startAlphaAnimation(view, ANIMATE_ALPHA);
+ } else {
+ // apply layer type
+ boolean becomesFullyVisible = this.alpha == 1.0f;
+ boolean newLayerTypeIsHardware = !becomesInvisible && !becomesFullyVisible
+ && view.hasOverlappingRendering();
+ int layerType = view.getLayerType();
+ int newLayerType = newLayerTypeIsHardware
+ ? View.LAYER_TYPE_HARDWARE
+ : View.LAYER_TYPE_NONE;
+ if (layerType != newLayerType) {
+ view.setLayerType(newLayerType, null);
+ }
+ // apply alpha
+ view.setAlpha(this.alpha);
}
-
- // apply alpha
- view.setAlpha(this.alpha);
}
// apply visibility
@@ -322,10 +340,6 @@
}
}
- private void updateAlphaAnimation(View view) {
- startAlphaAnimation(view, NO_NEW_ANIMATIONS);
- }
-
private void startAlphaAnimation(final View child, AnimationProperties properties) {
Float previousStartValue = getChildTag(child,TAG_START_ALPHA);
Float previousEndValue = getChildTag(child,TAG_END_ALPHA);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 6495144..8c2fa33 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -194,6 +194,16 @@
mPowerManager.setDozeAfterScreenOff(!controlScreenOffAnimation);
}
+ /**
+ * Whether we want to control the screen off animation when the device is unlocked. If we do,
+ * we'll animate in AOD before turning off the screen, rather than simply fading to black and
+ * then abruptly showing AOD.
+ */
+ public boolean shouldControlUnlockedScreenOff() {
+ return getAlwaysOn() && SystemProperties.getBoolean(
+ "persist.sysui.show_new_screen_on_transitions", false);
+ }
+
private boolean getBoolean(String propName, int resId) {
return SystemProperties.getBoolean(propName, mResources.getBoolean(resId));
}
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 1dfd1f3..57a64e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -196,13 +196,15 @@
}
public void run(Result result) {
- final int y = getClockY(mPanelExpansion);
+ final int y = getClockY(mPanelExpansion, mDarkAmount);
result.clockY = y;
+ result.clockYFullyDozing = getClockY(
+ 1.0f /* panelExpansion */, 1.0f /* darkAmount */);
result.clockAlpha = getClockAlpha(y);
result.stackScrollerPadding = mBypassEnabled ? mUnlockedStackScrollerPadding
: y + mKeyguardStatusHeight;
result.stackScrollerPaddingExpanded = mBypassEnabled ? mUnlockedStackScrollerPadding
- : getClockY(1.0f) + mKeyguardStatusHeight;
+ : getClockY(1.0f, mDarkAmount) + mKeyguardStatusHeight;
result.clockX = (int) interpolate(0, burnInPreventionOffsetX(), mDarkAmount);
result.clockScale = interpolate(getBurnInScale(), 1.0f, 1.0f - mDarkAmount);
}
@@ -259,7 +261,7 @@
return (int) y;
}
- private int getClockY(float panelExpansion) {
+ private int getClockY(float panelExpansion, float darkAmount) {
// Dark: Align the bottom edge of the clock at about half of the screen:
float clockYDark = (mHasCustomClock ? getPreferredClockY() : getMaxClockY())
+ burnInPreventionOffsetY();
@@ -273,7 +275,7 @@
float clockY = MathUtils.lerp(clockYBouncer, clockYRegular, shadeExpansion);
clockYDark = MathUtils.lerp(clockYBouncer, clockYDark, shadeExpansion);
- float darkAmount = mBypassEnabled && !mHasCustomClock ? 1.0f : mDarkAmount;
+ darkAmount = mBypassEnabled && !mHasCustomClock ? 1.0f : darkAmount;
if (mLockScreenMode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL) {
// This will keep the clock at the top but out of the cutout area
@@ -295,7 +297,7 @@
* @return Alpha from 0 to 1.
*/
private float getClockAlpha(int y) {
- float alphaKeyguard = Math.max(0, y / Math.max(1f, getClockY(1f)));
+ float alphaKeyguard = Math.max(0, y / Math.max(1f, getClockY(1f, mDarkAmount)));
alphaKeyguard *= (1f - mQsExpansion);
alphaKeyguard = Interpolators.ACCELERATE.getInterpolation(alphaKeyguard);
return MathUtils.lerp(alphaKeyguard, 1f, mDarkAmount);
@@ -328,6 +330,11 @@
public int clockY;
/**
+ * The y translation of the clock when we're fully dozing.
+ */
+ public int clockYFullyDozing;
+
+ /**
* The alpha value of the clock.
*/
public float clockAlpha;
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 3e09784..b24d0e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -896,9 +896,8 @@
int bottomPadding = Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding);
int clockPreferredY = mKeyguardStatusViewController.getClockPreferredY(totalHeight);
boolean bypassEnabled = mKeyguardBypassController.getBypassEnabled();
- final boolean hasVisibleNotifications = !bypassEnabled
- && (mNotificationStackScrollLayoutController.getVisibleNotificationCount() != 0
- || mMediaDataManager.hasActiveMedia());
+ final boolean hasVisibleNotifications = mNotificationStackScrollLayoutController
+ .getVisibleNotificationCount() != 0 || mMediaDataManager.hasActiveMedia();
mKeyguardStatusViewController.setHasVisibleNotifications(hasVisibleNotifications);
mClockPositionAlgorithm.setup(mStatusBarMinHeight, totalHeight - bottomPadding,
mNotificationStackScrollLayoutController.getIntrinsicContentHeight(),
@@ -3617,6 +3616,16 @@
int oldState = mBarState;
boolean keyguardShowing = statusBarState == KEYGUARD;
+ if (mDozeParameters.shouldControlUnlockedScreenOff() && isDozing() && keyguardShowing) {
+ // This means we're doing the screen off animation - position the keyguard status
+ // view where it'll be on AOD, so we can animate it in.
+ mKeyguardStatusViewController.updatePosition(
+ mClockPositionResult.clockX,
+ mClockPositionResult.clockYFullyDozing,
+ mClockPositionResult.clockScale,
+ false);
+ }
+
mKeyguardStatusViewController.setKeyguardStatusViewVisibility(
statusBarState,
keyguardFadingAway,
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 fc1811b..1463148 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -49,6 +49,7 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dock.DockManager;
import com.android.systemui.statusbar.BlurUtils;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.notification.stack.ViewState;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -125,6 +126,11 @@
*/
public static final float BUSY_SCRIM_ALPHA = 1f;
+ /**
+ * Scrim opacity that can have text on top.
+ */
+ public static final float GAR_SCRIM_ALPHA = 0.6f;
+
static final int TAG_KEY_ANIM = R.id.scrim;
private static final int TAG_START_ALPHA = R.id.scrim_alpha_start;
private static final int TAG_END_ALPHA = R.id.scrim_alpha_end;
@@ -199,10 +205,11 @@
AlarmManager alarmManager, KeyguardStateController keyguardStateController,
DelayedWakeLock.Builder delayedWakeLockBuilder, Handler handler,
KeyguardUpdateMonitor keyguardUpdateMonitor, DockManager dockManager,
- BlurUtils blurUtils, ConfigurationController configurationController) {
+ BlurUtils blurUtils, ConfigurationController configurationController,
+ FeatureFlags featureFlags) {
mScrimStateListener = lightBarController::setScrimState;
- mDefaultScrimAlpha = BUSY_SCRIM_ALPHA;
+ mDefaultScrimAlpha = featureFlags.isShadeOpaque() ? BUSY_SCRIM_ALPHA : GAR_SCRIM_ALPHA;
mBlurUtils = blurUtils;
mKeyguardStateController = keyguardStateController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 8ea173b..e07c3a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -193,6 +193,7 @@
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
+import com.android.systemui.statusbar.PowerButtonReveal;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.StatusBarState;
@@ -372,6 +373,7 @@
private boolean mWakeUpComingFromTouch;
private PointF mWakeUpTouchLocation;
private LightRevealScrim mLightRevealScrim;
+ private PowerButtonReveal mPowerButtonReveal;
private final Object mQueueLock = new Object();
@@ -1382,7 +1384,7 @@
* @param why the reason for the wake up
*/
public void wakeUpIfDozing(long time, View where, String why) {
- if (mDozing) {
+ if (mDozing && !mKeyguardViewMediator.isAnimatingScreenOff()) {
mPowerManager.wakeUp(
time, PowerManager.WAKE_REASON_GESTURE, "com.android.systemui:" + why);
mWakeUpComingFromTouch = true;
@@ -2945,6 +2947,9 @@
if (mBrightnessMirrorController != null) {
mBrightnessMirrorController.updateResources();
}
+
+ mPowerButtonReveal = new PowerButtonReveal(mContext.getResources().getDimensionPixelSize(
+ R.dimen.global_actions_top_padding));
}
// Visibility reporting
@@ -3652,6 +3657,16 @@
updateQsExpansionEnabled();
mKeyguardViewMediator.setDozing(mDozing);
+ final boolean usePowerButtonEffect =
+ (isDozing && mWakefulnessLifecycle.getLastSleepReason()
+ == PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON)
+ || (!isDozing && mWakefulnessLifecycle.getLastWakeReason()
+ == PowerManager.WAKE_REASON_POWER_BUTTON);
+
+ mLightRevealScrim.setRevealEffect(usePowerButtonEffect
+ ? mPowerButtonReveal
+ : LiftReveal.INSTANCE);
+
mNotificationsController.requestNotificationUpdate("onDozingChanged");
updateDozingState();
mDozeServiceHost.updateDozing();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
index 4cfbe69..0074dbe 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
@@ -22,6 +22,7 @@
import android.testing.AndroidTestingRunner;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -50,6 +51,8 @@
ConfigurationController mConfigurationController;
@Mock
NotificationIconAreaController mNotificationIconAreaController;
+ @Mock
+ DozeParameters mDozeParameters;
private KeyguardStatusViewController mController;
@@ -64,7 +67,8 @@
mKeyguardStateController,
mKeyguardUpdateMonitor,
mConfigurationController,
- mNotificationIconAreaController);
+ mNotificationIconAreaController,
+ mDozeParameters);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
index e967a5d..6c3b37e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
@@ -24,10 +24,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -54,8 +51,6 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.util.time.FakeSystemClock;
-import junit.framework.Assert;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -84,8 +79,7 @@
MockitoAnnotations.initMocks(this);
mFsc = new ForegroundServiceController(mAppOpsController, mMainHandler);
mListener = new ForegroundServiceNotificationListener(
- mContext, mFsc, mEntryManager, mNotifPipeline,
- mock(ForegroundServiceLifetimeExtender.class), mClock);
+ mContext, mFsc, mEntryManager, mNotifPipeline, mClock);
ArgumentCaptor<NotificationEntryListener> entryListenerCaptor =
ArgumentCaptor.forClass(NotificationEntryListener.class);
verify(mEntryManager).addNotificationEntryListener(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceNotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceNotificationListenerTest.java
deleted file mode 100644
index 9a40421..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceNotificationListenerTest.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui;
-
-import static com.android.systemui.ForegroundServiceLifetimeExtender.MIN_FGS_TIME_MS;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.app.Notification;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.systemui.statusbar.NotificationInteractionTracker;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
-import com.android.systemui.util.time.FakeSystemClock;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ForegroundServiceNotificationListenerTest extends SysuiTestCase {
- private ForegroundServiceLifetimeExtender mExtender;
- private NotificationEntry mEntry;
- private Notification mNotif;
- private final FakeSystemClock mClock = new FakeSystemClock();
-
- @Mock
- private NotificationInteractionTracker mInteractionTracker;
-
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
- mExtender = new ForegroundServiceLifetimeExtender(mInteractionTracker, mClock);
-
- mNotif = new Notification.Builder(mContext, "")
- .setSmallIcon(R.drawable.ic_person)
- .setContentTitle("Title")
- .setContentText("Text")
- .build();
-
- mEntry = new NotificationEntryBuilder()
- .setCreationTime(mClock.uptimeMillis())
- .setNotification(mNotif)
- .build();
- }
-
- /**
- * ForegroundServiceLifetimeExtenderTest
- */
- @Test
- public void testShouldExtendLifetime_should_foreground() {
- // Extend the lifetime of a FGS notification iff it has not been visible
- // for the minimum time
- mNotif.flags |= Notification.FLAG_FOREGROUND_SERVICE;
-
- // No time has elapsed, keep showing
- assertTrue(mExtender.shouldExtendLifetime(mEntry));
- }
-
- @Test
- public void testShouldExtendLifetime_shouldNot_foreground() {
- mNotif.flags |= Notification.FLAG_FOREGROUND_SERVICE;
-
- // Entry was created at mClock.uptimeMillis(), advance it MIN_FGS_TIME_MS + 1
- mClock.advanceTime(MIN_FGS_TIME_MS + 1);
- assertFalse(mExtender.shouldExtendLifetime(mEntry));
- }
-
- @Test
- public void testShouldExtendLifetime_shouldNot_notForeground() {
- mNotif.flags = 0;
-
- // Entry was created at mClock.uptimeMillis(), advance it MIN_FGS_TIME_MS + 1
- mClock.advanceTime(MIN_FGS_TIME_MS + 1);
- assertFalse(mExtender.shouldExtendLifetime(mEntry));
- }
-
- @Test
- public void testShouldExtendLifetime_shouldNot_interruped() {
- // GIVEN a notification that would trigger lifetime extension
- mNotif.flags |= Notification.FLAG_FOREGROUND_SERVICE;
-
- // GIVEN the notification has alerted
- mEntry.setInterruption();
-
- // THEN the notification does not need to have its lifetime extended by this extender
- assertFalse(mExtender.shouldExtendLifetime(mEntry));
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 67d0295..00943bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -44,6 +44,8 @@
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.navigationbar.NavigationModeController;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.DeviceConfigProxyFake;
@@ -73,6 +75,8 @@
private @Mock TrustManager mTrustManager;
private @Mock NavigationModeController mNavigationModeController;
private @Mock KeyguardDisplayManager mKeyguardDisplayManager;
+ private @Mock DozeParameters mDozeParameters;
+ private @Mock StatusBarStateController mStatusBarStateController;
private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake();
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
@@ -91,7 +95,7 @@
() -> mStatusBarKeyguardViewManager,
mDismissCallbackRegistry, mUpdateMonitor, mDumpManager, mUiBgExecutor,
mPowerManager, mTrustManager, mDeviceConfig, mNavigationModeController,
- mKeyguardDisplayManager);
+ mKeyguardDisplayManager, mDozeParameters, mStatusBarStateController);
mViewMediator.start();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WakefulnessLifecycleTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WakefulnessLifecycleTest.java
index 2e8e3ed..42e88b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WakefulnessLifecycleTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WakefulnessLifecycleTest.java
@@ -22,6 +22,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
+import android.os.PowerManager;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
@@ -58,7 +59,7 @@
@Test
public void dispatchStartedWakingUp() throws Exception {
- mWakefulness.dispatchStartedWakingUp();
+ mWakefulness.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
assertEquals(WakefulnessLifecycle.WAKEFULNESS_WAKING, mWakefulness.getWakefulness());
@@ -67,7 +68,7 @@
@Test
public void dispatchFinishedWakingUp() throws Exception {
- mWakefulness.dispatchStartedWakingUp();
+ mWakefulness.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
mWakefulness.dispatchFinishedWakingUp();
assertEquals(WakefulnessLifecycle.WAKEFULNESS_AWAKE, mWakefulness.getWakefulness());
@@ -77,9 +78,9 @@
@Test
public void dispatchStartedGoingToSleep() throws Exception {
- mWakefulness.dispatchStartedWakingUp();
+ mWakefulness.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
mWakefulness.dispatchFinishedWakingUp();
- mWakefulness.dispatchStartedGoingToSleep();
+ mWakefulness.dispatchStartedGoingToSleep(PowerManager.GO_TO_SLEEP_REASON_MIN);
assertEquals(WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP,
mWakefulness.getWakefulness());
@@ -89,9 +90,9 @@
@Test
public void dispatchFinishedGoingToSleep() throws Exception {
- mWakefulness.dispatchStartedWakingUp();
+ mWakefulness.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
mWakefulness.dispatchFinishedWakingUp();
- mWakefulness.dispatchStartedGoingToSleep();
+ mWakefulness.dispatchStartedGoingToSleep(PowerManager.GO_TO_SLEEP_REASON_MIN);
mWakefulness.dispatchFinishedGoingToSleep();
assertEquals(WakefulnessLifecycle.WAKEFULNESS_ASLEEP,
@@ -102,12 +103,12 @@
@Test
public void doesNotDispatchTwice() throws Exception {
- mWakefulness.dispatchStartedWakingUp();
- mWakefulness.dispatchStartedWakingUp();
+ mWakefulness.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
+ mWakefulness.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
mWakefulness.dispatchFinishedWakingUp();
mWakefulness.dispatchFinishedWakingUp();
- mWakefulness.dispatchStartedGoingToSleep();
- mWakefulness.dispatchStartedGoingToSleep();
+ mWakefulness.dispatchStartedGoingToSleep(PowerManager.GO_TO_SLEEP_REASON_MIN);
+ mWakefulness.dispatchStartedGoingToSleep(PowerManager.GO_TO_SLEEP_REASON_MIN);
mWakefulness.dispatchFinishedGoingToSleep();
mWakefulness.dispatchFinishedGoingToSleep();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerFlagsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerFlagsTest.kt
index c401fab..132bee0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerFlagsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerFlagsTest.kt
@@ -32,7 +32,6 @@
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
-import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
@@ -107,7 +106,6 @@
}
@Test
- @Ignore // TODO(b/168209929)
fun testMicCameraChanged() {
changeMicCamera(false) // default is true
executor.runAllReady()
@@ -140,7 +138,6 @@
}
@Test
- @Ignore // TODO(b/168209929)
fun testBothChanged() {
changeAll(true)
changeMicCamera(false)
@@ -162,7 +159,6 @@
}
@Test
- @Ignore // TODO(b/168209929)
fun testMicCamera_listening() {
changeMicCamera(true)
executor.runAllReady()
@@ -179,7 +175,6 @@
}
@Test
- @Ignore // TODO(b/168209929)
fun testAllFalse_notListening() {
changeAll(true)
executor.runAllReady()
@@ -191,7 +186,6 @@
}
@Test
- @Ignore // TODO(b/168209929)
fun testSomeListening_stillListening() {
// Mic and camera are true by default
changeAll(true)
@@ -203,7 +197,6 @@
}
@Test
- @Ignore // TODO(b/168209929)
fun testAllDeleted_micCameraFalse_stopListening() {
changeMicCamera(false)
changeAll(true)
@@ -215,7 +208,6 @@
}
@Test
- @Ignore // TODO(b/168209929)
fun testMicDeleted_stillListening() {
changeMicCamera(true)
executor.runAllReady()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
index a8b3056..7ca468e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
@@ -97,6 +97,7 @@
private lateinit var privacyItemController: PrivacyItemController
private lateinit var executor: FakeExecutor
+ private lateinit var fakeClock: FakeSystemClock
private lateinit var deviceConfigProxy: DeviceConfigProxy
fun PrivacyItemController(): PrivacyItemController {
@@ -113,7 +114,8 @@
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- executor = FakeExecutor(FakeSystemClock())
+ fakeClock = FakeSystemClock()
+ executor = FakeExecutor(fakeClock)
deviceConfigProxy = DeviceConfigProxyFake()
// Listen to everything by default
@@ -420,6 +422,104 @@
assertEquals(PrivacyType.TYPE_MICROPHONE, argCaptor.value[0].privacyType)
}
+ @Test
+ fun testPassageOfTimeDoesNotRemoveIndicators() {
+ doReturn(listOf(
+ AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, 0)
+ )).`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+
+ privacyItemController.addCallback(callback)
+
+ fakeClock.advanceTime(PrivacyItemController.TIME_TO_HOLD_INDICATORS * 10)
+ executor.runAllReady()
+
+ verify(callback, never()).onPrivacyItemsChanged(emptyList())
+ assertTrue(privacyItemController.privacyList.isNotEmpty())
+ }
+
+ @Test
+ fun testHoldingAfterEmptyBeforeTimeExpires() {
+ doReturn(listOf(
+ AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, 0)
+ )).`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+
+ privacyItemController.addCallback(callback)
+ executor.runAllReady()
+
+ verify(appOpsController).addCallback(any(), capture(argCaptorCallback))
+
+ `when`(appOpsController.getActiveAppOpsForUser(anyInt())).thenReturn(emptyList())
+ argCaptorCallback.value.onActiveStateChanged(
+ AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, false)
+ executor.runAllReady()
+
+ fakeClock.advanceTime(PrivacyItemController.TIME_TO_HOLD_INDICATORS / 5)
+ executor.runAllReady()
+
+ verify(callback, never()).onPrivacyItemsChanged(emptyList())
+ assertTrue(privacyItemController.privacyList.isNotEmpty())
+ }
+
+ @Test
+ fun testAfterHoldingIndicatorsAreEmpty() {
+ doReturn(listOf(
+ AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, 0)
+ )).`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+
+ privacyItemController.addCallback(callback)
+ executor.runAllReady()
+
+ verify(appOpsController).addCallback(any(), capture(argCaptorCallback))
+
+ `when`(appOpsController.getActiveAppOpsForUser(anyInt())).thenReturn(emptyList())
+ argCaptorCallback.value.onActiveStateChanged(
+ AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, false)
+ executor.runAllReady()
+
+ executor.advanceClockToLast()
+ executor.runAllReady()
+
+ verify(callback).onPrivacyItemsChanged(emptyList())
+ assertTrue(privacyItemController.privacyList.isEmpty())
+ }
+
+ @Test
+ fun testHoldingStopsIfNewIndicatorsAppear() {
+ doReturn(listOf(
+ AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, 0)
+ )).`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+
+ privacyItemController.addCallback(callback)
+ executor.runAllReady()
+
+ verify(appOpsController).addCallback(any(), capture(argCaptorCallback))
+
+ `when`(appOpsController.getActiveAppOpsForUser(anyInt())).thenReturn(emptyList())
+ argCaptorCallback.value.onActiveStateChanged(
+ AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, false)
+ executor.runAllReady()
+
+ fakeClock.advanceTime(PrivacyItemController.TIME_TO_HOLD_INDICATORS / 2)
+ executor.runAllReady()
+
+ doReturn(listOf(
+ AppOpItem(AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, 0)
+ )).`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+ argCaptorCallback.value.onActiveStateChanged(
+ AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true)
+ executor.runAllReady()
+
+ executor.advanceClockToLast()
+ executor.runAllReady()
+
+ verify(callback, never()).onPrivacyItemsChanged(emptyList())
+ verify(callback, atLeastOnce()).onPrivacyItemsChanged(capture(argCaptor))
+
+ val lastList = argCaptor.allValues.last()
+ assertEquals(1, lastList.size)
+ assertEquals(PrivacyType.TYPE_MICROPHONE, lastList.single().privacyType)
+ }
+
private fun changeMicCamera(value: Boolean?) = changeProperty(MIC_CAMERA, value)
private fun changeAll(value: Boolean?) = changeProperty(ALL_INDICATORS, value)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index a6b0330..1260eaf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -51,6 +51,7 @@
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.phone.AutoTileManager;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -87,6 +88,8 @@
private MediaHost mQSMediaHost;
@Mock
private MediaHost mQQSMediaHost;
+ @Mock
+ private FeatureFlags mFeatureFlags;
public QSFragmentTest() {
super(QSFragment.class);
@@ -175,6 +178,7 @@
new QSDetailDisplayer(),
mQSMediaHost,
mQQSMediaHost,
- mQsComponentFactory);
+ mQsComponentFactory,
+ mFeatureFlags);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageExporterTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageExporterTest.java
index f2bf7aa..b0f78ad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageExporterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageExporterTest.java
@@ -32,7 +32,6 @@
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
-import android.net.Uri;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.provider.MediaStore;
@@ -55,6 +54,7 @@
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
+import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
@@ -79,10 +79,13 @@
public void testUpdateExifAttributes_timeZoneUTC() throws IOException {
ExifInterface exifInterface = new ExifInterface(new ByteArrayInputStream(EXIF_FILE_TAG),
ExifInterface.STREAM_TYPE_EXIF_DATA_ONLY);
-
- ImageExporter.updateExifAttributes(exifInterface, 100, 100,
+ ImageExporter.updateExifAttributes(exifInterface,
+ UUID.fromString("3c11da99-9284-4863-b1d5-6f3684976814"), 100, 100,
ZonedDateTime.of(LocalDateTime.of(2020, 12, 15, 18, 15), ZoneId.of("UTC")));
+ assertEquals("Exif " + ExifInterface.TAG_IMAGE_UNIQUE_ID,
+ "3c11da99-9284-4863-b1d5-6f3684976814",
+ exifInterface.getAttribute(ExifInterface.TAG_IMAGE_UNIQUE_ID));
assertEquals("Exif " + ExifInterface.TAG_OFFSET_TIME_ORIGINAL, "+00:00",
exifInterface.getAttribute(ExifInterface.TAG_OFFSET_TIME_ORIGINAL));
}
@@ -93,24 +96,38 @@
ContentResolver contentResolver = context.getContentResolver();
ImageExporter exporter = new ImageExporter(contentResolver);
+ UUID requestId = UUID.fromString("3c11da99-9284-4863-b1d5-6f3684976814");
Bitmap original = createCheckerBitmap(10, 10, 10);
- ListenableFuture<Uri> direct = exporter.export(DIRECT_EXECUTOR, original, CAPTURE_TIME);
+ ListenableFuture<ImageExporter.Result> direct =
+ exporter.export(DIRECT_EXECUTOR, requestId, original, CAPTURE_TIME);
assertTrue("future should be done", direct.isDone());
assertFalse("future should not be canceled", direct.isCancelled());
- Uri result = direct.get();
+ ImageExporter.Result result = direct.get();
- assertNotNull("Uri should not be null", result);
+ assertEquals("Result should contain the same request id", requestId, result.requestId);
+ assertEquals("Filename should contain the correct filename",
+ "Screenshot_20201215-131500.png", result.fileName);
+ assertNotNull("CompressFormat should be set", result.format);
+ assertEquals("The default CompressFormat should be PNG", CompressFormat.PNG, result.format);
+ assertNotNull("Uri should not be null", result.uri);
+ assertEquals("Timestamp should match input", CAPTURE_TIME.toInstant().toEpochMilli(),
+ result.timestamp);
+
Bitmap decoded = null;
- try (InputStream in = contentResolver.openInputStream(result)) {
+ try (InputStream in = contentResolver.openInputStream(result.uri)) {
decoded = BitmapFactory.decodeStream(in);
assertNotNull("decoded image should not be null", decoded);
assertTrue("original and decoded image should be identical", original.sameAs(decoded));
- try (ParcelFileDescriptor pfd = contentResolver.openFile(result, "r", null)) {
+ try (ParcelFileDescriptor pfd = contentResolver.openFile(result.uri, "r", null)) {
assertNotNull(pfd);
ExifInterface exifInterface = new ExifInterface(pfd.getFileDescriptor());
+ assertEquals("Exif " + ExifInterface.TAG_IMAGE_UNIQUE_ID,
+ "3c11da99-9284-4863-b1d5-6f3684976814",
+ exifInterface.getAttribute(ExifInterface.TAG_IMAGE_UNIQUE_ID));
+
assertEquals("Exif " + ExifInterface.TAG_SOFTWARE, "Android " + Build.DISPLAY,
exifInterface.getAttribute(ExifInterface.TAG_SOFTWARE));
@@ -130,13 +147,14 @@
if (decoded != null) {
decoded.recycle();
}
- contentResolver.delete(result, null);
+ contentResolver.delete(result.uri, null);
}
}
@Test
public void testMediaStoreMetadata() {
- ContentValues values = ImageExporter.createMetadata(CAPTURE_TIME, CompressFormat.PNG);
+ String name = ImageExporter.createFilename(CAPTURE_TIME, CompressFormat.PNG);
+ ContentValues values = ImageExporter.createMetadata(CAPTURE_TIME, CompressFormat.PNG, name);
assertEquals("Pictures/Screenshots",
values.getAsString(MediaStore.MediaColumns.RELATIVE_PATH));
assertEquals("Screenshot_20201215-131500.png",
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java
index 639e791..0954621 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java
@@ -31,7 +31,6 @@
import android.app.Notification;
import android.os.Bundle;
import android.os.UserHandle;
-import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -46,7 +45,6 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
-import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -71,7 +69,6 @@
private NotificationEntryBuilder mEntryBuilder;
private AppOpsCoordinator mAppOpsCoordinator;
private NotifFilter mForegroundFilter;
- private NotifLifetimeExtender mForegroundNotifLifetimeExtender;
private NotifSectioner mFgsSection;
private FakeSystemClock mClock = new FakeSystemClock();
@@ -98,13 +95,6 @@
verify(mNotifPipeline, times(1)).addPreGroupFilter(filterCaptor.capture());
mForegroundFilter = filterCaptor.getValue();
- // capture lifetime extender
- ArgumentCaptor<NotifLifetimeExtender> lifetimeExtenderCaptor =
- ArgumentCaptor.forClass(NotifLifetimeExtender.class);
- verify(mNotifPipeline, times(1)).addNotificationLifetimeExtender(
- lifetimeExtenderCaptor.capture());
- mForegroundNotifLifetimeExtender = lifetimeExtenderCaptor.getValue();
-
mFgsSection = mAppOpsCoordinator.getSectioner();
}
@@ -160,55 +150,6 @@
}
@Test
- public void extendLifetimeText_notForeground() {
- // GIVEN the notification doesn't represent a foreground service
- mEntryBuilder.modifyNotification(mContext)
- .setFlag(FLAG_FOREGROUND_SERVICE, false);
-
- // THEN don't extend the lifetime
- assertFalse(mForegroundNotifLifetimeExtender
- .shouldExtendLifetime(mEntryBuilder.build(),
- NotificationListenerService.REASON_CLICK));
- }
-
- @Test
- public void extendLifetimeText_foregroundNotifRecentlyPosted() {
- // GIVEN the notification represents a foreground service that was just posted
- Notification notification = new Notification.Builder(mContext, "test_channel")
- .setFlag(FLAG_FOREGROUND_SERVICE, true)
- .build();
- NotificationEntry entry = mEntryBuilder
- .setSbn(new StatusBarNotification(TEST_PKG, TEST_PKG, NOTIF_USER_ID, "",
- NOTIF_USER_ID, NOTIF_USER_ID, notification,
- new UserHandle(NOTIF_USER_ID), "", System.currentTimeMillis()))
- .setNotification(notification)
- .build();
-
- // THEN extend the lifetime
- assertTrue(mForegroundNotifLifetimeExtender
- .shouldExtendLifetime(entry, NotificationListenerService.REASON_CLICK));
- }
-
- @Test
- public void extendLifetimeText_foregroundNotifOld() {
- // GIVEN the notification represents a foreground service that was posted 10 seconds ago
- Notification notification = new Notification.Builder(mContext, "test_channel")
- .setFlag(FLAG_FOREGROUND_SERVICE, true)
- .build();
- NotificationEntry entry = mEntryBuilder
- .setSbn(new StatusBarNotification(TEST_PKG, TEST_PKG, NOTIF_USER_ID, "",
- NOTIF_USER_ID, NOTIF_USER_ID, notification,
- new UserHandle(NOTIF_USER_ID), "",
- System.currentTimeMillis() - 10000))
- .setNotification(notification)
- .build();
-
- // THEN don't extend the lifetime because the extended time exceeds MIN_FGS_TIME_MS
- assertFalse(mForegroundNotifLifetimeExtender
- .shouldExtendLifetime(entry, NotificationListenerService.REASON_CLICK));
- }
-
- @Test
public void testIncludeFGSInSection_importanceDefault() {
// GIVEN the notification represents a colorized foreground service with > min importance
mEntryBuilder
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 342b2f5..30c3e6d 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
@@ -50,6 +50,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dock.DockManager;
import com.android.systemui.statusbar.BlurUtils;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -104,6 +105,8 @@
private BlurUtils mBlurUtils;
@Mock
private ConfigurationController mConfigurationController;
+ @Mock
+ private FeatureFlags mFeatureFlags;
private static class AnimatorListener implements Animator.AnimatorListener {
@@ -211,13 +214,13 @@
when(mDelayedWakeLockBuilder.setTag(any(String.class)))
.thenReturn(mDelayedWakeLockBuilder);
when(mDelayedWakeLockBuilder.build()).thenReturn(mWakeLock);
-
+ when(mFeatureFlags.isShadeOpaque()).thenReturn(true);
when(mDockManager.isDocked()).thenReturn(false);
mScrimController = new ScrimController(mLightBarController,
mDozeParamenters, mAlarmManager, mKeyguardStateController, mDelayedWakeLockBuilder,
new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor,
- mDockManager, mBlurUtils, mConfigurationController);
+ mDockManager, mBlurUtils, mConfigurationController, mFeatureFlags);
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
mScrimController.attachViews(mScrimBehind, mScrimInFront, mScrimForBubble);
mScrimController.setAnimatorListener(mAnimatorListener);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 51ce8e5..2c781ba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -317,7 +317,7 @@
when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
WakefulnessLifecycle wakefulnessLifecycle = new WakefulnessLifecycle();
- wakefulnessLifecycle.dispatchStartedWakingUp();
+ wakefulnessLifecycle.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
wakefulnessLifecycle.dispatchFinishedWakingUp();
when(mGradientColors.supportsDarkText()).thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 273a77b..c83835b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -62,6 +62,7 @@
import androidx.test.InstrumentationRegistry;
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.settingslib.R;
import com.android.settingslib.graph.SignalDrawable;
import com.android.settingslib.mobile.MobileMappings.Config;
@@ -82,6 +83,8 @@
import org.junit.runner.Description;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -126,6 +129,8 @@
private ConnectivityManager.NetworkCallback mDefaultCallbackInNetworkController;
private ConnectivityManager.NetworkCallback mNetworkCallback;
+ MockitoSession mMockingSession = null;
+
@Rule
public TestWatcher failWatcher = new TestWatcher() {
@Override
@@ -145,7 +150,11 @@
@Before
public void setUp() throws Exception {
- FeatureFlagUtils.setEnabled(mContext, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL, true);
+ mMockingSession = ExtendedMockito.mockitoSession().strictness(Strictness.LENIENT)
+ .mockStatic(FeatureFlagUtils.class).startMocking();
+ ExtendedMockito.doReturn(true).when(() -> FeatureFlagUtils.isEnabled(mContext,
+ FeatureFlagUtils.SETTINGS_PROVIDER_MODEL));
+
mInstrumentation = InstrumentationRegistry.getInstrumentation();
Settings.Global.putInt(mContext.getContentResolver(), Global.AIRPLANE_MODE_ON, 0);
TestableResources res = mContext.getOrCreateTestableResources();
@@ -227,7 +236,9 @@
@After
public void tearDown() throws Exception {
- FeatureFlagUtils.setEnabled(mContext, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL, false);
+ if (mMockingSession != null) {
+ mMockingSession.finishMocking();
+ }
}
protected void setupNetworkController() {
diff --git a/services/Android.bp b/services/Android.bp
index da24719..b11a2e8 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -147,11 +147,20 @@
baseline_file: "api/lint-baseline.txt",
},
},
- dist: {
- targets: ["sdk", "win_sdk"],
- dir: "apistubs/android/system-server/api",
- dest: "android.txt",
- },
+ dists: [
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/system-server/api",
+ dest: "android.txt",
+ tag: ".api.txt"
+ },
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/system-server/api",
+ dest: "removed.txt",
+ tag: ".removed-api.txt",
+ },
+ ]
}
java_library {
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
index 7483ff3..2434e2c 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
@@ -141,12 +141,12 @@
public FullScreenMagnificationGestureHandler(Context context,
FullScreenMagnificationController fullScreenMagnificationController,
- ScaleChangedListener listener,
+ Callback callback,
boolean detectTripleTap,
boolean detectShortcutTrigger,
@NonNull WindowMagnificationPromptController promptController,
int displayId) {
- super(displayId, detectTripleTap, detectShortcutTrigger, listener);
+ super(displayId, detectTripleTap, detectShortcutTrigger, callback);
if (DEBUG_ALL) {
Log.i(mLogTag,
"FullScreenMagnificationGestureHandler(detectTripleTap = " + detectTripleTap
@@ -211,16 +211,14 @@
}
@Override
- public void notifyShortcutTriggered() {
- if (mDetectShortcutTrigger) {
- boolean wasMagnifying = mFullScreenMagnificationController.resetIfNeeded(mDisplayId,
- /* animate */ true);
- if (wasMagnifying) {
- clearAndTransitionToStateDetecting();
- } else {
- mPromptController.showNotificationIfNeeded();
- mDetectingState.toggleShortcutTriggered();
- }
+ public void handleShortcutTriggered() {
+ boolean wasMagnifying = mFullScreenMagnificationController.resetIfNeeded(mDisplayId,
+ /* animate */ true);
+ if (wasMagnifying) {
+ clearAndTransitionToStateDetecting();
+ } else {
+ mPromptController.showNotificationIfNeeded();
+ mDetectingState.toggleShortcutTriggered();
}
}
@@ -395,7 +393,6 @@
if (DEBUG_PANNING_SCALING) Slog.i(mLogTag, "Scaled content to: " + scale + "x");
mFullScreenMagnificationController.setScale(mDisplayId, scale, pivotX, pivotY, false,
AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
- mListener.onMagnificationScaleChanged(mDisplayId, getMode());
return /* handled: */ true;
}
@@ -869,6 +866,8 @@
mPromptController.showNotificationIfNeeded();
zoomOn(up.getX(), up.getY());
}
+
+ mCallback.onTripleTapped(mDisplayId, getMode());
}
private boolean isMagnifying() {
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
index df88ceb..2a65b64 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
@@ -34,11 +34,24 @@
import com.android.server.accessibility.AccessibilityManagerService;
/**
- * Handles all magnification controllers initialization, generic interactions
- * and magnification mode transition.
+ * Handles all magnification controllers initialization, generic interactions,
+ * magnification mode transition and magnification switch UI show/hide logic
+ * in the following callbacks:
+ *
+ * <ol>
+ * <li> 1. {@link #onTouchInteractionStart} shows magnification switch UI when
+ * the user touch interaction starts if magnification capabilities is all. </li>
+ * <li> 2. {@link #onTouchInteractionEnd} shows magnification switch UI when
+ * the user touch interaction ends if magnification capabilities is all. </li>
+ * <li> 3. {@link #onShortcutTriggered} updates magnification switch UI depending on
+ * magnification capabilities and magnification active state when magnification shortcut
+ * is triggered.</li>
+ * <li> 4. {@link #onTripleTapped} updates magnification switch UI depending on magnification
+ * capabilities and magnification active state when triple-tap gesture is detected. </li>
+ * </ol>
*/
public class MagnificationController implements WindowMagnificationManager.Callback,
- MagnificationGestureHandler.ScaleChangedListener {
+ MagnificationGestureHandler.Callback {
private static final boolean DEBUG = false;
private static final String TAG = "MagnificationController";
@@ -84,16 +97,44 @@
public void onPerformScaleAction(int displayId, float scale) {
getWindowMagnificationMgr().setScale(displayId, scale);
getWindowMagnificationMgr().persistScale(displayId);
- onMagnificationScaleChanged(displayId,
- Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
}
@Override
- public void onMagnificationScaleChanged(int displayId, int mode) {
+ public void onTouchInteractionStart(int displayId, int mode) {
+ handleUserInteractionChanged(displayId, mode);
+ }
+
+ @Override
+ public void onTouchInteractionEnd(int displayId, int mode) {
+ handleUserInteractionChanged(displayId, mode);
+ }
+
+ private void handleUserInteractionChanged(int displayId, int mode) {
if (mMagnificationCapabilities != Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL) {
return;
}
- getWindowMagnificationMgr().showMagnificationButton(displayId, mode);
+ if (isActivated(displayId, mode)) {
+ getWindowMagnificationMgr().showMagnificationButton(displayId, mode);
+ }
+ }
+
+ @Override
+ public void onShortcutTriggered(int displayId, int mode) {
+ updateMagnificationButton(displayId, mode);
+ }
+
+ @Override
+ public void onTripleTapped(int displayId, int mode) {
+ updateMagnificationButton(displayId, mode);
+ }
+
+ private void updateMagnificationButton(int displayId, int mode) {
+ if (isActivated(displayId, mode) && mMagnificationCapabilities
+ == Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL) {
+ getWindowMagnificationMgr().showMagnificationButton(displayId, mode);
+ } else {
+ getWindowMagnificationMgr().removeMagnificationButton(displayId);
+ }
}
/**
@@ -272,6 +313,18 @@
return mTempPoint;
}
+ private boolean isActivated(int displayId, int mode) {
+ boolean isActivated = false;
+ if (mode == ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN
+ && mFullScreenMagnificationController != null) {
+ isActivated = mFullScreenMagnificationController.isMagnifying(displayId);
+ } else if (mode == ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW
+ && mWindowMagnificationMgr != null) {
+ isActivated = mWindowMagnificationMgr.isWindowMagnifierEnabled(displayId);
+ }
+ return isActivated;
+ }
+
private final class DisableMagnificationCallback implements
MagnificationAnimationCallback {
private final TransitionCallBack mTransitionCallBack;
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java
index 386d0bb..bbe40b6 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java
@@ -17,6 +17,8 @@
package com.android.server.accessibility.magnification;
import static android.view.InputDevice.SOURCE_TOUCHSCREEN;
+import static android.view.MotionEvent.ACTION_CANCEL;
+import static android.view.MotionEvent.ACTION_UP;
import android.annotation.NonNull;
import android.util.Log;
@@ -59,26 +61,53 @@
*/
protected final boolean mDetectTripleTap;
- /** Interface for listening to the magnification scaling gesture. */
- public interface ScaleChangedListener {
+ /** Callback interface to report that magnification is interactive with a user. */
+ public interface Callback {
/**
- * Called when the magnification scale is changed by users.
+ * Called when the touch interaction is started by a user.
*
* @param displayId The logical display id
- * @param mode The magnification mode
+ * @param mode The magnification mode
*/
- void onMagnificationScaleChanged(int displayId, int mode);
+ void onTouchInteractionStart(int displayId, int mode);
+
+ /**
+ * Called when the touch interaction is ended by a user.
+ *
+ * @param displayId The logical display id
+ * @param mode The magnification mode
+ */
+ void onTouchInteractionEnd(int displayId, int mode);
+
+ /**
+ * Called when the magnification shortcut is triggered by a user. The magnification
+ * shortcut can be accessibility button or volume shortcut.
+ *
+ * @param displayId The logical display id
+ * @param mode The magnification mode
+ */
+ void onShortcutTriggered(int displayId, int mode);
+
+ /**
+ * Called when the triple-tap gesture is handled. The magnification
+ * shortcut can be a triple-tap gesture or accessibility button.
+ * Called when the triple-tap gesture is handled
+ *
+ * @param displayId The logical display id
+ * @param mode The magnification mode
+ */
+ void onTripleTapped(int displayId, int mode);
}
- protected final ScaleChangedListener mListener;
+ protected final Callback mCallback;
protected MagnificationGestureHandler(int displayId, boolean detectTripleTap,
boolean detectShortcutTrigger,
- @NonNull ScaleChangedListener listener) {
+ @NonNull Callback callback) {
mDisplayId = displayId;
mDetectTripleTap = detectTripleTap;
mDetectShortcutTrigger = detectShortcutTrigger;
- mListener = listener;
+ mCallback = callback;
mDebugInputEventHistory = DEBUG_EVENT_STREAM ? new ArrayDeque<>() : null;
mDebugOutputEventHistory = DEBUG_EVENT_STREAM ? new ArrayDeque<>() : null;
@@ -96,6 +125,13 @@
dispatchTransformedEvent(event, rawEvent, policyFlags);
} else {
onMotionEventInternal(event, rawEvent, policyFlags);
+
+ final int action = event.getAction();
+ if (action == MotionEvent.ACTION_DOWN) {
+ mCallback.onTouchInteractionStart(mDisplayId, getMode());
+ } else if (action == ACTION_UP || action == ACTION_CANCEL) {
+ mCallback.onTouchInteractionEnd(mDisplayId, getMode());
+ }
}
}
@@ -107,8 +143,7 @@
return false;
}
- final void dispatchTransformedEvent(MotionEvent event, MotionEvent rawEvent,
- int policyFlags) {
+ final void dispatchTransformedEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
if (DEBUG_EVENT_STREAM) {
storeEventInto(mDebugOutputEventHistory, event);
try {
@@ -140,7 +175,20 @@
/**
* Called when the shortcut target is magnification.
*/
- public abstract void notifyShortcutTriggered();
+ public void notifyShortcutTriggered() {
+ if (DEBUG_ALL) {
+ Slog.i(mLogTag, "notifyShortcutTriggered():");
+ }
+ if (mDetectShortcutTrigger) {
+ handleShortcutTriggered();
+ mCallback.onShortcutTriggered(mDisplayId, getMode());
+ }
+ }
+
+ /**
+ * Handles shortcut triggered event.
+ */
+ abstract void handleShortcutTriggered();
/**
* Indicates the magnification mode.
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
index 7f26b27..55a911e 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
@@ -88,9 +88,9 @@
public WindowMagnificationGestureHandler(Context context,
WindowMagnificationManager windowMagnificationMgr,
- ScaleChangedListener listener,
+ Callback callback,
boolean detectTripleTap, boolean detectShortcutTrigger, int displayId) {
- super(displayId, detectTripleTap, detectShortcutTrigger, listener);
+ super(displayId, detectTripleTap, detectShortcutTrigger, callback);
if (DEBUG_ALL) {
Slog.i(mLogTag,
"WindowMagnificationGestureHandler() , displayId = " + displayId + ")");
@@ -115,7 +115,6 @@
@Override
public void setScale(int displayId, float scale) {
mWindowMagnificationMgr.setScale(displayId, scale);
- mListener.onMagnificationScaleChanged(displayId, getMode());
}
@Override
@@ -153,13 +152,7 @@
}
@Override
- public void notifyShortcutTriggered() {
- if (DEBUG_ALL) {
- Slog.i(mLogTag, "notifyShortcutTriggered():");
- }
- if (!mDetectShortcutTrigger) {
- return;
- }
+ public void handleShortcutTriggered() {
final Point screenSize = mTempPoint;
getScreenSize(mTempPoint);
toggleMagnification(screenSize.x / 2.0f, screenSize.y / 2.0f);
@@ -206,6 +199,7 @@
Slog.i(mLogTag, "onTripleTap()");
}
toggleMagnification(up.getX(), up.getY());
+ mCallback.onTripleTapped(mDisplayId, getMode());
}
void resetToDetectState() {
diff --git a/services/appwidget/java/com/android/server/appwidget/OWNERS b/services/appwidget/java/com/android/server/appwidget/OWNERS
new file mode 100644
index 0000000..d724cac
--- /dev/null
+++ b/services/appwidget/java/com/android/server/appwidget/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/appwidget/OWNERS
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 3750f14..2f3ad19 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -120,6 +120,9 @@
"time_zone_distro",
"time_zone_distro_installer",
"android.hardware.authsecret-V1.0-java",
+ "android.hardware.boot-V1.0-java",
+ "android.hardware.boot-V1.1-java",
+ "android.hardware.boot-V1.2-java",
"android.hardware.broadcastradio-V2.0-java",
"android.hardware.health-V1.0-java",
"android.hardware.health-V2.0-java",
@@ -223,6 +226,8 @@
"java/com/android/server/connectivity/NetworkRanker.java",
"java/com/android/server/connectivity/PermissionMonitor.java",
"java/com/android/server/connectivity/ProxyTracker.java",
+ "java/com/android/server/connectivity/QosCallbackAgentConnection.java",
+ "java/com/android/server/connectivity/QosCallbackTracker.java",
"java/com/android/server/connectivity/TcpKeepaliveController.java",
"java/com/android/server/connectivity/Vpn.java",
"java/com/android/server/connectivity/VpnIkev2Utils.java",
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 7541833..b6232a0 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -94,6 +94,7 @@
import android.net.INetworkMonitorCallbacks;
import android.net.INetworkPolicyListener;
import android.net.INetworkStatsService;
+import android.net.IQosCallback;
import android.net.ISocketKeepaliveCallback;
import android.net.InetAddresses;
import android.net.IpMemoryStore;
@@ -121,6 +122,10 @@
import android.net.NetworkWatchlistManager;
import android.net.PrivateDnsConfigParcel;
import android.net.ProxyInfo;
+import android.net.QosCallbackException;
+import android.net.QosFilter;
+import android.net.QosSocketFilter;
+import android.net.QosSocketInfo;
import android.net.RouteInfo;
import android.net.RouteInfoParcel;
import android.net.SocketKeepalive;
@@ -204,6 +209,7 @@
import com.android.server.connectivity.NetworkRanker;
import com.android.server.connectivity.PermissionMonitor;
import com.android.server.connectivity.ProxyTracker;
+import com.android.server.connectivity.QosCallbackTracker;
import com.android.server.connectivity.Vpn;
import com.android.server.net.BaseNetworkObserver;
import com.android.server.net.LockdownVpnTracker;
@@ -279,6 +285,10 @@
// Default to 30s linger time-out. Modifiable only for testing.
private static final String LINGER_DELAY_PROPERTY = "persist.netmon.linger";
private static final int DEFAULT_LINGER_DELAY_MS = 30_000;
+
+ // The maximum number of network request allowed per uid before an exception is thrown.
+ private static final int MAX_NETWORK_REQUESTS_PER_UID = 100;
+
@VisibleForTesting
protected int mLingerDelayMs; // Can't be final, or test subclass constructors can't change it.
@@ -291,6 +301,8 @@
@VisibleForTesting
protected final PermissionMonitor mPermissionMonitor;
+ private final PerUidCounter mNetworkRequestCounter;
+
private KeyStore mKeyStore;
@VisibleForTesting
@@ -614,6 +626,7 @@
private final LocationPermissionChecker mLocationPermissionChecker;
private KeepaliveTracker mKeepaliveTracker;
+ private QosCallbackTracker mQosCallbackTracker;
private NetworkNotificationManager mNotifier;
private LingerMonitor mLingerMonitor;
@@ -858,6 +871,66 @@
};
/**
+ * Keeps track of the number of requests made under different uids.
+ */
+ public static class PerUidCounter {
+ private final int mMaxCountPerUid;
+
+ // Map from UID to number of NetworkRequests that UID has filed.
+ @GuardedBy("mUidToNetworkRequestCount")
+ private final SparseIntArray mUidToNetworkRequestCount = new SparseIntArray();
+
+ /**
+ * Constructor
+ *
+ * @param maxCountPerUid the maximum count per uid allowed
+ */
+ public PerUidCounter(final int maxCountPerUid) {
+ mMaxCountPerUid = maxCountPerUid;
+ }
+
+ /**
+ * Increments the request count of the given uid. Throws an exception if the number
+ * of open requests for the uid exceeds the value of maxCounterPerUid which is the value
+ * passed into the constructor. see: {@link #PerUidCounter(int)}.
+ *
+ * @throws ServiceSpecificException with
+ * {@link ConnectivityManager.Errors.TOO_MANY_REQUESTS} if the number of requests for
+ * the uid exceed the allowed number.
+ *
+ * @param uid the uid that the request was made under
+ */
+ public void incrementCountOrThrow(final int uid) {
+ synchronized (mUidToNetworkRequestCount) {
+ final int networkRequests = mUidToNetworkRequestCount.get(uid, 0) + 1;
+ if (networkRequests >= mMaxCountPerUid) {
+ throw new ServiceSpecificException(
+ ConnectivityManager.Errors.TOO_MANY_REQUESTS);
+ }
+ mUidToNetworkRequestCount.put(uid, networkRequests);
+ }
+ }
+
+ /**
+ * Decrements the request count of the given uid.
+ *
+ * @param uid the uid that the request was made under
+ */
+ public void decrementCount(final int uid) {
+ synchronized (mUidToNetworkRequestCount) {
+ final int requests = mUidToNetworkRequestCount.get(uid, 0);
+ if (requests < 1) {
+ logwtf("BUG: too small request count " + requests + " for UID " + uid);
+ } else if (requests == 1) {
+ mUidToNetworkRequestCount.delete(uid);
+ } else {
+ mUidToNetworkRequestCount.put(uid, requests - 1);
+ }
+ }
+ }
+ }
+
+ /**
* Dependencies of ConnectivityService, for injection in tests.
*/
@VisibleForTesting
@@ -945,6 +1018,7 @@
mSystemProperties = mDeps.getSystemProperties();
mNetIdManager = mDeps.makeNetIdManager();
mContext = Objects.requireNonNull(context, "missing Context");
+ mNetworkRequestCounter = new PerUidCounter(MAX_NETWORK_REQUESTS_PER_UID);
mMetricsLog = logger;
mDefaultRequest = createDefaultInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST);
@@ -1115,11 +1189,7 @@
userAllContext.registerReceiver(
mIntentReceiver, intentFilter, NETWORK_STACK, mHandler);
- try {
- mNMS.registerObserver(mDataActivityObserver);
- } catch (RemoteException e) {
- loge("Error registering observer :" + e);
- }
+ mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mNMS);
mSettingsObserver = new SettingsObserver(mContext, mHandler);
registerSettingsCallbacks();
@@ -1129,6 +1199,7 @@
mKeepaliveTracker = new KeepaliveTracker(mContext, mHandler);
mNotifier = new NetworkNotificationManager(mContext, mTelephonyManager);
+ mQosCallbackTracker = new QosCallbackTracker(mHandler, mNetworkRequestCounter);
final int dailyLimit = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT,
@@ -1802,30 +1873,6 @@
}
}
- private INetworkManagementEventObserver mDataActivityObserver = new BaseNetworkObserver() {
- @Override
- public void interfaceClassDataActivityChanged(int transportType, boolean active,
- long tsNanos, int uid) {
- sendDataActivityBroadcast(transportTypeToLegacyType(transportType), active, tsNanos);
- }
- };
-
- // This is deprecated and only to support legacy use cases.
- private int transportTypeToLegacyType(int type) {
- switch (type) {
- case NetworkCapabilities.TRANSPORT_CELLULAR:
- return ConnectivityManager.TYPE_MOBILE;
- case NetworkCapabilities.TRANSPORT_WIFI:
- return ConnectivityManager.TYPE_WIFI;
- case NetworkCapabilities.TRANSPORT_BLUETOOTH:
- return ConnectivityManager.TYPE_BLUETOOTH;
- case NetworkCapabilities.TRANSPORT_ETHERNET:
- return ConnectivityManager.TYPE_ETHERNET;
- default:
- loge("Unexpected transport in transportTypeToLegacyType: " + type);
- }
- return ConnectivityManager.TYPE_NONE;
- }
/**
* Ensures that the system cannot call a particular method.
*/
@@ -2274,20 +2321,6 @@
sendStickyBroadcast(makeGeneralIntent(info, bcastType));
}
- private void sendDataActivityBroadcast(int deviceType, boolean active, long tsNanos) {
- Intent intent = new Intent(ConnectivityManager.ACTION_DATA_ACTIVITY_CHANGE);
- intent.putExtra(ConnectivityManager.EXTRA_DEVICE_TYPE, deviceType);
- intent.putExtra(ConnectivityManager.EXTRA_IS_ACTIVE, active);
- intent.putExtra(ConnectivityManager.EXTRA_REALTIME_NS, tsNanos);
- final long ident = Binder.clearCallingIdentity();
- try {
- mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL,
- RECEIVE_DATA_ACTIVITY_CHANGE, null, null, 0, null, null);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
private void sendStickyBroadcast(Intent intent) {
synchronized (this) {
if (!mSystemReady
@@ -2393,74 +2426,6 @@
}
/**
- * Setup data activity tracking for the given network.
- *
- * Every {@code setupDataActivityTracking} should be paired with a
- * {@link #removeDataActivityTracking} for cleanup.
- */
- private void setupDataActivityTracking(NetworkAgentInfo networkAgent) {
- final String iface = networkAgent.linkProperties.getInterfaceName();
-
- final int timeout;
- final int type;
-
- if (networkAgent.networkCapabilities.hasTransport(
- NetworkCapabilities.TRANSPORT_CELLULAR)) {
- timeout = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE,
- 10);
- type = NetworkCapabilities.TRANSPORT_CELLULAR;
- } else if (networkAgent.networkCapabilities.hasTransport(
- NetworkCapabilities.TRANSPORT_WIFI)) {
- timeout = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI,
- 15);
- type = NetworkCapabilities.TRANSPORT_WIFI;
- } else {
- return; // do not track any other networks
- }
-
- if (timeout > 0 && iface != null) {
- try {
- mNMS.addIdleTimer(iface, timeout, type);
- } catch (Exception e) {
- // You shall not crash!
- loge("Exception in setupDataActivityTracking " + e);
- }
- }
- }
-
- /**
- * Remove data activity tracking when network disconnects.
- */
- private void removeDataActivityTracking(NetworkAgentInfo networkAgent) {
- final String iface = networkAgent.linkProperties.getInterfaceName();
- final NetworkCapabilities caps = networkAgent.networkCapabilities;
-
- if (iface != null && (caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
- caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))) {
- try {
- // the call fails silently if no idle timer setup for this interface
- mNMS.removeIdleTimer(iface);
- } catch (Exception e) {
- loge("Exception in removeDataActivityTracking " + e);
- }
- }
- }
-
- /**
- * Update data activity tracking when network state is updated.
- */
- private void updateDataActivityTracking(NetworkAgentInfo newNetwork,
- NetworkAgentInfo oldNetwork) {
- if (newNetwork != null) {
- setupDataActivityTracking(newNetwork);
- }
- if (oldNetwork != null) {
- removeDataActivityTracking(oldNetwork);
- }
- }
- /**
* Reads the network specific MTU size from resources.
* and set it on it's iface.
*/
@@ -2874,13 +2839,7 @@
Log.wtf(TAG, "Non-virtual networks cannot have underlying networks");
break;
}
- final ArrayList<Network> underlying;
- try {
- underlying = ((Bundle) arg.second).getParcelableArrayList(
- NetworkAgent.UNDERLYING_NETWORKS_KEY);
- } catch (NullPointerException | ClassCastException e) {
- break;
- }
+ final List<Network> underlying = (List<Network>) arg.second;
final Network[] oldUnderlying = nai.declaredUnderlyingNetworks;
nai.declaredUnderlyingNetworks = (underlying != null)
? underlying.toArray(new Network[0]) : null;
@@ -2893,6 +2852,7 @@
updateCapabilitiesForNetwork(nai);
notifyIfacesChangedForNetworkStats();
}
+ break;
}
}
}
@@ -3454,6 +3414,8 @@
// of rematchAllNetworksAndRequests
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST);
mKeepaliveTracker.handleStopAllKeepalives(nai, SocketKeepalive.ERROR_INVALID_NETWORK);
+
+ mQosCallbackTracker.handleNetworkReleased(nai.network);
for (String iface : nai.linkProperties.getAllInterfaceNames()) {
// Disable wakeup packet monitoring for each interface.
wakeupModifyInterface(iface, nai.networkCapabilities, false);
@@ -3484,7 +3446,7 @@
// the default network disconnecting. Find out why, fix the rematch code, and delete this.
if (nai.isSatisfyingRequest(mDefaultRequest.requestId)) {
mDefaultNetworkNai = null;
- updateDataActivityTracking(null /* newNetwork */, nai);
+ mNetworkActivityTracker.updateDataActivityTracking(null /* newNetwork */, nai);
notifyLockdownVpn(nai);
ensureNetworkTransitionWakelock(nai.toShortString());
}
@@ -3723,7 +3685,7 @@
nri.unlinkDeathRecipient();
mNetworkRequests.remove(nri.request);
- decrementNetworkRequestPerUidCount(nri);
+ mNetworkRequestCounter.decrementCount(nri.mUid);
mNetworkRequestInfoLogs.log("RELEASE " + nri);
if (nri.request.isRequest()) {
@@ -3796,19 +3758,6 @@
}
}
- private void decrementNetworkRequestPerUidCount(final NetworkRequestInfo nri) {
- synchronized (mUidToNetworkRequestCount) {
- final int requests = mUidToNetworkRequestCount.get(nri.mUid, 0);
- if (requests < 1) {
- Log.wtf(TAG, "BUG: too small request count " + requests + " for UID " + nri.mUid);
- } else if (requests == 1) {
- mUidToNetworkRequestCount.removeAt(mUidToNetworkRequestCount.indexOfKey(nri.mUid));
- } else {
- mUidToNetworkRequestCount.put(nri.mUid, requests - 1);
- }
- }
- }
-
@Override
public void setAcceptUnvalidated(Network network, boolean accept, boolean always) {
enforceNetworkStackSettingsOrSetup();
@@ -4635,6 +4584,10 @@
Log.w(TAG, s);
}
+ private static void logwtf(String s) {
+ Log.wtf(TAG, s);
+ }
+
private static void loge(String s) {
Log.e(TAG, s);
}
@@ -5377,11 +5330,6 @@
private final HashMap<Messenger, NetworkProviderInfo> mNetworkProviderInfos = new HashMap<>();
private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests = new HashMap<>();
- private static final int MAX_NETWORK_REQUESTS_PER_UID = 100;
- // Map from UID to number of NetworkRequests that UID has filed.
- @GuardedBy("mUidToNetworkRequestCount")
- private final SparseIntArray mUidToNetworkRequestCount = new SparseIntArray();
-
private static class NetworkProviderInfo {
public final String name;
public final Messenger messenger;
@@ -5495,7 +5443,7 @@
mBinder = null;
mPid = getCallingPid();
mUid = mDeps.getCallingUid();
- enforceRequestCountLimit();
+ mNetworkRequestCounter.incrementCountOrThrow(mUid);
}
NetworkRequestInfo(Messenger m, NetworkRequest r, IBinder binder) {
@@ -5508,7 +5456,7 @@
mPid = getCallingPid();
mUid = mDeps.getCallingUid();
mPendingIntent = null;
- enforceRequestCountLimit();
+ mNetworkRequestCounter.incrementCountOrThrow(mUid);
try {
mBinder.linkToDeath(this, 0);
@@ -5545,17 +5493,6 @@
return null;
}
- private void enforceRequestCountLimit() {
- synchronized (mUidToNetworkRequestCount) {
- int networkRequests = mUidToNetworkRequestCount.get(mUid, 0) + 1;
- if (networkRequests >= MAX_NETWORK_REQUESTS_PER_UID) {
- throw new ServiceSpecificException(
- ConnectivityManager.Errors.TOO_MANY_REQUESTS);
- }
- mUidToNetworkRequestCount.put(mUid, networkRequests);
- }
- }
-
void unlinkDeathRecipient() {
if (mBinder != null) {
mBinder.unlinkToDeath(this, 0);
@@ -5777,9 +5714,14 @@
// Policy already enforced.
return;
}
- if (mPolicyManagerInternal.isUidRestrictedOnMeteredNetworks(uid)) {
- // If UID is restricted, don't allow them to bring up metered APNs.
- networkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ if (mPolicyManager.isUidRestrictedOnMeteredNetworks(uid)) {
+ // If UID is restricted, don't allow them to bring up metered APNs.
+ networkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
@@ -6114,7 +6056,7 @@
final NetworkAgentInfo nai = new NetworkAgentInfo(na,
new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig),
- this, mNetd, mDnsResolver, mNMS, providerId, uid);
+ this, mNetd, mDnsResolver, mNMS, providerId, uid, mQosCallbackTracker);
// Make sure the LinkProperties and NetworkCapabilities reflect what the agent info says.
processCapabilitiesFromAgent(nai, nc);
@@ -7314,7 +7256,8 @@
if (oldDefaultNetwork != null) {
mLingerMonitor.noteLingerDefaultNetwork(oldDefaultNetwork, newDefaultNetwork);
}
- updateDataActivityTracking(newDefaultNetwork, oldDefaultNetwork);
+ mNetworkActivityTracker.updateDataActivityTracking(
+ newDefaultNetwork, oldDefaultNetwork);
// Notify system services of the new default.
makeDefault(newDefaultNetwork);
@@ -7912,10 +7855,11 @@
}
@Override
- public void startNattKeepaliveWithFd(Network network, FileDescriptor fd, int resourceId,
+ public void startNattKeepaliveWithFd(Network network, ParcelFileDescriptor pfd, int resourceId,
int intervalSeconds, ISocketKeepaliveCallback cb, String srcAddr,
String dstAddr) {
try {
+ final FileDescriptor fd = pfd.getFileDescriptor();
mKeepaliveTracker.startNattKeepalive(
getNetworkAgentInfoForNetwork(network), fd, resourceId,
intervalSeconds, cb,
@@ -7923,24 +7867,25 @@
} finally {
// FileDescriptors coming from AIDL calls must be manually closed to prevent leaks.
// startNattKeepalive calls Os.dup(fd) before returning, so we can close immediately.
- if (fd != null && Binder.getCallingPid() != Process.myPid()) {
- IoUtils.closeQuietly(fd);
+ if (pfd != null && Binder.getCallingPid() != Process.myPid()) {
+ IoUtils.closeQuietly(pfd);
}
}
}
@Override
- public void startTcpKeepalive(Network network, FileDescriptor fd, int intervalSeconds,
+ public void startTcpKeepalive(Network network, ParcelFileDescriptor pfd, int intervalSeconds,
ISocketKeepaliveCallback cb) {
try {
enforceKeepalivePermission();
+ final FileDescriptor fd = pfd.getFileDescriptor();
mKeepaliveTracker.startTcpKeepalive(
getNetworkAgentInfoForNetwork(network), fd, intervalSeconds, cb);
} finally {
// FileDescriptors coming from AIDL calls must be manually closed to prevent leaks.
// startTcpKeepalive calls Os.dup(fd) before returning, so we can close immediately.
- if (fd != null && Binder.getCallingPid() != Process.myPid()) {
- IoUtils.closeQuietly(fd);
+ if (pfd != null && Binder.getCallingPid() != Process.myPid()) {
+ IoUtils.closeQuietly(pfd);
}
}
}
@@ -8391,7 +8336,7 @@
// Decrement the reference count for this NetworkRequestInfo. The reference count is
// incremented when the NetworkRequestInfo is created as part of
// enforceRequestCountLimit().
- decrementNetworkRequestPerUidCount(nri);
+ mNetworkRequestCounter.decrementCount(nri.mUid);
return;
}
@@ -8457,7 +8402,7 @@
// Decrement the reference count for this NetworkRequestInfo. The reference count is
// incremented when the NetworkRequestInfo is created as part of
// enforceRequestCountLimit().
- decrementNetworkRequestPerUidCount(nri);
+ mNetworkRequestCounter.decrementCount(nri.mUid);
iCb.unlinkToDeath(cbInfo, 0);
}
@@ -8666,4 +8611,194 @@
notifyDataStallSuspected(p, network.getNetId());
}
+
+ private final LegacyNetworkActivityTracker mNetworkActivityTracker;
+
+ /**
+ * Class used for updating network activity tracking with netd and notify network activity
+ * changes.
+ */
+ private static final class LegacyNetworkActivityTracker {
+ private final Context mContext;
+ private final INetworkManagementService mNMS;
+
+ LegacyNetworkActivityTracker(@NonNull Context context,
+ @NonNull INetworkManagementService nms) {
+ mContext = context;
+ mNMS = nms;
+ try {
+ mNMS.registerObserver(mDataActivityObserver);
+ } catch (RemoteException e) {
+ loge("Error registering observer :" + e);
+ }
+ }
+
+ // TODO: Migrate away the dependency with INetworkManagementEventObserver.
+ private final INetworkManagementEventObserver mDataActivityObserver =
+ new BaseNetworkObserver() {
+ @Override
+ public void interfaceClassDataActivityChanged(int transportType, boolean active,
+ long tsNanos, int uid) {
+ sendDataActivityBroadcast(transportTypeToLegacyType(transportType), active,
+ tsNanos);
+ }
+ };
+
+ // This is deprecated and only to support legacy use cases.
+ private int transportTypeToLegacyType(int type) {
+ switch (type) {
+ case NetworkCapabilities.TRANSPORT_CELLULAR:
+ return ConnectivityManager.TYPE_MOBILE;
+ case NetworkCapabilities.TRANSPORT_WIFI:
+ return ConnectivityManager.TYPE_WIFI;
+ case NetworkCapabilities.TRANSPORT_BLUETOOTH:
+ return ConnectivityManager.TYPE_BLUETOOTH;
+ case NetworkCapabilities.TRANSPORT_ETHERNET:
+ return ConnectivityManager.TYPE_ETHERNET;
+ default:
+ loge("Unexpected transport in transportTypeToLegacyType: " + type);
+ }
+ return ConnectivityManager.TYPE_NONE;
+ }
+
+ public void sendDataActivityBroadcast(int deviceType, boolean active, long tsNanos) {
+ final Intent intent = new Intent(ConnectivityManager.ACTION_DATA_ACTIVITY_CHANGE);
+ intent.putExtra(ConnectivityManager.EXTRA_DEVICE_TYPE, deviceType);
+ intent.putExtra(ConnectivityManager.EXTRA_IS_ACTIVE, active);
+ intent.putExtra(ConnectivityManager.EXTRA_REALTIME_NS, tsNanos);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL,
+ RECEIVE_DATA_ACTIVITY_CHANGE,
+ null /* resultReceiver */,
+ null /* scheduler */,
+ 0 /* initialCode */,
+ null /* initialData */,
+ null /* initialExtra */);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ /**
+ * Setup data activity tracking for the given network.
+ *
+ * Every {@code setupDataActivityTracking} should be paired with a
+ * {@link #removeDataActivityTracking} for cleanup.
+ */
+ private void setupDataActivityTracking(NetworkAgentInfo networkAgent) {
+ final String iface = networkAgent.linkProperties.getInterfaceName();
+
+ final int timeout;
+ final int type;
+
+ if (networkAgent.networkCapabilities.hasTransport(
+ NetworkCapabilities.TRANSPORT_CELLULAR)) {
+ timeout = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE,
+ 10);
+ type = NetworkCapabilities.TRANSPORT_CELLULAR;
+ } else if (networkAgent.networkCapabilities.hasTransport(
+ NetworkCapabilities.TRANSPORT_WIFI)) {
+ timeout = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI,
+ 15);
+ type = NetworkCapabilities.TRANSPORT_WIFI;
+ } else {
+ return; // do not track any other networks
+ }
+
+ if (timeout > 0 && iface != null) {
+ try {
+ // TODO: Access INetd directly instead of NMS
+ mNMS.addIdleTimer(iface, timeout, type);
+ } catch (Exception e) {
+ // You shall not crash!
+ loge("Exception in setupDataActivityTracking " + e);
+ }
+ }
+ }
+
+ /**
+ * Remove data activity tracking when network disconnects.
+ */
+ private void removeDataActivityTracking(NetworkAgentInfo networkAgent) {
+ final String iface = networkAgent.linkProperties.getInterfaceName();
+ final NetworkCapabilities caps = networkAgent.networkCapabilities;
+
+ if (iface != null && (caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
+ || caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))) {
+ try {
+ // the call fails silently if no idle timer setup for this interface
+ // TODO: Access INetd directly instead of NMS
+ mNMS.removeIdleTimer(iface);
+ } catch (Exception e) {
+ // You shall not crash!
+ loge("Exception in removeDataActivityTracking " + e);
+ }
+ }
+ }
+
+ /**
+ * Update data activity tracking when network state is updated.
+ */
+ public void updateDataActivityTracking(NetworkAgentInfo newNetwork,
+ NetworkAgentInfo oldNetwork) {
+ if (newNetwork != null) {
+ setupDataActivityTracking(newNetwork);
+ }
+ if (oldNetwork != null) {
+ removeDataActivityTracking(oldNetwork);
+ }
+ }
+ }
+ /**
+ * Registers {@link QosSocketFilter} with {@link IQosCallback}.
+ *
+ * @param socketInfo the socket information
+ * @param callback the callback to register
+ */
+ @Override
+ public void registerQosSocketCallback(@NonNull final QosSocketInfo socketInfo,
+ @NonNull final IQosCallback callback) {
+ final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(socketInfo.getNetwork());
+ if (nai == null || nai.networkCapabilities == null) {
+ try {
+ callback.onError(QosCallbackException.EX_TYPE_FILTER_NETWORK_RELEASED);
+ } catch (final RemoteException ex) {
+ loge("registerQosCallbackInternal: RemoteException", ex);
+ }
+ return;
+ }
+ registerQosCallbackInternal(new QosSocketFilter(socketInfo), callback, nai);
+ }
+
+ /**
+ * Register a {@link IQosCallback} with base {@link QosFilter}.
+ *
+ * @param filter the filter to register
+ * @param callback the callback to register
+ * @param nai the agent information related to the filter's network
+ */
+ @VisibleForTesting
+ public void registerQosCallbackInternal(@NonNull final QosFilter filter,
+ @NonNull final IQosCallback callback, @NonNull final NetworkAgentInfo nai) {
+ if (filter == null) throw new IllegalArgumentException("filter must be non-null");
+ if (callback == null) throw new IllegalArgumentException("callback must be non-null");
+
+ if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
+ enforceConnectivityRestrictedNetworksPermission();
+ }
+ mQosCallbackTracker.registerCallback(callback, filter, nai);
+ }
+
+ /**
+ * Unregisters the given callback.
+ *
+ * @param callback the callback to unregister
+ */
+ @Override
+ public void unregisterQosCallback(@NonNull final IQosCallback callback) {
+ mQosCallbackTracker.unregisterCallback(callback);
+ }
}
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 1ea4a89..d30a640 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -405,6 +405,9 @@
if (mLastPowerStateFromRadio != powerState) {
mLastPowerStateFromRadio = powerState;
try {
+ // TODO: The interface changes that comes from netd are handled by BSS itself.
+ // There are still events caused by setting or removing idle timer, so keep
+ // reporting from here until setting idler timer moved to CS.
getBatteryStats().noteMobileRadioPowerState(powerState, tsNanos, uid);
} catch (RemoteException e) {
}
@@ -415,6 +418,9 @@
if (mLastPowerStateFromWifi != powerState) {
mLastPowerStateFromWifi = powerState;
try {
+ // TODO: The interface changes that comes from netd are handled by BSS itself.
+ // There are still events caused by setting or removing idle timer, so keep
+ // reporting from here until setting idler timer moved to CS.
getBatteryStats().noteWifiRadioPowerState(powerState, tsNanos, uid);
} catch (RemoteException e) {
}
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index e99bb24..0aee780 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -16,10 +16,14 @@
package com.android.server;
+import static android.app.ActivityManager.RunningServiceInfo;
+import static android.app.ActivityManager.RunningTaskInfo;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.OP_CAMERA;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
+import static android.content.Intent.EXTRA_PACKAGE_NAME;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.hardware.SensorPrivacyManager.EXTRA_SENSOR;
import static android.os.UserHandle.USER_SYSTEM;
import static android.service.SensorPrivacyIndividualEnabledSensorProto.CAMERA;
import static android.service.SensorPrivacyIndividualEnabledSensorProto.MICROPHONE;
@@ -28,15 +32,20 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.ActivityTaskManager;
import android.app.AppOpsManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.graphics.drawable.Icon;
import android.hardware.ISensorPrivacyListener;
import android.hardware.ISensorPrivacyManager;
@@ -55,10 +64,12 @@
import android.service.SensorPrivacyIndividualEnabledSensorProto;
import android.service.SensorPrivacyServiceDumpProto;
import android.service.SensorPrivacyUserProto;
+import android.text.Html;
import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.IndentingPrintWriter;
import android.util.Log;
+import android.util.Pair;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.TypedXmlPullParser;
@@ -66,6 +77,7 @@
import android.util.Xml;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FunctionalUtils;
@@ -83,6 +95,8 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
@@ -91,6 +105,8 @@
private static final String TAG = "SensorPrivacyService";
+ private static final int SUPPRESS_REMINDERS_REMOVAL_DELAY_MILLIS = 2000;
+
/** Version number indicating compatibility parsing the persisted file */
private static final int CURRENT_PERSISTENCE_VERSION = 1;
/** Version number indicating the persisted data needs upgraded to match new internal data
@@ -110,8 +126,6 @@
private static final String SENSOR_PRIVACY_CHANNEL_ID = Context.SENSOR_PRIVACY_SERVICE;
private static final String ACTION_DISABLE_INDIVIDUAL_SENSOR_PRIVACY =
SensorPrivacyService.class.getName() + ".action.disable_sensor_privacy";
- private static final String EXTRA_SENSOR = SensorPrivacyService.class.getName()
- + ".extra.sensor";
// These are associated with fields that existed for older persisted versions of files
private static final int VER0_ENABLED = 0;
@@ -121,11 +135,15 @@
private final SensorPrivacyServiceImpl mSensorPrivacyServiceImpl;
private final UserManagerInternal mUserManagerInternal;
+ private final ActivityManager mActivityManager;
+ private final ActivityTaskManager mActivityTaskManager;
public SensorPrivacyService(Context context) {
super(context);
mUserManagerInternal = getLocalService(UserManagerInternal.class);
mSensorPrivacyServiceImpl = new SensorPrivacyServiceImpl(context);
+ mActivityManager = context.getSystemService(ActivityManager.class);
+ mActivityTaskManager = context.getSystemService(ActivityTaskManager.class);
}
@Override
@@ -134,7 +152,8 @@
}
class SensorPrivacyServiceImpl extends ISensorPrivacyManager.Stub implements
- AppOpsManager.OnOpNotedListener, AppOpsManager.OnOpStartedListener {
+ AppOpsManager.OnOpNotedListener, AppOpsManager.OnOpStartedListener,
+ IBinder.DeathRecipient {
private final SensorPrivacyHandler mHandler;
private final Context mContext;
@@ -146,6 +165,15 @@
@GuardedBy("mLock")
private SparseArray<SparseBooleanArray> mIndividualEnabled = new SparseArray<>();
+ /**
+ * Packages for which not to show sensor use reminders.
+ *
+ * <Package, User> -> list of suppressor tokens
+ */
+ @GuardedBy("mLock")
+ private ArrayMap<Pair<String, UserHandle>, ArrayList<IBinder>> mSuppressReminders =
+ new ArrayMap<>();
+
SensorPrivacyServiceImpl(Context context) {
mContext = context;
mHandler = new SensorPrivacyHandler(FgThread.get().getLooper(), mContext);
@@ -166,7 +194,9 @@
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- setIndividualSensorPrivacy(intent.getIntExtra(Intent.EXTRA_USER_ID, -1),
+ setIndividualSensorPrivacy(
+ ((UserHandle) intent.getParcelableExtra(
+ Intent.EXTRA_USER)).getIdentifier(),
intent.getIntExtra(EXTRA_SENSOR, UNKNOWN), false);
}
}, new IntentFilter(ACTION_DISABLE_INDIVIDUAL_SENSOR_PRIVACY));
@@ -192,7 +222,12 @@
sensor = CAMERA;
}
- onSensorUseStarted(uid, packageName, sensor);
+ long token = Binder.clearCallingIdentity();
+ try {
+ onSensorUseStarted(uid, packageName, sensor);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
/**
@@ -203,31 +238,138 @@
* @param sensor The sensor that is attempting to be used
*/
private void onSensorUseStarted(int uid, String packageName, int sensor) {
- int userId = UserHandle.getUserId(uid);
- if (!isIndividualSensorPrivacyEnabled(userId, sensor)) {
+ UserHandle user = UserHandle.getUserHandleForUid(uid);
+ if (!isIndividualSensorPrivacyEnabled(user.getIdentifier(), sensor)) {
return;
}
- // TODO moltmann: Use dialog instead of notification if we can determine the activity
- // which triggered this usage
+ synchronized (mLock) {
+ if (mSuppressReminders.containsKey(new Pair<>(packageName, user))) {
+ Log.d(TAG,
+ "Suppressed sensor privacy reminder for " + packageName + "/" + user);
+ return;
+ }
+ }
- // TODO evanseverson: - Implement final UX for notification
- // - Finalize strings and icons and add as resources
+ // TODO: Handle reminders with multiple sensors
- int icon;
- CharSequence notificationMessage;
+ // - If we have a likely activity that triggered the sensor use overlay a dialog over
+ // it. This should be the most common case.
+ // - If there is no use visible entity that triggered the sensor don't show anything as
+ // this is - from the point of the user - a background usage
+ // - Otherwise show a notification as we are not quite sure where to display the dialog.
+
+ List<RunningTaskInfo> tasksOfPackageUsingSensor = new ArrayList<>();
+
+ List<RunningTaskInfo> tasks = mActivityTaskManager.getTasks(Integer.MAX_VALUE);
+ int numTasks = tasks.size();
+ for (int taskNum = 0; taskNum < numTasks; taskNum++) {
+ RunningTaskInfo task = tasks.get(taskNum);
+
+ if (task.isVisible && task.topActivity.getPackageName().equals(packageName)) {
+ if (task.isFocused) {
+ // There is the one focused activity
+ showSensorUseReminderDialog(task.taskId, user, packageName, sensor);
+ return;
+ }
+
+ tasksOfPackageUsingSensor.add(task);
+ }
+ }
+
+ // TODO: Test this case
+ // There is one or more non-focused activity
+ if (tasksOfPackageUsingSensor.size() == 1) {
+ showSensorUseReminderDialog(tasksOfPackageUsingSensor.get(0).taskId, user,
+ packageName, sensor);
+ return;
+ } else if (tasksOfPackageUsingSensor.size() > 1) {
+ showSensorUseReminderNotification(user, packageName, sensor);
+ return;
+ }
+
+ // TODO: Test this case
+ // Check if there is a foreground service for this package
+ List<RunningServiceInfo> services = mActivityManager.getRunningServices(
+ Integer.MAX_VALUE);
+ int numServices = services.size();
+ for (int serviceNum = 0; serviceNum < numServices; serviceNum++) {
+ RunningServiceInfo service = services.get(serviceNum);
+
+ if (service.foreground && service.service.getPackageName().equals(packageName)) {
+ showSensorUseReminderNotification(user, packageName, sensor);
+ return;
+ }
+ }
+
+ Log.i(TAG, packageName + "/" + uid + " started using sensor " + sensor
+ + " but no activity or foreground service was running. The user will not be"
+ + " informed. System components should check if sensor privacy is enabled for"
+ + " the sensor before accessing it.");
+ }
+
+ /**
+ * Show a dialog that informs the user that a sensor use or a blocked sensor started.
+ * The user can then react to this event.
+ *
+ * @param taskId The task this dialog should be overlaid on.
+ * @param user The user of the package using the sensor.
+ * @param packageName The name of the package using the sensor.
+ * @param sensor The sensor that is being used.
+ */
+ private void showSensorUseReminderDialog(int taskId, @NonNull UserHandle user,
+ @NonNull String packageName, int sensor) {
+ Intent dialogIntent = new Intent();
+ dialogIntent.setComponent(ComponentName.unflattenFromString(
+ mContext.getResources().getString(
+ R.string.config_sensorUseStartedActivity)));
+
+ ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchTaskId(taskId);
+ options.setTaskOverlay(true, true);
+
+ dialogIntent.putExtra(EXTRA_PACKAGE_NAME, packageName);
+ dialogIntent.putExtra(EXTRA_SENSOR, sensor);
+
+ mContext.startActivityAsUser(dialogIntent, options.toBundle(), user);
+ }
+
+ /**
+ * Show a notification that informs the user that a sensor use or a blocked sensor started.
+ * The user can then react to this event.
+ *
+ * @param user The user of the package using the sensor.
+ * @param packageName The name of the package using the sensor.
+ * @param sensor The sensor that is being used.
+ */
+ private void showSensorUseReminderNotification(@NonNull UserHandle user,
+ @NonNull String packageName, int sensor) {
+ int iconRes;
+ int messageRes;
+
+ CharSequence packageLabel;
+ try {
+ packageLabel = getUiContext().getPackageManager()
+ .getApplicationInfoAsUser(packageName, 0, user)
+ .loadLabel(mContext.getPackageManager());
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Cannot show sensor use notification for " + packageName);
+ return;
+ }
+
if (sensor == MICROPHONE) {
- icon = com.android.internal.R.drawable.ic_mic;
- notificationMessage = "Microphone is muted because of sensor privacy";
+ iconRes = R.drawable.ic_mic_blocked;
+ messageRes = R.string.sensor_privacy_start_use_mic_notification_content;
} else {
- icon = com.android.internal.R.drawable.ic_camera;
- notificationMessage = "Camera is blocked because of sensor privacy";
+ iconRes = R.drawable.ic_camera_blocked;
+ messageRes = R.string.sensor_privacy_start_use_camera_notification_content;
}
NotificationManager notificationManager =
mContext.getSystemService(NotificationManager.class);
NotificationChannel channel = new NotificationChannel(
- SENSOR_PRIVACY_CHANNEL_ID, "Sensor privacy",
+ SENSOR_PRIVACY_CHANNEL_ID,
+ getUiContext().getString(R.string.sensor_privacy_notification_channel_label),
NotificationManager.IMPORTANCE_HIGH);
channel.setSound(null, null);
channel.setBypassDnd(true);
@@ -236,18 +378,21 @@
notificationManager.createNotificationChannel(channel);
+ Icon icon = Icon.createWithResource(getUiContext().getResources(), iconRes);
notificationManager.notify(sensor,
new Notification.Builder(mContext, SENSOR_PRIVACY_CHANNEL_ID)
- .setContentTitle(notificationMessage)
+ .setContentTitle(Html.fromHtml(getUiContext().getString(messageRes,
+ packageLabel),0))
.setSmallIcon(icon)
- .addAction(new Notification.Action.Builder(
- Icon.createWithResource(mContext, icon),
- "Disable sensor privacy",
+ .setLargeIcon(icon)
+ .addAction(new Notification.Action.Builder(icon,
+ getUiContext().getString(
+ R.string.sensor_privacy_start_use_dialog_turn_on_button),
PendingIntent.getBroadcast(mContext, sensor,
new Intent(ACTION_DISABLE_INDIVIDUAL_SENSOR_PRIVACY)
.setPackage(mContext.getPackageName())
.putExtra(EXTRA_SENSOR, sensor)
- .putExtra(Intent.EXTRA_USER_ID, userId),
+ .putExtra(Intent.EXTRA_USER, user),
PendingIntent.FLAG_IMMUTABLE
| PendingIntent.FLAG_UPDATE_CURRENT))
.build())
@@ -587,6 +732,88 @@
}
@Override
+ public void suppressIndividualSensorPrivacyReminders(int userId, String packageName,
+ IBinder token, boolean suppress) {
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(token);
+
+ Pair<String, UserHandle> key = new Pair<>(packageName, UserHandle.of(userId));
+
+ synchronized (mLock) {
+ if (suppress) {
+ try {
+ token.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not suppress sensor use reminder", e);
+ return;
+ }
+
+ ArrayList<IBinder> suppressPackageReminderTokens = mSuppressReminders.get(key);
+ if (suppressPackageReminderTokens == null) {
+ suppressPackageReminderTokens = new ArrayList<>(1);
+ mSuppressReminders.put(key, suppressPackageReminderTokens);
+ }
+
+ suppressPackageReminderTokens.add(token);
+ } else {
+ mHandler.postDelayed(PooledLambda.obtainRunnable(
+ SensorPrivacyServiceImpl::removeSuppressPackageReminderToken,
+ this, key, token),
+ SUPPRESS_REMINDERS_REMOVAL_DELAY_MILLIS);
+ }
+ }
+ }
+
+ /**
+ * Remove a sensor use reminder suppression token.
+ *
+ * @param key Key the token is in
+ * @param token The token to remove
+ */
+ private void removeSuppressPackageReminderToken(@NonNull Pair<String, UserHandle> key,
+ @NonNull IBinder token) {
+ synchronized (mLock) {
+ ArrayList<IBinder> suppressPackageReminderTokens =
+ mSuppressReminders.get(key);
+ if (suppressPackageReminderTokens == null) {
+ Log.e(TAG, "No tokens for " + key);
+ return;
+ }
+
+ boolean wasRemoved = suppressPackageReminderTokens.remove(token);
+ if (wasRemoved) {
+ token.unlinkToDeath(this, 0);
+
+ if (suppressPackageReminderTokens.isEmpty()) {
+ mSuppressReminders.remove(key);
+ }
+ } else {
+ Log.w(TAG, "Could not remove sensor use reminder suppression token " + token
+ + " from " + key);
+ }
+ }
+ }
+
+ /**
+ * A owner of a suppressor token died. Clean up.
+ *
+ * @param token The token that is invalid now.
+ */
+ @Override
+ public void binderDied(@NonNull IBinder token) {
+ synchronized (mLock) {
+ for (Pair<String, UserHandle> key : mSuppressReminders.keySet()) {
+ removeSuppressPackageReminderToken(key, token);
+ }
+ }
+ }
+
+ @Override
+ public void binderDied() {
+ // Handled in binderDied(IBinder)
+ }
+
+ @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Objects.requireNonNull(fd);
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 2fdc796..76db019 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -31,16 +31,19 @@
import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.IBinder;
import android.os.Looper;
import android.os.ParcelUuid;
import android.os.PersistableBundle;
import android.os.Process;
+import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.os.UserHandle;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
+import android.util.Log;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -155,6 +158,11 @@
@NonNull private final PersistableBundleUtils.LockingReadWriteHelper mConfigDiskRwHelper;
+ @GuardedBy("mLock")
+ @NonNull
+ private final Map<IBinder, PolicyListenerBinderDeath> mRegisteredPolicyListeners =
+ new ArrayMap<>();
+
@VisibleForTesting(visibility = Visibility.PRIVATE)
VcnManagementService(@NonNull Context context, @NonNull Dependencies deps) {
mContext = requireNonNull(context, "Missing context");
@@ -497,19 +505,60 @@
}
}
+ /** Binder death recipient used to remove a registered policy listener. */
+ private class PolicyListenerBinderDeath implements Binder.DeathRecipient {
+ @NonNull private final IVcnUnderlyingNetworkPolicyListener mListener;
+
+ PolicyListenerBinderDeath(@NonNull IVcnUnderlyingNetworkPolicyListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void binderDied() {
+ Log.e(TAG, "app died without removing VcnUnderlyingNetworkPolicyListener");
+ removeVcnUnderlyingNetworkPolicyListener(mListener);
+ }
+ }
+
/** Adds the provided listener for receiving VcnUnderlyingNetworkPolicy updates. */
+ @GuardedBy("mLock")
@Override
public void addVcnUnderlyingNetworkPolicyListener(
- IVcnUnderlyingNetworkPolicyListener listener) {
- // TODO(b/175739863): implement policy listener registration
- throw new UnsupportedOperationException("Not yet implemented");
+ @NonNull IVcnUnderlyingNetworkPolicyListener listener) {
+ requireNonNull(listener, "listener was null");
+
+ mContext.enforceCallingPermission(
+ android.Manifest.permission.NETWORK_FACTORY,
+ "Must have permission NETWORK_FACTORY to register a policy listener");
+
+ PolicyListenerBinderDeath listenerBinderDeath = new PolicyListenerBinderDeath(listener);
+
+ synchronized (mLock) {
+ mRegisteredPolicyListeners.put(listener.asBinder(), listenerBinderDeath);
+
+ try {
+ listener.asBinder().linkToDeath(listenerBinderDeath, 0 /* flags */);
+ } catch (RemoteException e) {
+ // Remote binder already died - cleanup registered Listener
+ listenerBinderDeath.binderDied();
+ }
+ }
}
/** Removes the provided listener from receiving VcnUnderlyingNetworkPolicy updates. */
+ @GuardedBy("mLock")
@Override
public void removeVcnUnderlyingNetworkPolicyListener(
- IVcnUnderlyingNetworkPolicyListener listener) {
- // TODO(b/175739863): implement policy listener unregistration
- throw new UnsupportedOperationException("Not yet implemented");
+ @NonNull IVcnUnderlyingNetworkPolicyListener listener) {
+ requireNonNull(listener, "listener was null");
+
+ synchronized (mLock) {
+ PolicyListenerBinderDeath listenerBinderDeath =
+ mRegisteredPolicyListeners.remove(listener.asBinder());
+
+ if (listenerBinderDeath != null) {
+ listener.asBinder().unlinkToDeath(listenerBinderDeath, 0 /* flags */);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 2c83da5..a6a00fb 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -129,8 +129,10 @@
Slog.d(TAG, "Vibration thread finished with status " + status);
}
synchronized (mLock) {
- mThread = null;
- reportFinishVibrationLocked(status);
+ if (mCurrentVibration != null && mCurrentVibration.id == vibrationId) {
+ mThread = null;
+ reportFinishVibrationLocked(status);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index fcb32a1..e476ca9 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -5373,7 +5373,7 @@
for (int i = mAm.mProcessList.mLruProcesses.size() - 1; i >= 0; i--) {
final ProcessRecord pr = mAm.mProcessList.mLruProcesses.get(i);
if (pr.uid == callingUid) {
- if (pr.getWindowProcessController().areBackgroundActivityStartsAllowed()) {
+ if (pr.getWindowProcessController().areBackgroundFgsStartsAllowed()) {
ret = FGS_FEATURE_ALLOWED_BY_ACTIVITY_STARTER;
break;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index aada21d..df90a40 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -180,6 +180,7 @@
import android.app.usage.UsageStatsManager;
import android.app.usage.UsageStatsManagerInternal;
import android.appwidget.AppWidgetManager;
+import android.compat.Compatibility;
import android.content.AutofillOptions;
import android.content.BroadcastReceiver;
import android.content.ComponentCallbacks2;
@@ -303,6 +304,7 @@
import com.android.internal.app.ProcessMap;
import com.android.internal.app.SystemUserHomeActivity;
import com.android.internal.app.procstats.ProcessStats;
+import com.android.internal.compat.CompatibilityChangeConfig;
import com.android.internal.content.PackageHelper;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
@@ -2533,11 +2535,8 @@
Slog.d(TAG_SWITCH, "updateActivityUsageStats: comp="
+ activity + " hash=" + appToken.hashCode() + " event=" + event);
}
- synchronized (this) {
- if (mUsageStatsService != null) {
- mUsageStatsService.reportEvent(activity, userId, event, appToken.hashCode(),
- taskRoot);
- }
+ if (mUsageStatsService != null) {
+ mUsageStatsService.reportEvent(activity, userId, event, appToken.hashCode(), taskRoot);
}
if (mContentCaptureService != null && (event == Event.ACTIVITY_PAUSED
|| event == Event.ACTIVITY_RESUMED || event == Event.ACTIVITY_STOPPED
@@ -2557,10 +2556,8 @@
Slog.d(TAG_SWITCH, "updateActivityUsageStats: package="
+ packageName + " event=" + event);
}
- synchronized (this) {
- if (mUsageStatsService != null) {
- mUsageStatsService.reportEvent(packageName, userId, event);
- }
+ if (mUsageStatsService != null) {
+ mUsageStatsService.reportEvent(packageName, userId, event);
}
}
@@ -2575,12 +2572,10 @@
Slog.d(TAG_SWITCH, "updateForegroundServiceUsageStats: comp="
+ service + " started=" + started);
}
- synchronized (this) {
- if (mUsageStatsService != null) {
- mUsageStatsService.reportEvent(service, userId,
- started ? UsageEvents.Event.FOREGROUND_SERVICE_START
- : UsageEvents.Event.FOREGROUND_SERVICE_STOP, 0, null);
- }
+ if (mUsageStatsService != null) {
+ mUsageStatsService.reportEvent(service, userId,
+ started ? UsageEvents.Event.FOREGROUND_SERVICE_START
+ : UsageEvents.Event.FOREGROUND_SERVICE_STOP, 0, null);
}
}
@@ -6098,7 +6093,7 @@
return pfd;
}
- void reportGlobalUsageEventLocked(int event) {
+ void reportGlobalUsageEvent(int event) {
final int currentUserId = mUserController.getCurrentUserId();
mUsageStatsService.reportEvent(Event.DEVICE_EVENT_PACKAGE_NAME, currentUserId, event);
int[] profiles = mUserController.getCurrentProfileIds();
@@ -6112,8 +6107,8 @@
}
}
- void reportCurWakefulnessUsageEventLocked() {
- reportGlobalUsageEventLocked(mWakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE
+ void reportCurWakefulnessUsageEvent() {
+ reportGlobalUsageEvent(mWakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE
? UsageEvents.Event.SCREEN_INTERACTIVE
: UsageEvents.Event.SCREEN_NON_INTERACTIVE);
}
@@ -6127,7 +6122,7 @@
if (wasAwake != isAwake) {
// Also update state in a special way for running foreground services UI.
mServices.updateScreenStateLocked(isAwake);
- reportCurWakefulnessUsageEventLocked();
+ reportCurWakefulnessUsageEvent();
mActivityTaskManager.onScreenAwakeChanged(isAwake);
mOomAdjProfiler.onWakefulnessChanged(wakefulness);
}
@@ -14351,6 +14346,8 @@
if (disableHiddenApiChecks || disableTestApiChecks) {
enforceCallingPermission(android.Manifest.permission.DISABLE_HIDDEN_API_CHECKS,
"disable hidden API checks");
+
+ enableTestApiAccess(ii.packageName);
}
final long origId = Binder.clearCallingIdentity();
@@ -14518,6 +14515,25 @@
app.userId,
"finished inst");
}
+
+ disableTestApiAccess(app.info.packageName);
+ }
+
+ private void enableTestApiAccess(String packageName) {
+ if (mPlatformCompat != null) {
+ Compatibility.ChangeConfig config = new Compatibility.ChangeConfig(
+ Collections.singleton(166236554L /* VMRuntime.ALLOW_TEST_API_ACCESS */),
+ Collections.emptySet());
+ CompatibilityChangeConfig override = new CompatibilityChangeConfig(config);
+ mPlatformCompat.setOverridesForTest(override, packageName);
+ }
+ }
+
+ private void disableTestApiAccess(String packageName) {
+ if (mPlatformCompat != null) {
+ mPlatformCompat.clearOverrideForTest(166236554L /* VMRuntime.ALLOW_TEST_API_ACCESS */,
+ packageName);
+ }
}
public void finishInstrumentation(IApplicationThread target,
@@ -16506,11 +16522,9 @@
}
public void reportCurKeyguardUsageEvent(boolean keyguardShowing) {
- synchronized(ActivityManagerService.this) {
- ActivityManagerService.this.reportGlobalUsageEventLocked(keyguardShowing
- ? UsageEvents.Event.KEYGUARD_SHOWN
- : UsageEvents.Event.KEYGUARD_HIDDEN);
- }
+ ActivityManagerService.this.reportGlobalUsageEvent(keyguardShowing
+ ? UsageEvents.Event.KEYGUARD_SHOWN
+ : UsageEvents.Event.KEYGUARD_HIDDEN);
}
@Override
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index ada7eea..a3fac05 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -593,7 +593,7 @@
}
if (modemInfo != null) {
- mStats.updateMobileRadioState(modemInfo, elapsedRealtime, uptime);
+ mStats.noteModemControllerActivity(modemInfo, elapsedRealtime, uptime);
}
if (updateFlags == UPDATE_ALL) {
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 4fb7abb..b1cbb4a 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -21,6 +21,8 @@
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.net.INetworkManagementEventObserver;
+import android.net.NetworkCapabilities;
import android.os.BatteryStats;
import android.os.BatteryStatsInternal;
import android.os.BatteryUsageStats;
@@ -29,6 +31,7 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
+import android.os.INetworkManagementService;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.ParcelFormatException;
@@ -36,6 +39,7 @@
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.Process;
+import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -54,6 +58,7 @@
import android.telephony.TelephonyManager;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.BatteryStatsHelper;
import com.android.internal.os.BatteryStatsImpl;
@@ -68,6 +73,7 @@
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
import com.android.server.Watchdog;
+import com.android.server.net.BaseNetworkObserver;
import com.android.server.pm.UserManagerInternal;
import java.io.File;
@@ -123,6 +129,40 @@
private final Handler mHandler;
private final Object mLock = new Object();
+ @GuardedBy("mStats")
+ private int mLastPowerStateFromRadio = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
+ @GuardedBy("mStats")
+ private int mLastPowerStateFromWifi = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
+ private final INetworkManagementEventObserver mActivityChangeObserver =
+ new BaseNetworkObserver() {
+ @Override
+ public void interfaceClassDataActivityChanged(int transportType, boolean active,
+ long tsNanos, int uid) {
+ final int powerState = active
+ ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
+ : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
+ final long timestampNanos;
+ if (tsNanos <= 0) {
+ timestampNanos = SystemClock.elapsedRealtimeNanos();
+ } else {
+ timestampNanos = tsNanos;
+ }
+
+ switch (transportType) {
+ case NetworkCapabilities.TRANSPORT_CELLULAR:
+ noteMobileRadioPowerState(powerState, timestampNanos, uid);
+ break;
+ case NetworkCapabilities.TRANSPORT_WIFI:
+ noteWifiRadioPowerState(powerState, timestampNanos, uid);
+ break;
+ default:
+ Slog.d(TAG, "Received unexpected transport in "
+ + "interfaceClassDataActivityChanged unexpected type: "
+ + transportType);
+ }
+ }
+ };
+
/**
* Replaces the information in the given rpmStats with up-to-date information.
*/
@@ -225,6 +265,13 @@
public void systemServicesReady() {
mStats.systemServicesReady(mContext);
mWorker.systemServicesReady();
+ final INetworkManagementService nms = INetworkManagementService.Stub.asInterface(
+ ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
+ try {
+ nms.registerObserver(mActivityChangeObserver);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Could not register INetworkManagement event observer " + e);
+ }
Watchdog.getInstance().addMonitor(this);
}
@@ -1040,6 +1087,10 @@
mHandler.post(() -> {
final boolean update;
synchronized (mStats) {
+ // Ignore if no power state change.
+ if (mLastPowerStateFromRadio == powerState) return;
+
+ mLastPowerStateFromRadio = powerState;
update = mStats.noteMobileRadioPowerStateLocked(powerState, timestampNs, uid,
elapsedRealtime, uptime);
}
@@ -1343,6 +1394,10 @@
// There was a change in WiFi power state.
// Collect data now for the past activity.
synchronized (mStats) {
+ // Ignore if no power state change.
+ if (mLastPowerStateFromWifi == powerState) return;
+
+ mLastPowerStateFromWifi = powerState;
if (mStats.isOnBattery()) {
final String type =
(powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
@@ -1798,7 +1853,7 @@
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
mHandler.post(() -> {
- mStats.updateMobileRadioState(info, elapsedRealtime, uptime);
+ mStats.noteModemControllerActivity(info, elapsedRealtime, uptime);
});
}
}
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 9eb7c07..dd09a1c 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -133,7 +133,7 @@
static final int REPORT_UNFREEZE_MSG = 4;
//TODO:change this static definition into a configurable flag.
- static final int FREEZE_TIMEOUT_MS = 10000;
+ static final long FREEZE_TIMEOUT_MS = 600000;
static final int DO_FREEZE = 1;
static final int REPORT_UNFREEZE = 2;
diff --git a/services/core/java/com/android/server/am/PreBootBroadcaster.java b/services/core/java/com/android/server/am/PreBootBroadcaster.java
index f20b3a1..60b2467 100644
--- a/services/core/java/com/android/server/am/PreBootBroadcaster.java
+++ b/services/core/java/com/android/server/am/PreBootBroadcaster.java
@@ -110,8 +110,12 @@
EventLogTags.writeAmPreBoot(mUserId, componentName.getPackageName());
mIntent.setComponent(componentName);
- final long duration = LocalServices.getService(ActivityManagerInternal.class)
- .getBootTimeTempAllowListDuration();
+ long duration = 10_000;
+ final ActivityManagerInternal amInternal =
+ LocalServices.getService(ActivityManagerInternal.class);
+ if (amInternal != null) {
+ duration = amInternal.getBootTimeTempAllowListDuration();
+ }
final BroadcastOptions bOptions = BroadcastOptions.makeBasic();
bOptions.setTemporaryAppWhitelistDuration(
BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 47b7e1b..2273779 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -340,12 +340,23 @@
private static final long NATIVE_HEAP_POINTER_TAGGING = 135754954; // This is a bug id.
/**
- * Enable memory tag checks in non-system apps. This flag will only have an effect on
- * hardware supporting the ARM Memory Tagging Extension (MTE).
+ * Enable asynchronous (ASYNC) memory tag checking in this process. This
+ * flag will only have an effect on hardware supporting the ARM Memory
+ * Tagging Extension (MTE).
*/
@ChangeId
@Disabled
- private static final long NATIVE_MEMORY_TAGGING = 135772972; // This is a bug id.
+ private static final long NATIVE_MEMTAG_ASYNC = 135772972; // This is a bug id.
+
+ /**
+ * Enable synchronous (SYNC) memory tag checking in this process. This flag
+ * will only have an effect on hardware supporting the ARM Memory Tagging
+ * Extension (MTE). If both NATIVE_MEMTAG_ASYNC and this option is selected,
+ * this option takes preference and MTE is enabled in SYNC mode.
+ */
+ @ChangeId
+ @Disabled
+ private static final long NATIVE_MEMTAG_SYNC = 177438394; // This is a bug id.
/**
* Enable sampled memory bug detection in the app.
@@ -1655,23 +1666,23 @@
return gidArray;
}
- private boolean shouldEnableMemoryTagging(ProcessRecord app) {
+ // Returns the memory tagging level to be enabled. If memory tagging isn't
+ // requested, returns zero.
+ private int getMemtagLevel(ProcessRecord app) {
// Ensure the hardware + kernel actually supports MTE.
if (!Zygote.nativeSupportsMemoryTagging()) {
- return false;
+ return 0;
}
- // Enable MTE for system apps if supported.
- if ((app.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
- return true;
+ if (mPlatformCompat.isChangeEnabled(NATIVE_MEMTAG_SYNC, app.info)) {
+ return Zygote.MEMORY_TAG_LEVEL_SYNC;
}
- // Enable MTE if the compat feature is enabled.
- if (mPlatformCompat.isChangeEnabled(NATIVE_MEMORY_TAGGING, app.info)) {
- return true;
+ if (mPlatformCompat.isChangeEnabled(NATIVE_MEMTAG_ASYNC, app.info)) {
+ return Zygote.MEMORY_TAG_LEVEL_ASYNC;
}
- return false;
+ return 0;
}
private boolean shouldEnableTaggedPointers(ProcessRecord app) {
@@ -1695,8 +1706,9 @@
private int decideTaggingLevel(ProcessRecord app) {
// Check MTE support first, as it should take precedence over TBI.
- if (shouldEnableMemoryTagging(app)) {
- return Zygote.MEMORY_TAG_LEVEL_ASYNC;
+ int memtagLevel = getMemtagLevel(app);
+ if (memtagLevel != 0) {
+ return memtagLevel;
}
if (shouldEnableTaggedPointers(app)) {
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 6d90eaa..3bbc837 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -2811,8 +2811,12 @@
}
private BroadcastOptions getTemporaryAppWhitelistBroadcastOptions() {
- final long duration = LocalServices.getService(ActivityManagerInternal.class)
- .getBootTimeTempAllowListDuration();
+ long duration = 10_000;
+ final ActivityManagerInternal amInternal =
+ LocalServices.getService(ActivityManagerInternal.class);
+ if (amInternal != null) {
+ duration = amInternal.getBootTimeTempAllowListDuration();
+ }
final BroadcastOptions bOptions = BroadcastOptions.makeBasic();
bOptions.setTemporaryAppWhitelistDuration(
BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
@@ -3042,15 +3046,11 @@
}
void reportGlobalUsageEventLocked(int event) {
- synchronized (mService) {
- mService.reportGlobalUsageEventLocked(event);
- }
+ mService.reportGlobalUsageEvent(event);
}
void reportCurWakefulnessUsageEvent() {
- synchronized (mService) {
- mService.reportCurWakefulnessUsageEventLocked();
- }
+ mService.reportCurWakefulnessUsageEvent();
}
void taskSupervisorRemoveUser(@UserIdInt int userId) {
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 26f5c4c..9aea7c4 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -154,6 +154,8 @@
mPreferredDeviceforComm = null;
initCommunicationStrategyId();
+
+ mSystemServer.registerUserStartedReceiver(mContext);
}
/*package*/ Context getContext() {
@@ -993,6 +995,10 @@
}
}
+ /*package*/ void broadcastStickyIntentToCurrentProfileGroup(Intent intent) {
+ mSystemServer.broadcastStickyIntentToCurrentProfileGroup(intent);
+ }
+
/*package*/ void dump(PrintWriter pw, String prefix) {
if (mBrokerHandler != null) {
pw.println(prefix + "Message handler (watch for unhandled messages):");
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 82586b8..076cbff 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -16,7 +16,6 @@
package com.android.server.audio;
import android.annotation.NonNull;
-import android.app.ActivityManager;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
@@ -37,7 +36,6 @@
import android.os.Binder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
-import android.os.UserHandle;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -1270,7 +1268,7 @@
final long ident = Binder.clearCallingIdentity();
try {
- ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_CURRENT);
+ mDeviceBroker.broadcastStickyIntentToCurrentProfileGroup(intent);
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 7115c9a..c94b48c 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -572,9 +572,9 @@
// Pre-scale for Bluetooth Absolute Volume
private float[] mPrescaleAbsoluteVolume = new float[] {
- 0.5f, // Pre-scale for index 1
- 0.7f, // Pre-scale for index 2
- 0.85f, // Pre-scale for index 3
+ 0.6f, // Pre-scale for index 1
+ 0.8f, // Pre-scale for index 2
+ 0.9f, // Pre-scale for index 3
};
private NotificationManager mNm;
@@ -5591,7 +5591,9 @@
profile, suppressNoisyIntent, a2dpVolume);
}
- /*package*/ void setMusicMute(boolean mute) {
+ /** only public for mocking/spying, do not call outside of AudioService */
+ @VisibleForTesting
+ public void setMusicMute(boolean mute) {
mStreamStates[AudioSystem.STREAM_MUSIC].muteInternally(mute);
}
@@ -7071,7 +7073,9 @@
}
}
- /*package*/ void checkMusicActive(int deviceType, String caller) {
+ /** only public for mocking/spying, do not call outside of AudioService */
+ @VisibleForTesting
+ public void checkMusicActive(int deviceType, String caller) {
if (mSafeMediaVolumeDevices.contains(deviceType)) {
sendMsg(mAudioHandler,
MSG_CHECK_MUSIC_ACTIVE,
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index 5025c4a..b1633b0 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -288,6 +288,7 @@
@GuardedBy("mAudioFocusLock")
private void removeFocusStackEntry(String clientToRemove, boolean signal,
boolean notifyFocusFollowers) {
+ AudioFocusInfo abandonSource = null;
// is the current top of the focus stack abandoning focus? (because of request, not death)
if (!mFocusStack.empty() && mFocusStack.peek().hasSameClient(clientToRemove))
{
@@ -295,9 +296,7 @@
FocusRequester fr = mFocusStack.pop();
fr.release();
if (notifyFocusFollowers) {
- final AudioFocusInfo afi = fr.toAudioFocusInfo();
- afi.clearLossReceived();
- notifyExtPolicyFocusLoss_syncAf(afi, false);
+ abandonSource = fr.toAudioFocusInfo();
}
if (signal) {
// notify the new top of the stack it gained focus
@@ -315,11 +314,19 @@
Log.i(TAG, "AudioFocus removeFocusStackEntry(): removing entry for "
+ clientToRemove);
stackIterator.remove();
+ if (notifyFocusFollowers) {
+ abandonSource = fr.toAudioFocusInfo();
+ }
// stack entry not used anymore, clear references
fr.release();
}
}
}
+ // focus followers still want to know focus was abandoned, handled as a loss
+ if (abandonSource != null) {
+ abandonSource.clearLossReceived();
+ notifyExtPolicyFocusLoss_syncAf(abandonSource, false);
+ }
if (mMultiAudioFocusEnabled && !mMultiAudioFocusList.isEmpty()) {
Iterator<FocusRequester> listIterator = mMultiAudioFocusList.iterator();
diff --git a/services/core/java/com/android/server/audio/SystemServerAdapter.java b/services/core/java/com/android/server/audio/SystemServerAdapter.java
index 68893f8..22456bc 100644
--- a/services/core/java/com/android/server/audio/SystemServerAdapter.java
+++ b/services/core/java/com/android/server/audio/SystemServerAdapter.java
@@ -18,11 +18,20 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.UserInfo;
import android.media.AudioManager;
import android.os.Binder;
import android.os.UserHandle;
+import android.os.UserManager;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.LocalServices;
import java.util.Objects;
@@ -82,4 +91,58 @@
Binder.restoreCallingIdentity(ident);
}
}
+
+ /**
+ * Send sticky broadcast to current user's profile group (including current user)
+ */
+ @VisibleForTesting
+ public void broadcastStickyIntentToCurrentProfileGroup(Intent intent) {
+ int[] profileIds = LocalServices.getService(
+ ActivityManagerInternal.class).getCurrentProfileIds();
+ for (int userId : profileIds) {
+ ActivityManager.broadcastStickyIntent(intent, userId);
+ }
+ }
+
+ /**
+ * Broadcast sticky intents when a profile is started. This is needed because newly created
+ * profiles would not receive the intents until the next state change.
+ */
+ /*package*/ void registerUserStartedReceiver(Context context) {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_USER_STARTED);
+ context.registerReceiverAsUser(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_USER_STARTED.equals(intent.getAction())) {
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+ UserHandle.USER_NULL);
+ if (userId == UserHandle.USER_NULL) {
+ return;
+ }
+
+ UserManager userManager = context.getSystemService(UserManager.class);
+ final UserInfo profileParent = userManager.getProfileParent(userId);
+ if (profileParent == null) {
+ return;
+ }
+
+ // get sticky intents from parent and broadcast them to the started profile
+ broadcastProfileParentStickyIntent(context, AudioManager.ACTION_HDMI_AUDIO_PLUG,
+ userId, profileParent.id);
+ broadcastProfileParentStickyIntent(context, AudioManager.ACTION_HEADSET_PLUG,
+ userId, profileParent.id);
+ }
+ }
+ }, UserHandle.ALL, filter, null, null);
+ }
+
+ private void broadcastProfileParentStickyIntent(Context context, String intentAction,
+ int profileId, int parentId) {
+ Intent intent = context.registerReceiverAsUser(/*receiver*/ null, UserHandle.of(parentId),
+ new IntentFilter(intentAction), /*broadcastPermission*/ null, /*scheduler*/ null);
+ if (intent != null) {
+ ActivityManager.broadcastStickyIntent(intent, profileId);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/AuthSession.java b/services/core/java/com/android/server/biometrics/AuthSession.java
index 52152ab..14292d9c 100644
--- a/services/core/java/com/android/server/biometrics/AuthSession.java
+++ b/services/core/java/com/android/server/biometrics/AuthSession.java
@@ -37,7 +37,6 @@
import android.hardware.biometrics.PromptInfo;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
-import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.IBinder;
import android.os.RemoteException;
@@ -62,8 +61,6 @@
private static final String TAG = "BiometricService/AuthSession";
private static final boolean DEBUG = false;
-
-
/*
* Defined in biometrics.proto
*/
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 3387049..614c5f1 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -815,12 +815,16 @@
final long ident = Binder.clearCallingIdentity();
try {
if (args.length > 0 && "--proto".equals(args[0])) {
+ final boolean clearSchedulerBuffer = args.length > 1
+ && "--clear-scheduler-buffer".equals(args[1]);
+ Slog.d(TAG, "ClearSchedulerBuffer: " + clearSchedulerBuffer);
final ProtoOutputStream proto = new ProtoOutputStream(fd);
proto.write(BiometricServiceStateProto.AUTH_SESSION_STATE,
mCurrentAuthSession != null ? mCurrentAuthSession.getState()
: STATE_AUTH_IDLE);
for (BiometricSensor sensor : mSensors) {
- byte[] serviceState = sensor.impl.dumpSensorServiceStateProto();
+ byte[] serviceState = sensor.impl
+ .dumpSensorServiceStateProto(clearSchedulerBuffer);
proto.write(BiometricServiceStateProto.SENSOR_SERVICE_STATES, serviceState);
}
proto.flush();
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index 5663495..3f6ae64 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -33,6 +33,7 @@
import android.util.EventLog;
import android.util.Slog;
+import com.android.server.biometrics.BiometricsProto;
import com.android.server.biometrics.Utils;
import java.util.ArrayList;
@@ -298,4 +299,9 @@
mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
}
}
+
+ @Override
+ public int getProtoEnum() {
+ return BiometricsProto.CM_AUTHENTICATE;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
index f3c37ef..8fa3bbb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
@@ -24,6 +24,8 @@
import android.os.RemoteException;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.util.NoSuchElementException;
/**
@@ -80,6 +82,12 @@
@NonNull protected Callback mCallback;
/**
+ * Returns a ClientMonitorEnum constant defined in biometrics.proto
+ * @return
+ */
+ public abstract int getProtoEnum();
+
+ /**
* @param context system_server context
* @param token a unique token for the client
* @param listener recipient of related events (e.g. authentication)
@@ -195,10 +203,16 @@
return mSensorId;
}
+ @VisibleForTesting
+ public Callback getCallback() {
+ return mCallback;
+ }
+
@Override
public String toString() {
return "{[" + mSequentialId + "] "
+ this.getClass().getSimpleName()
+ + ", " + getProtoEnum()
+ ", " + getOwnerString()
+ ", " + getCookie() + "}";
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
index aa7faf5..c86bfcb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -28,8 +28,11 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.biometrics.BiometricSchedulerProto;
+import com.android.server.biometrics.BiometricsProto;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import java.io.PrintWriter;
@@ -51,6 +54,8 @@
public class BiometricScheduler {
private static final String BASE_TAG = "BiometricScheduler";
+ // Number of recent operations to keep in our logs for dumpsys
+ private static final int LOG_NUM_RECENT_OPERATIONS = 50;
/**
* Contains all the necessary information for a HAL operation.
@@ -200,6 +205,10 @@
@VisibleForTesting @Nullable Operation mCurrentOperation;
@NonNull private final ArrayDeque<CrashState> mCrashStates;
+ private int mTotalOperationsHandled;
+ private final int mRecentOperationsLimit;
+ @NonNull private final List<Integer> mRecentOperations;
+
// Internal callback, notified when an operation is complete. Notifies the requester
// that the operation is complete, before performing internal scheduler work (such as
// starting the next client).
@@ -240,7 +249,12 @@
mCurrentOperation.mClientMonitor.getSensorId(), false /* active */);
}
+ if (mRecentOperations.size() >= mRecentOperationsLimit) {
+ mRecentOperations.remove(0);
+ }
+ mRecentOperations.add(mCurrentOperation.mClientMonitor.getProtoEnum());
mCurrentOperation = null;
+ mTotalOperationsHandled++;
startNextOperationIfIdle();
});
}
@@ -249,13 +263,15 @@
@VisibleForTesting
BiometricScheduler(@NonNull String tag,
@Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
- @NonNull IBiometricService biometricService) {
+ @NonNull IBiometricService biometricService, int recentOperationsLimit) {
mBiometricTag = tag;
mInternalCallback = new InternalCallback();
mGestureAvailabilityDispatcher = gestureAvailabilityDispatcher;
mPendingOperations = new ArrayDeque<>();
mBiometricService = biometricService;
mCrashStates = new ArrayDeque<>();
+ mRecentOperationsLimit = recentOperationsLimit;
+ mRecentOperations = new ArrayList<>();
}
/**
@@ -267,7 +283,7 @@
public BiometricScheduler(@NonNull String tag,
@Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
this(tag, gestureAvailabilityDispatcher, IBiometricService.Stub.asInterface(
- ServiceManager.getService(Context.BIOMETRIC_SERVICE)));
+ ServiceManager.getService(Context.BIOMETRIC_SERVICE)), LOG_NUM_RECENT_OPERATIONS);
}
/**
@@ -602,6 +618,24 @@
}
}
+ public byte[] dumpProtoState(boolean clearSchedulerBuffer) {
+ final ProtoOutputStream proto = new ProtoOutputStream();
+ proto.write(BiometricSchedulerProto.CURRENT_OPERATION, mCurrentOperation != null
+ ? mCurrentOperation.mClientMonitor.getProtoEnum() : BiometricsProto.CM_NONE);
+ proto.write(BiometricSchedulerProto.TOTAL_OPERATIONS, mTotalOperationsHandled);
+ Slog.d(getTag(), "Total operations: " + mTotalOperationsHandled);
+ for (int i = 0; i < mRecentOperations.size(); i++) {
+ Slog.d(getTag(), "Operation: " + mRecentOperations.get(i));
+ proto.write(BiometricSchedulerProto.RECENT_OPERATIONS, mRecentOperations.get(i));
+ }
+ proto.flush();
+
+ if (clearSchedulerBuffer) {
+ mRecentOperations.clear();
+ }
+ return proto.getBytes();
+ }
+
/**
* Clears the scheduler of anything work-related. This should be used for example when the
* HAL dies.
diff --git a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
index 61e7c89..da76af8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
+++ b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
@@ -160,4 +160,18 @@
mFaceServiceReceiver.onChallengeInterruptFinished(sensorId);
}
}
+
+ // Fingerprint-specific callbacks for FingerprintManager only
+
+ public void onUdfpsPointerDown(int sensorId, int cookie) throws RemoteException {
+ if (mFingerprintServiceReceiver != null) {
+ mFingerprintServiceReceiver.onUdfpsPointerDown(sensorId);
+ }
+ }
+
+ public void onUdfpsPointerUp(int sensorId, int cookie) throws RemoteException {
+ if (mFingerprintServiceReceiver != null) {
+ mFingerprintServiceReceiver.onUdfpsPointerUp(sensorId);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
index 8bf9680..8d81016 100644
--- a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
@@ -24,6 +24,8 @@
import android.os.RemoteException;
import android.util.Slog;
+import com.android.server.biometrics.BiometricsProto;
+
import java.util.Arrays;
/**
@@ -106,4 +108,9 @@
false /* enrollSuccessful */);
super.onError(error, vendorCode);
}
+
+ @Override
+ public int getProtoEnum() {
+ return BiometricsProto.CM_ENROLL;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java
index 6a622c3..741946e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java
@@ -23,6 +23,8 @@
import android.os.RemoteException;
import android.util.Slog;
+import com.android.server.biometrics.BiometricsProto;
+
public abstract class GenerateChallengeClient<T> extends HalClientMonitor<T> {
private static final String TAG = "GenerateChallengeClient";
@@ -50,4 +52,9 @@
startHalOperation();
}
+
+ @Override
+ public int getProtoEnum() {
+ return BiometricsProto.CM_GENERATE_CHALLENGE;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java b/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java
index 8529e81..ce24e5e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java
@@ -24,6 +24,7 @@
import android.util.Slog;
import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.biometrics.BiometricsProto;
import java.util.ArrayList;
import java.util.List;
@@ -166,4 +167,9 @@
}
((EnumerateConsumer) mCurrentTask).onEnumerationResult(identifier, remaining);
}
+
+ @Override
+ public int getProtoEnum() {
+ return BiometricsProto.CM_INTERNAL_CLEANUP;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java b/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java
index 2693f2f..9d19fdf 100644
--- a/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java
@@ -24,6 +24,7 @@
import android.util.Slog;
import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.biometrics.BiometricsProto;
import java.util.ArrayList;
import java.util.List;
@@ -123,4 +124,9 @@
public List<BiometricAuthenticator.Identifier> getUnknownHALTemplates() {
return mUnknownHALTemplates;
}
+
+ @Override
+ public int getProtoEnum() {
+ return BiometricsProto.CM_ENUMERATE;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/InvalidationClient.java b/services/core/java/com/android/server/biometrics/sensors/InvalidationClient.java
index 630e5ea..cede4a7 100644
--- a/services/core/java/com/android/server/biometrics/sensors/InvalidationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/InvalidationClient.java
@@ -24,6 +24,8 @@
import android.os.RemoteException;
import android.util.Slog;
+import com.android.server.biometrics.BiometricsProto;
+
import java.util.Map;
/**
@@ -70,4 +72,9 @@
public void unableToStart() {
}
+
+ @Override
+ public int getProtoEnum() {
+ return BiometricsProto.CM_INVALIDATE;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/InvalidationRequesterClient.java b/services/core/java/com/android/server/biometrics/sensors/InvalidationRequesterClient.java
index c97003b..5ba1b00 100644
--- a/services/core/java/com/android/server/biometrics/sensors/InvalidationRequesterClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/InvalidationRequesterClient.java
@@ -23,6 +23,8 @@
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IInvalidationCallback;
+import com.android.server.biometrics.BiometricsProto;
+
/**
* ClientMonitor subclass responsible for coordination of authenticatorId invalidation of other
* sensors. See {@link InvalidationClient} for the ClientMonitor subclass responsible for initiating
@@ -89,4 +91,9 @@
mBiometricManager.invalidateAuthenticatorIds(getTargetUserId(), getSensorId(),
mInvalidationCallback);
}
+
+ @Override
+ public int getProtoEnum() {
+ return BiometricsProto.CM_INVALIDATION_REQUESTER;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/LoggableMonitor.java b/services/core/java/com/android/server/biometrics/sensors/LoggableMonitor.java
index 3ca0691..edde3d4 100644
--- a/services/core/java/com/android/server/biometrics/sensors/LoggableMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/LoggableMonitor.java
@@ -67,10 +67,23 @@
return mStatsClient;
}
- private boolean isAnyFieldUnknown() {
- return mStatsModality == BiometricsProtoEnums.MODALITY_UNKNOWN
- || mStatsAction == BiometricsProtoEnums.ACTION_UNKNOWN
- || mStatsClient == BiometricsProtoEnums.CLIENT_UNKNOWN;
+ private boolean shouldSkipLogging() {
+ boolean shouldSkipLogging = (mStatsModality == BiometricsProtoEnums.MODALITY_UNKNOWN
+ || mStatsAction == BiometricsProtoEnums.ACTION_UNKNOWN);
+
+ if (mStatsModality == BiometricsProtoEnums.MODALITY_UNKNOWN) {
+ Slog.w(TAG, "Unknown field detected: MODALITY_UNKNOWN, will not report metric");
+ }
+
+ if (mStatsAction == BiometricsProtoEnums.ACTION_UNKNOWN) {
+ Slog.w(TAG, "Unknown field detected: ACTION_UNKNOWN, will not report metric");
+ }
+
+ if (mStatsClient == BiometricsProtoEnums.CLIENT_UNKNOWN) {
+ Slog.w(TAG, "Unknown field detected: CLIENT_UNKNOWN");
+ }
+
+ return shouldSkipLogging;
}
protected final void logOnAcquired(Context context, int acquiredInfo, int vendorCode,
@@ -101,7 +114,7 @@
+ ", VendorCode: " + vendorCode);
}
- if (isAnyFieldUnknown()) {
+ if (shouldSkipLogging()) {
return;
}
@@ -138,7 +151,7 @@
Slog.v(TAG, "Error latency: " + latency);
}
- if (isAnyFieldUnknown()) {
+ if (shouldSkipLogging()) {
return;
}
@@ -189,7 +202,7 @@
Slog.v(TAG, "Authentication latency: " + latency);
}
- if (isAnyFieldUnknown()) {
+ if (shouldSkipLogging()) {
return;
}
@@ -219,7 +232,7 @@
Slog.v(TAG, "Enroll latency: " + latency);
}
- if (isAnyFieldUnknown()) {
+ if (shouldSkipLogging()) {
return;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java b/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java
index 4ea48fd..e062695 100644
--- a/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java
@@ -25,6 +25,8 @@
import android.os.RemoteException;
import android.util.Slog;
+import com.android.server.biometrics.BiometricsProto;
+
import java.util.Map;
/**
@@ -90,4 +92,9 @@
mCallback.onClientFinished(this, true /* success */);
}
}
+
+ @Override
+ public int getProtoEnum() {
+ return BiometricsProto.CM_REMOVE;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java
index 187193d..90fa1b4 100644
--- a/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java
@@ -21,6 +21,8 @@
import android.hardware.biometrics.BiometricsProtoEnums;
import android.os.IBinder;
+import com.android.server.biometrics.BiometricsProto;
+
public abstract class RevokeChallengeClient<T> extends HalClientMonitor<T> {
public RevokeChallengeClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
@@ -42,4 +44,9 @@
startHalOperation();
mCallback.onClientFinished(this, true /* success */);
}
+
+ @Override
+ public int getProtoEnum() {
+ return BiometricsProto.CM_REVOKE_CHALLENGE;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
index 54ab2e5..f37cf18 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
@@ -52,8 +52,8 @@
}
@Override
- public byte[] dumpSensorServiceStateProto() throws RemoteException {
- return mFaceService.dumpSensorServiceStateProto(mSensorId);
+ public byte[] dumpSensorServiceStateProto(boolean clearSchedulerBuffer) throws RemoteException {
+ return mFaceService.dumpSensorServiceStateProto(mSensorId, clearSchedulerBuffer);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
index f055d55..1a63dde 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
@@ -147,13 +147,13 @@
}
@Override
- public byte[] dumpSensorServiceStateProto(int sensorId) {
+ public byte[] dumpSensorServiceStateProto(int sensorId, boolean clearSchedulerBuffer) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
final ProtoOutputStream proto = new ProtoOutputStream();
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider != null) {
- provider.dumpProtoState(sensorId, proto);
+ provider.dumpProtoState(sensorId, proto, clearSchedulerBuffer);
}
proto.flush();
return proto.getBytes();
@@ -405,7 +405,7 @@
final ProtoOutputStream proto = new ProtoOutputStream(fd);
for (ServiceProvider provider : mServiceProviders) {
for (FaceSensorPropertiesInternal props : provider.getSensorProperties()) {
- provider.dumpProtoState(props.sensorId, proto);
+ provider.dumpProtoState(props.sensorId, proto, false);
}
}
proto.flush();
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
index 51b427d..32428ac1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
@@ -121,7 +121,8 @@
void scheduleInternalCleanup(int sensorId, int userId);
- void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto);
+ void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto,
+ boolean clearSchedulerBuffer);
void dumpProtoMetrics(int sensorId, @NonNull FileDescriptor fd);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java
index 13bbb7e8..211d79c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java
@@ -21,6 +21,8 @@
import android.annotation.NonNull;
import android.content.Context;
import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.face.AuthenticationFrame;
+import android.hardware.biometrics.face.BaseFrame;
import android.hardware.face.Face;
import android.hardware.face.IFaceServiceReceiver;
import android.os.Binder;
@@ -180,12 +182,21 @@
mSensor.getSessionForUser(userId).mHalSessionCallback.onAuthenticationFailed();
}
+ // TODO(b/174619156): replace with notifyAuthenticationFrame and notifyEnrollmentFrame.
@Override
- public void notifyAcquired(int userId, int acquireInfo) {
+ public void notifyAcquired(int userId, int acquireInfo) {
Utils.checkPermission(mContext, TEST_BIOMETRIC);
- mSensor.getSessionForUser(userId).mHalSessionCallback
- .onAcquired((byte) acquireInfo, 0 /* vendorCode */);
+ BaseFrame data = new BaseFrame();
+ data.acquiredInfo = (byte) acquireInfo;
+
+ AuthenticationFrame authenticationFrame = new AuthenticationFrame();
+ authenticationFrame.data = data;
+
+ // TODO(b/174619156): Currently onAuthenticationFrame and onEnrollmentFrame are the same.
+ // This will need to call the correct callback once the onAcquired callback is removed.
+ mSensor.getSessionForUser(userId).mHalSessionCallback.onAuthenticationFrame(
+ authenticationFrame);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
index f09df1e..632cc4b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
@@ -22,6 +22,7 @@
import android.hardware.biometrics.BiometricFaceConstants;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.common.ICancellationSignal;
+import android.hardware.biometrics.face.EnrollmentType;
import android.hardware.biometrics.face.IFace;
import android.hardware.biometrics.face.ISession;
import android.hardware.face.Face;
@@ -114,7 +115,8 @@
try {
// TODO(b/172593978): Pass features.
- mCancellationSignal = getFreshDaemon().enroll(mSequentialId,
+ // TODO(b/174619156): Handle accessibility enrollment.
+ mCancellationSignal = getFreshDaemon().enroll(mSequentialId, EnrollmentType.DEFAULT,
HardwareAuthTokenUtils.toHardwareAuthToken(mHardwareAuthToken),
mPreviewSurface);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java
index 5fb194c..773647b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java
@@ -23,6 +23,7 @@
import android.os.RemoteException;
import android.util.Slog;
+import com.android.server.biometrics.BiometricsProto;
import com.android.server.biometrics.sensors.HalClientMonitor;
import java.util.Map;
@@ -65,4 +66,9 @@
mAuthenticatorIds.put(getTargetUserId(), authenticatorId);
mCallback.onClientFinished(this, true /* success */);
}
+
+ @Override
+ public int getProtoEnum() {
+ return BiometricsProto.CM_GET_AUTHENTICATOR_ID;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index 810489b1c..20318e3 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -571,9 +571,10 @@
}
@Override
- public void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto) {
+ public void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto,
+ boolean clearSchedulerBuffer) {
if (mSensors.contains(sensorId)) {
- mSensors.get(sensorId).dumpProtoState(sensorId, proto);
+ mSensors.get(sensorId).dumpProtoState(sensorId, proto, clearSchedulerBuffer);
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java
index f355158..71bac57 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java
@@ -25,6 +25,7 @@
import android.os.RemoteException;
import android.util.Slog;
+import com.android.server.biometrics.BiometricsProto;
import com.android.server.biometrics.HardwareAuthTokenUtils;
import com.android.server.biometrics.sensors.HalClientMonitor;
import com.android.server.biometrics.sensors.LockoutCache;
@@ -81,4 +82,9 @@
mLockoutResetDispatcher.notifyLockoutResetCallbacks(getSensorId());
mCallback.onClientFinished(this, true /* success */);
}
+
+ @Override
+ public int getProtoEnum() {
+ return BiometricsProto.CM_RESET_LOCKOUT;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
index 82ad387..9b00ba6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
@@ -22,6 +22,8 @@
import android.content.pm.UserInfo;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.ITestSession;
+import android.hardware.biometrics.face.AuthenticationFrame;
+import android.hardware.biometrics.face.EnrollmentFrame;
import android.hardware.biometrics.face.Error;
import android.hardware.biometrics.face.IFace;
import android.hardware.biometrics.face.ISession;
@@ -167,7 +169,8 @@
}
@Override
- public void onAcquired(byte info, int vendorCode) {
+ public void onAuthenticationFrame(AuthenticationFrame frame) {
+ // TODO(b/174619156): propagate the frame to an AuthenticationClient
mHandler.post(() -> {
final BaseClientMonitor client = mScheduler.getCurrentClient();
if (!(client instanceof AcquisitionClient)) {
@@ -177,7 +180,23 @@
}
final AcquisitionClient<?> acquisitionClient = (AcquisitionClient<?>) client;
- acquisitionClient.onAcquired(info, vendorCode);
+ acquisitionClient.onAcquired(frame.data.acquiredInfo, frame.data.vendorCode);
+ });
+ }
+
+ @Override
+ public void onEnrollmentFrame(EnrollmentFrame frame) {
+ // TODO(b/174619156): propagate the frame to an EnrollmentClient
+ mHandler.post(() -> {
+ final BaseClientMonitor client = mScheduler.getCurrentClient();
+ if (!(client instanceof AcquisitionClient)) {
+ Slog.e(mTag, "onAcquired for non-acquisition client: "
+ + Utils.getClientName(client));
+ return;
+ }
+
+ final AcquisitionClient<?> acquisitionClient = (AcquisitionClient<?>) client;
+ acquisitionClient.onAcquired(frame.data.acquiredInfo, frame.data.vendorCode);
});
}
@@ -467,12 +486,13 @@
mTestHalEnabled = enabled;
}
- void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto) {
+ void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto,
+ boolean clearSchedulerBuffer) {
final long sensorToken = proto.start(SensorServiceStateProto.SENSOR_STATES);
proto.write(SensorStateProto.SENSOR_ID, mSensorProperties.sensorId);
proto.write(SensorStateProto.MODALITY, SensorStateProto.FACE);
- proto.write(SensorStateProto.IS_BUSY, mScheduler.getCurrentClient() != null);
+ proto.write(SensorStateProto.SCHEDULER, mScheduler.dumpProtoState(clearSchedulerBuffer));
for (UserInfo user : UserManager.get(mContext).getUsers()) {
final int userId = user.getUserHandle().getIdentifier();
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestHal.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestHal.java
index 34bf9bc..dc1efa0 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestHal.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestHal.java
@@ -49,8 +49,8 @@
}
@Override
- public ICancellationSignal enroll(int cookie, HardwareAuthToken hat,
- NativeHandle previewSurface) {
+ public ICancellationSignal enroll(int cookie, byte enrollmentType,
+ HardwareAuthToken hat, NativeHandle previewSurface) {
return null;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestSession.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestSession.java
index 50483d9..189c726 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestSession.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestSession.java
@@ -50,7 +50,7 @@
}
@Override
- public ICancellationSignal enroll(int cookie, HardwareAuthToken hat,
+ public ICancellationSignal enroll(int cookie, byte enrollmentType, HardwareAuthToken hat,
NativeHandle previewSurface) {
return null;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
index 5e7ddeb..7010d96 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
@@ -767,12 +767,13 @@
}
@Override
- public void dumpProtoState(int sensorId, ProtoOutputStream proto) {
+ public void dumpProtoState(int sensorId, ProtoOutputStream proto,
+ boolean clearSchedulerBuffer) {
final long sensorToken = proto.start(SensorServiceStateProto.SENSOR_STATES);
proto.write(SensorStateProto.SENSOR_ID, mSensorProperties.sensorId);
proto.write(SensorStateProto.MODALITY, SensorStateProto.FACE);
- proto.write(SensorStateProto.IS_BUSY, mScheduler.getCurrentClient() != null);
+ proto.write(SensorStateProto.SCHEDULER, mScheduler.dumpProtoState(clearSchedulerBuffer));
for (UserInfo user : UserManager.get(mContext).getUsers()) {
final int userId = user.getUserHandle().getIdentifier();
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java
index 442303b..722a3b8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java
@@ -27,6 +27,7 @@
import android.os.RemoteException;
import android.util.Slog;
+import com.android.server.biometrics.BiometricsProto;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.HalClientMonitor;
@@ -88,4 +89,9 @@
boolean getValue() {
return mValue;
}
+
+ @Override
+ public int getProtoEnum() {
+ return BiometricsProto.CM_GET_FEATURE;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceResetLockoutClient.java
index e0548e0..14a4648 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceResetLockoutClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceResetLockoutClient.java
@@ -23,6 +23,7 @@
import android.os.RemoteException;
import android.util.Slog;
+import com.android.server.biometrics.BiometricsProto;
import com.android.server.biometrics.sensors.HalClientMonitor;
import java.util.ArrayList;
@@ -71,4 +72,9 @@
mCallback.onClientFinished(this, false /* success */);
}
}
+
+ @Override
+ public int getProtoEnum() {
+ return BiometricsProto.CM_RESET_LOCKOUT;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceSetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceSetFeatureClient.java
index 4356043..6290e00 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceSetFeatureClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceSetFeatureClient.java
@@ -25,6 +25,7 @@
import android.os.RemoteException;
import android.util.Slog;
+import com.android.server.biometrics.BiometricsProto;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.HalClientMonitor;
@@ -88,4 +89,9 @@
mCallback.onClientFinished(this, false /* success */);
}
}
+
+ @Override
+ public int getProtoEnum() {
+ return BiometricsProto.CM_SET_FEATURE;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java
index 0e72f94..70e2033 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java
@@ -24,6 +24,7 @@
import android.os.RemoteException;
import android.util.Slog;
+import com.android.server.biometrics.BiometricsProto;
import com.android.server.biometrics.sensors.HalClientMonitor;
import java.io.File;
@@ -91,4 +92,9 @@
mCallback.onClientFinished(this, false /* success */);
}
}
+
+ @Override
+ public int getProtoEnum() {
+ return BiometricsProto.CM_UPDATE_ACTIVE_USER;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
index 312a3ba..34a9099 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
@@ -53,8 +53,8 @@
}
@Override
- public byte[] dumpSensorServiceStateProto() throws RemoteException {
- return mFingerprintService.dumpSensorServiceStateProto(mSensorId);
+ public byte[] dumpSensorServiceStateProto(boolean clearSchedulerBuffer) throws RemoteException {
+ return mFingerprintService.dumpSensorServiceStateProto(mSensorId, clearSchedulerBuffer);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index d541eb3..0265cb9 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -116,13 +116,13 @@
}
@Override
- public byte[] dumpSensorServiceStateProto(int sensorId) {
+ public byte[] dumpSensorServiceStateProto(int sensorId, boolean clearSchedulerBuffer) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
final ProtoOutputStream proto = new ProtoOutputStream();
final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider != null) {
- provider.dumpProtoState(sensorId, proto);
+ provider.dumpProtoState(sensorId, proto, clearSchedulerBuffer);
}
proto.flush();
return proto.getBytes();
@@ -419,7 +419,7 @@
for (ServiceProvider provider : mServiceProviders) {
for (FingerprintSensorPropertiesInternal props
: provider.getSensorProperties()) {
- provider.dumpProtoState(props.sensorId, proto);
+ provider.dumpProtoState(props.sensorId, proto, false);
}
}
proto.flush();
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
index 272e2b2..d3b5b5a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
@@ -128,7 +128,8 @@
void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller);
- void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto);
+ void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto,
+ boolean clearSchedulerBuffer);
void dumpProtoMetrics(int sensorId, @NonNull FileDescriptor fd);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
index e95447b..c2a30be 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
@@ -96,6 +96,16 @@
public void onChallengeGenerated(int sensorId, long challenge) {
}
+
+ @Override
+ public void onUdfpsPointerDown(int sensorId) {
+
+ }
+
+ @Override
+ public void onUdfpsPointerUp(int sensorId) {
+
+ }
};
BiometricTestSessionImpl(@NonNull Context context, int sensorId,
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index c413c8b..bd57fea 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -117,6 +117,9 @@
public void onPointerDown(int x, int y, float minor, float major) {
try {
getFreshDaemon().onPointerDown(0 /* pointerId */, x, y, minor, major);
+ if (getListener() != null) {
+ getListener().onUdfpsPointerDown(getSensorId(), getCookie());
+ }
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
}
@@ -126,6 +129,9 @@
public void onPointerUp() {
try {
getFreshDaemon().onPointerUp(0 /* pointerId */);
+ if (getListener() != null) {
+ getListener().onUdfpsPointerUp(getSensorId(), getCookie());
+ }
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
index 3b376fe..b4bb4f8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
@@ -27,6 +27,7 @@
import android.os.RemoteException;
import android.util.Slog;
+import com.android.server.biometrics.BiometricsProto;
import com.android.server.biometrics.sensors.AcquisitionClient;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.fingerprint.UdfpsHelper;
@@ -91,4 +92,9 @@
mCallback.onClientFinished(this, false /* success */);
}
}
+
+ @Override
+ public int getProtoEnum() {
+ return BiometricsProto.CM_DETECT_INTERACTION;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGetAuthenticatorIdClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGetAuthenticatorIdClient.java
index 02d4ac3..ce1a318 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGetAuthenticatorIdClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGetAuthenticatorIdClient.java
@@ -23,6 +23,7 @@
import android.os.RemoteException;
import android.util.Slog;
+import com.android.server.biometrics.BiometricsProto;
import com.android.server.biometrics.sensors.HalClientMonitor;
import java.util.Map;
@@ -65,4 +66,9 @@
mAuthenticatorIds.put(getTargetUserId(), authenticatorId);
mCallback.onClientFinished(this, true /* success */);
}
+
+ @Override
+ public int getProtoEnum() {
+ return BiometricsProto.CM_GET_AUTHENTICATOR_ID;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index 8a666f9..727184f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -627,9 +627,10 @@
}
@Override
- public void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto) {
+ public void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto,
+ boolean clearSchedulerBuffer) {
if (mSensors.contains(sensorId)) {
- mSensors.get(sensorId).dumpProtoState(sensorId, proto);
+ mSensors.get(sensorId).dumpProtoState(sensorId, proto, clearSchedulerBuffer);
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
index cd84cdf..ddcfcad 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
@@ -25,6 +25,7 @@
import android.os.RemoteException;
import android.util.Slog;
+import com.android.server.biometrics.BiometricsProto;
import com.android.server.biometrics.HardwareAuthTokenUtils;
import com.android.server.biometrics.sensors.HalClientMonitor;
import com.android.server.biometrics.sensors.LockoutCache;
@@ -76,4 +77,9 @@
mLockoutResetDispatcher.notifyLockoutResetCallbacks(getSensorId());
mCallback.onClientFinished(this, true /* success */);
}
+
+ @Override
+ public int getProtoEnum() {
+ return BiometricsProto.CM_RESET_LOCKOUT;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
index 911f6b4..f0e7e1c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
@@ -481,12 +481,13 @@
mTestHalEnabled = enabled;
}
- void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto) {
+ void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto,
+ boolean clearSchedulerBuffer) {
final long sensorToken = proto.start(SensorServiceStateProto.SENSOR_STATES);
proto.write(SensorStateProto.SENSOR_ID, mSensorProperties.sensorId);
proto.write(SensorStateProto.MODALITY, SensorStateProto.FINGERPRINT);
- proto.write(SensorStateProto.IS_BUSY, mScheduler.getCurrentClient() != null);
+ proto.write(SensorStateProto.SCHEDULER, mScheduler.dumpProtoState(clearSchedulerBuffer));
for (UserInfo user : UserManager.get(mContext).getUsers()) {
final int userId = user.getUserHandle().getIdentifier();
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
index 95c4cee..6893e72 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
@@ -97,6 +97,16 @@
public void onChallengeGenerated(int sensorId, long challenge) {
}
+
+ @Override
+ public void onUdfpsPointerDown(int sensorId) {
+
+ }
+
+ @Override
+ public void onUdfpsPointerUp(int sensorId) {
+
+ }
};
BiometricTestSessionImpl(@NonNull Context context, int sensorId,
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index 6cc8687..acc575f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -714,12 +714,13 @@
}
@Override
- public void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto) {
+ public void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto,
+ boolean clearSchedulerBuffer) {
final long sensorToken = proto.start(SensorServiceStateProto.SENSOR_STATES);
proto.write(SensorStateProto.SENSOR_ID, mSensorProperties.sensorId);
proto.write(SensorStateProto.MODALITY, SensorStateProto.FINGERPRINT);
- proto.write(SensorStateProto.IS_BUSY, mScheduler.getCurrentClient() != null);
+ proto.write(SensorStateProto.SCHEDULER, mScheduler.dumpProtoState(clearSchedulerBuffer));
for (UserInfo user : UserManager.get(mContext).getUsers()) {
final int userId = user.getUserHandle().getIdentifier();
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
index 13e2e4f..589db6c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
@@ -150,11 +150,25 @@
@Override
public void onPointerDown(int x, int y, float minor, float major) {
UdfpsHelper.onFingerDown(getFreshDaemon(), x, y, minor, major);
+ if (getListener() != null) {
+ try {
+ getListener().onUdfpsPointerDown(getSensorId(), getCookie());
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }
}
@Override
public void onPointerUp() {
UdfpsHelper.onFingerUp(getFreshDaemon());
+ if (getListener() != null) {
+ try {
+ getListener().onUdfpsPointerUp(getSensorId(), getCookie());
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }
}
public boolean isKeyguard() {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
index 55995ea..6318139 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
@@ -28,6 +28,7 @@
import android.os.RemoteException;
import android.util.Slog;
+import com.android.server.biometrics.BiometricsProto;
import com.android.server.biometrics.sensors.AcquisitionClient;
import com.android.server.biometrics.sensors.AuthenticationConsumer;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
@@ -123,4 +124,9 @@
Slog.e(TAG, "Remote exception when sending onDetected", e);
}
}
+
+ @Override
+ public int getProtoEnum() {
+ return BiometricsProto.CM_DETECT_INTERACTION;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java
index f6ec4d9..11ffbb2 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java
@@ -26,6 +26,7 @@
import android.os.SELinux;
import android.util.Slog;
+import com.android.server.biometrics.BiometricsProto;
import com.android.server.biometrics.sensors.HalClientMonitor;
import java.io.File;
@@ -121,4 +122,9 @@
mCallback.onClientFinished(this, false /* success */);
}
}
+
+ @Override
+ public int getProtoEnum() {
+ return BiometricsProto.CM_UPDATE_ACTIVE_USER;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java
index 3e5b88c..8e84613 100644
--- a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java
@@ -50,7 +50,7 @@
}
@Override
- public byte[] dumpSensorServiceStateProto() throws RemoteException {
+ public byte[] dumpSensorServiceStateProto(boolean clearSchedulerBuffer) throws RemoteException {
return null;
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index ba6cbcd..ab0360b 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -36,13 +36,17 @@
import android.net.NetworkMonitorManager;
import android.net.NetworkRequest;
import android.net.NetworkState;
+import android.net.QosCallbackException;
+import android.net.QosFilter;
+import android.net.QosFilterParcelable;
+import android.net.QosSession;
import android.net.TcpKeepalivePacketData;
-import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.INetworkManagementService;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.telephony.data.EpsBearerQosSessionAttributes;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
@@ -53,7 +57,6 @@
import com.android.server.ConnectivityService;
import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
@@ -323,18 +326,20 @@
private final ConnectivityService mConnService;
private final Context mContext;
private final Handler mHandler;
+ private final QosCallbackTracker mQosCallbackTracker;
public NetworkAgentInfo(INetworkAgent na, Network net, NetworkInfo info,
LinkProperties lp, NetworkCapabilities nc, int score, Context context,
Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd,
IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber,
- int creatorUid) {
+ int creatorUid, QosCallbackTracker qosCallbackTracker) {
Objects.requireNonNull(net);
Objects.requireNonNull(info);
Objects.requireNonNull(lp);
Objects.requireNonNull(nc);
Objects.requireNonNull(context);
Objects.requireNonNull(config);
+ Objects.requireNonNull(qosCallbackTracker);
networkAgent = na;
network = net;
networkInfo = info;
@@ -348,6 +353,7 @@
networkAgentConfig = config;
this.factorySerialNumber = factorySerialNumber;
this.creatorUid = creatorUid;
+ mQosCallbackTracker = qosCallbackTracker;
}
private class AgentDeathMonitor implements IBinder.DeathRecipient {
@@ -533,6 +539,31 @@
}
}
+ /**
+ * Notify the NetworkAgent that the qos filter should be registered against the given qos
+ * callback id.
+ */
+ public void onQosFilterCallbackRegistered(final int qosCallbackId,
+ final QosFilter qosFilter) {
+ try {
+ networkAgent.onQosFilterCallbackRegistered(qosCallbackId,
+ new QosFilterParcelable(qosFilter));
+ } catch (final RemoteException e) {
+ Log.e(TAG, "Error registering a qos callback id against a qos filter", e);
+ }
+ }
+
+ /**
+ * Notify the NetworkAgent that the given qos callback id should be unregistered.
+ */
+ public void onQosCallbackUnregistered(final int qosCallbackId) {
+ try {
+ networkAgent.onQosCallbackUnregistered(qosCallbackId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error unregistering a qos callback id", e);
+ }
+ }
+
// TODO: consider moving out of NetworkAgentInfo into its own class
private class NetworkAgentMessageHandler extends INetworkAgentRegistry.Stub {
private final Handler mHandler;
@@ -583,16 +614,25 @@
@Override
public void sendUnderlyingNetworks(@Nullable List<Network> networks) {
- final Bundle args = new Bundle();
- if (networks instanceof ArrayList<?>) {
- args.putParcelableArrayList(NetworkAgent.UNDERLYING_NETWORKS_KEY,
- (ArrayList<Network>) networks);
- } else {
- args.putParcelableArrayList(NetworkAgent.UNDERLYING_NETWORKS_KEY,
- networks == null ? null : new ArrayList<>(networks));
- }
mHandler.obtainMessage(NetworkAgent.EVENT_UNDERLYING_NETWORKS_CHANGED,
- new Pair<>(NetworkAgentInfo.this, args)).sendToTarget();
+ new Pair<>(NetworkAgentInfo.this, networks)).sendToTarget();
+ }
+
+ @Override
+ public void sendEpsQosSessionAvailable(final int qosCallbackId, final QosSession session,
+ final EpsBearerQosSessionAttributes attributes) {
+ mQosCallbackTracker.sendEventQosSessionAvailable(qosCallbackId, session, attributes);
+ }
+
+ @Override
+ public void sendQosSessionLost(final int qosCallbackId, final QosSession session) {
+ mQosCallbackTracker.sendEventQosSessionLost(qosCallbackId, session);
+ }
+
+ @Override
+ public void sendQosCallbackError(final int qosCallbackId,
+ @QosCallbackException.ExceptionType final int exceptionType) {
+ mQosCallbackTracker.sendEventQosCallbackError(qosCallbackId, exceptionType);
}
}
diff --git a/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java b/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java
new file mode 100644
index 0000000..816bf2b
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity;
+
+import static android.net.QosCallbackException.EX_TYPE_FILTER_NONE;
+
+import android.annotation.NonNull;
+import android.net.IQosCallback;
+import android.net.Network;
+import android.net.QosCallbackException;
+import android.net.QosFilter;
+import android.net.QosSession;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.util.Slog;
+
+import java.util.Objects;
+
+/**
+ * Wraps callback related information and sends messages between network agent and the application.
+ * <p/>
+ * This is a satellite class of {@link com.android.server.ConnectivityService} and not meant
+ * to be used in other contexts.
+ *
+ * @hide
+ */
+class QosCallbackAgentConnection implements IBinder.DeathRecipient {
+ private static final String TAG = QosCallbackAgentConnection.class.getSimpleName();
+ private static final boolean DBG = false;
+
+ private final int mAgentCallbackId;
+ @NonNull private final QosCallbackTracker mQosCallbackTracker;
+ @NonNull private final IQosCallback mCallback;
+ @NonNull private final IBinder mBinder;
+ @NonNull private final QosFilter mFilter;
+ @NonNull private final NetworkAgentInfo mNetworkAgentInfo;
+
+ private final int mUid;
+
+ /**
+ * Gets the uid
+ * @return uid
+ */
+ int getUid() {
+ return mUid;
+ }
+
+ /**
+ * Gets the binder
+ * @return binder
+ */
+ @NonNull
+ IBinder getBinder() {
+ return mBinder;
+ }
+
+ /**
+ * Gets the callback id
+ *
+ * @return callback id
+ */
+ int getAgentCallbackId() {
+ return mAgentCallbackId;
+ }
+
+ /**
+ * Gets the network tied to the callback of this connection
+ *
+ * @return network
+ */
+ @NonNull
+ Network getNetwork() {
+ return mFilter.getNetwork();
+ }
+
+ QosCallbackAgentConnection(@NonNull final QosCallbackTracker qosCallbackTracker,
+ final int agentCallbackId,
+ @NonNull final IQosCallback callback,
+ @NonNull final QosFilter filter,
+ final int uid,
+ @NonNull final NetworkAgentInfo networkAgentInfo) {
+ Objects.requireNonNull(qosCallbackTracker, "qosCallbackTracker must be non-null");
+ Objects.requireNonNull(callback, "callback must be non-null");
+ Objects.requireNonNull(filter, "filter must be non-null");
+ Objects.requireNonNull(networkAgentInfo, "networkAgentInfo must be non-null");
+
+ mQosCallbackTracker = qosCallbackTracker;
+ mAgentCallbackId = agentCallbackId;
+ mCallback = callback;
+ mFilter = filter;
+ mUid = uid;
+ mBinder = mCallback.asBinder();
+ mNetworkAgentInfo = networkAgentInfo;
+ }
+
+ @Override
+ public void binderDied() {
+ logw("binderDied: binder died with callback id: " + mAgentCallbackId);
+ mQosCallbackTracker.unregisterCallback(mCallback);
+ }
+
+ void unlinkToDeathRecipient() {
+ mBinder.unlinkToDeath(this, 0);
+ }
+
+ // Returns false if the NetworkAgent was never notified.
+ boolean sendCmdRegisterCallback() {
+ final int exceptionType = mFilter.validate();
+ if (exceptionType != EX_TYPE_FILTER_NONE) {
+ try {
+ if (DBG) log("sendCmdRegisterCallback: filter validation failed");
+ mCallback.onError(exceptionType);
+ } catch (final RemoteException e) {
+ loge("sendCmdRegisterCallback:", e);
+ }
+ return false;
+ }
+
+ try {
+ mBinder.linkToDeath(this, 0);
+ } catch (final RemoteException e) {
+ loge("failed linking to death recipient", e);
+ return false;
+ }
+ mNetworkAgentInfo.onQosFilterCallbackRegistered(mAgentCallbackId, mFilter);
+ return true;
+ }
+
+ void sendCmdUnregisterCallback() {
+ if (DBG) log("sendCmdUnregisterCallback: unregistering");
+ mNetworkAgentInfo.onQosCallbackUnregistered(mAgentCallbackId);
+ }
+
+ void sendEventQosSessionAvailable(final QosSession session,
+ final EpsBearerQosSessionAttributes attributes) {
+ try {
+ if (DBG) log("sendEventQosSessionAvailable: sending...");
+ mCallback.onQosEpsBearerSessionAvailable(session, attributes);
+ } catch (final RemoteException e) {
+ loge("sendEventQosSessionAvailable: remote exception", e);
+ }
+ }
+
+ void sendEventQosSessionLost(@NonNull final QosSession session) {
+ try {
+ if (DBG) log("sendEventQosSessionLost: sending...");
+ mCallback.onQosSessionLost(session);
+ } catch (final RemoteException e) {
+ loge("sendEventQosSessionLost: remote exception", e);
+ }
+ }
+
+ void sendEventQosCallbackError(@QosCallbackException.ExceptionType final int exceptionType) {
+ try {
+ if (DBG) log("sendEventQosCallbackError: sending...");
+ mCallback.onError(exceptionType);
+ } catch (final RemoteException e) {
+ loge("sendEventQosCallbackError: remote exception", e);
+ }
+ }
+
+ private static void log(@NonNull final String msg) {
+ Slog.d(TAG, msg);
+ }
+
+ private static void logw(@NonNull final String msg) {
+ Slog.w(TAG, msg);
+ }
+
+ private static void loge(@NonNull final String msg, final Throwable t) {
+ Slog.e(TAG, msg, t);
+ }
+
+ private static void logwtf(@NonNull final String msg) {
+ Slog.wtf(TAG, msg);
+ }
+}
diff --git a/services/core/java/com/android/server/connectivity/QosCallbackTracker.java b/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
new file mode 100644
index 0000000..87b4c16
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.IQosCallback;
+import android.net.Network;
+import android.net.QosCallbackException;
+import android.net.QosFilter;
+import android.net.QosSession;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.util.Slog;
+
+import com.android.internal.util.CollectionUtils;
+import com.android.server.ConnectivityService;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tracks qos callbacks and handles the communication between the network agent and application.
+ * <p/>
+ * Any method prefixed by handle must be called from the
+ * {@link com.android.server.ConnectivityService} handler thread.
+ *
+ * @hide
+ */
+public class QosCallbackTracker {
+ private static final String TAG = QosCallbackTracker.class.getSimpleName();
+ private static final boolean DBG = true;
+
+ @NonNull
+ private final Handler mConnectivityServiceHandler;
+
+ @NonNull
+ private final ConnectivityService.PerUidCounter mNetworkRequestCounter;
+
+ /**
+ * Each agent gets a unique callback id that is used to proxy messages back to the original
+ * callback.
+ * <p/>
+ * Note: The fact that this is initialized to 0 is to ensure that the thread running
+ * {@link #handleRegisterCallback(IQosCallback, QosFilter, int, NetworkAgentInfo)} sees the
+ * initialized value. This would not necessarily be the case if the value was initialized to
+ * the non-default value.
+ * <p/>
+ * Note: The term previous does not apply to the first callback id that is assigned.
+ */
+ private int mPreviousAgentCallbackId = 0;
+
+ @NonNull
+ private final List<QosCallbackAgentConnection> mConnections = new ArrayList<>();
+
+ /**
+ *
+ * @param connectivityServiceHandler must be the same handler used with
+ * {@link com.android.server.ConnectivityService}
+ * @param networkRequestCounter keeps track of the number of open requests under a given
+ * uid
+ */
+ public QosCallbackTracker(@NonNull final Handler connectivityServiceHandler,
+ final ConnectivityService.PerUidCounter networkRequestCounter) {
+ mConnectivityServiceHandler = connectivityServiceHandler;
+ mNetworkRequestCounter = networkRequestCounter;
+ }
+
+ /**
+ * Registers the callback with the tracker
+ *
+ * @param callback the callback to register
+ * @param filter the filter being registered alongside the callback
+ */
+ public void registerCallback(@NonNull final IQosCallback callback,
+ @NonNull final QosFilter filter, @NonNull final NetworkAgentInfo networkAgentInfo) {
+ final int uid = Binder.getCallingUid();
+
+ // Enforce that the number of requests under this uid has exceeded the allowed number
+ mNetworkRequestCounter.incrementCountOrThrow(uid);
+
+ mConnectivityServiceHandler.post(
+ () -> handleRegisterCallback(callback, filter, uid, networkAgentInfo));
+ }
+
+ private void handleRegisterCallback(@NonNull final IQosCallback callback,
+ @NonNull final QosFilter filter, final int uid,
+ @NonNull final NetworkAgentInfo networkAgentInfo) {
+ final QosCallbackAgentConnection ac =
+ handleRegisterCallbackInternal(callback, filter, uid, networkAgentInfo);
+ if (ac != null) {
+ if (DBG) log("handleRegisterCallback: added callback " + ac.getAgentCallbackId());
+ mConnections.add(ac);
+ } else {
+ mNetworkRequestCounter.decrementCount(uid);
+ }
+ }
+
+ private QosCallbackAgentConnection handleRegisterCallbackInternal(
+ @NonNull final IQosCallback callback,
+ @NonNull final QosFilter filter, final int uid,
+ @NonNull final NetworkAgentInfo networkAgentInfo) {
+ final IBinder binder = callback.asBinder();
+ if (CollectionUtils.any(mConnections, c -> c.getBinder().equals(binder))) {
+ // A duplicate registration would have only made this far due to a programming error.
+ logwtf("handleRegisterCallback: Callbacks can only be register once.");
+ return null;
+ }
+
+ mPreviousAgentCallbackId = mPreviousAgentCallbackId + 1;
+ final int newCallbackId = mPreviousAgentCallbackId;
+
+ final QosCallbackAgentConnection ac =
+ new QosCallbackAgentConnection(this, newCallbackId, callback,
+ filter, uid, networkAgentInfo);
+
+ final int exceptionType = filter.validate();
+ if (exceptionType != QosCallbackException.EX_TYPE_FILTER_NONE) {
+ ac.sendEventQosCallbackError(exceptionType);
+ return null;
+ }
+
+ // Only add to the callback maps if the NetworkAgent successfully registered it
+ if (!ac.sendCmdRegisterCallback()) {
+ // There was an issue when registering the agent
+ if (DBG) log("handleRegisterCallback: error sending register callback");
+ mNetworkRequestCounter.decrementCount(uid);
+ return null;
+ }
+ return ac;
+ }
+
+ /**
+ * Unregisters callback
+ * @param callback callback to unregister
+ */
+ public void unregisterCallback(@NonNull final IQosCallback callback) {
+ mConnectivityServiceHandler.post(() -> handleUnregisterCallback(callback.asBinder(), true));
+ }
+
+ private void handleUnregisterCallback(@NonNull final IBinder binder,
+ final boolean sendToNetworkAgent) {
+ final QosCallbackAgentConnection agentConnection =
+ CollectionUtils.find(mConnections, c -> c.getBinder().equals(binder));
+ if (agentConnection == null) {
+ logw("handleUnregisterCallback: agentConnection is null");
+ return;
+ }
+
+ if (DBG) {
+ log("handleUnregisterCallback: unregister "
+ + agentConnection.getAgentCallbackId());
+ }
+
+ mNetworkRequestCounter.decrementCount(agentConnection.getUid());
+ mConnections.remove(agentConnection);
+
+ if (sendToNetworkAgent) {
+ agentConnection.sendCmdUnregisterCallback();
+ }
+ agentConnection.unlinkToDeathRecipient();
+ }
+
+ /**
+ * Called when the NetworkAgent sends the qos session available event
+ *
+ * @param qosCallbackId the callback id that the qos session is now available to
+ * @param session the qos session that is now available
+ * @param attributes the qos attributes that are now available on the qos session
+ */
+ public void sendEventQosSessionAvailable(final int qosCallbackId,
+ final QosSession session,
+ final EpsBearerQosSessionAttributes attributes) {
+ runOnAgentConnection(qosCallbackId, "sendEventQosSessionAvailable: ",
+ ac -> ac.sendEventQosSessionAvailable(session, attributes));
+ }
+
+ /**
+ * Called when the NetworkAgent sends the qos session lost event
+ *
+ * @param qosCallbackId the callback id that lost the qos session
+ * @param session the corresponding qos session
+ */
+ public void sendEventQosSessionLost(final int qosCallbackId,
+ final QosSession session) {
+ runOnAgentConnection(qosCallbackId, "sendEventQosSessionLost: ",
+ ac -> ac.sendEventQosSessionLost(session));
+ }
+
+ /**
+ * Called when the NetworkAgent sends the qos session on error event
+ *
+ * @param qosCallbackId the callback id that should receive the exception
+ * @param exceptionType the type of exception that caused the callback to error
+ */
+ public void sendEventQosCallbackError(final int qosCallbackId,
+ @QosCallbackException.ExceptionType final int exceptionType) {
+ runOnAgentConnection(qosCallbackId, "sendEventQosCallbackError: ",
+ ac -> {
+ ac.sendEventQosCallbackError(exceptionType);
+ handleUnregisterCallback(ac.getBinder(), false);
+ });
+ }
+
+ /**
+ * Unregisters all callbacks associated to this network agent
+ *
+ * Note: Must be called on the connectivity service handler thread
+ *
+ * @param network the network that was released
+ */
+ public void handleNetworkReleased(@Nullable final Network network) {
+ final List<QosCallbackAgentConnection> connections =
+ CollectionUtils.filter(mConnections, ac -> ac.getNetwork().equals(network));
+
+ for (final QosCallbackAgentConnection agentConnection : connections) {
+ agentConnection.sendEventQosCallbackError(
+ QosCallbackException.EX_TYPE_FILTER_NETWORK_RELEASED);
+
+ // Call unregister workflow w\o sending anything to agent since it is disconnected.
+ handleUnregisterCallback(agentConnection.getBinder(), false);
+ }
+ }
+
+ private interface AgentConnectionAction {
+ void execute(@NonNull QosCallbackAgentConnection agentConnection);
+ }
+
+ @Nullable
+ private void runOnAgentConnection(final int qosCallbackId,
+ @NonNull final String logPrefix,
+ @NonNull final AgentConnectionAction action) {
+ mConnectivityServiceHandler.post(() -> {
+ final QosCallbackAgentConnection ac =
+ CollectionUtils.find(mConnections,
+ c -> c.getAgentCallbackId() == qosCallbackId);
+ if (ac == null) {
+ loge(logPrefix + ": " + qosCallbackId + " missing callback id");
+ return;
+ }
+
+ action.execute(ac);
+ });
+ }
+
+ private static void log(final String msg) {
+ Slog.d(TAG, msg);
+ }
+
+ private static void logw(final String msg) {
+ Slog.w(TAG, msg);
+ }
+
+ private static void loge(final String msg) {
+ Slog.e(TAG, msg);
+ }
+
+ private static void logwtf(final String msg) {
+ Slog.wtf(TAG, msg);
+ }
+}
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 68708d36..d687221 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -24,6 +24,7 @@
import android.view.DisplayAddress;
import com.android.internal.BrightnessSynchronizer;
+import com.android.internal.R;
import com.android.server.display.config.DisplayConfiguration;
import com.android.server.display.config.DisplayQuirks;
import com.android.server.display.config.HbmTiming;
@@ -64,6 +65,7 @@
private static final String STABLE_ID_SUFFIX_FORMAT = "id_%d";
private static final String NO_SUFFIX_FORMAT = "%d";
private static final long STABLE_FLAG = 1L << 62;
+
// Float.NaN (used as invalid for brightness) cannot be stored in config.xml
// so -2 is used instead
private static final float INVALID_BRIGHTNESS_IN_CONFIG = -2f;
@@ -75,6 +77,10 @@
private float mBrightnessMinimum = Float.NaN;
private float mBrightnessMaximum = Float.NaN;
private float mBrightnessDefault = Float.NaN;
+ private float mBrightnessRampFastDecrease = Float.NaN;
+ private float mBrightnessRampFastIncrease = Float.NaN;
+ private float mBrightnessRampSlowDecrease = Float.NaN;
+ private float mBrightnessRampSlowIncrease = Float.NaN;
private List<String> mQuirks;
private boolean mIsHighBrightnessModeEnabled = false;
private HighBrightnessModeData mHbmData;
@@ -177,6 +183,22 @@
return mBrightnessDefault;
}
+ public float getBrightnessRampFastDecrease() {
+ return mBrightnessRampFastDecrease;
+ }
+
+ public float getBrightnessRampFastIncrease() {
+ return mBrightnessRampFastIncrease;
+ }
+
+ public float getBrightnessRampSlowDecrease() {
+ return mBrightnessRampSlowDecrease;
+ }
+
+ public float getBrightnessRampSlowIncrease() {
+ return mBrightnessRampSlowIncrease;
+ }
+
/**
* @param quirkValue The quirk to test.
* @return {@code true} if the specified quirk is present in this configuration,
@@ -210,6 +232,10 @@
+ ", mQuirks=" + mQuirks
+ ", isHbmEnabled=" + mIsHighBrightnessModeEnabled
+ ", mHbmData=" + mHbmData
+ + ", mBrightnessRampFastDecrease=" + mBrightnessRampFastDecrease
+ + ", mBrightnessRampFastIncrease=" + mBrightnessRampFastIncrease
+ + ", mBrightnessRampSlowDecrease=" + mBrightnessRampSlowDecrease
+ + ", mBrightnessRampSlowIncrease=" + mBrightnessRampSlowIncrease
+ "}";
return str;
}
@@ -265,6 +291,7 @@
loadBrightnessConstraintsFromConfigXml();
loadHighBrightnessModeData(config);
loadQuirks(config);
+ loadBrightnessRamps(config);
} else {
Slog.w(TAG, "DisplayDeviceConfig file is null");
}
@@ -278,6 +305,7 @@
// If no ddc exists, use config.xml
loadBrightnessDefaultFromConfigXml();
loadBrightnessConstraintsFromConfigXml();
+ loadBrightnessRampsFromConfigXml();
}
private void initFromPmValues() {
@@ -397,6 +425,41 @@
}
}
+ private void loadBrightnessRamps(DisplayConfiguration config) {
+ // Priority 1: Value in the display device config (float)
+ // Priority 2: Value in the config.xml (int)
+ final BigDecimal fastDownDecimal = config.getScreenBrightnessRampFastDecrease();
+ final BigDecimal fastUpDecimal = config.getScreenBrightnessRampFastIncrease();
+ final BigDecimal slowDownDecimal = config.getScreenBrightnessRampSlowDecrease();
+ final BigDecimal slowUpDecimal = config.getScreenBrightnessRampSlowIncrease();
+
+ if (fastDownDecimal != null && fastUpDecimal != null && slowDownDecimal != null
+ && slowUpDecimal != null) {
+ mBrightnessRampFastDecrease = fastDownDecimal.floatValue();
+ mBrightnessRampFastIncrease = fastUpDecimal.floatValue();
+ mBrightnessRampSlowDecrease = slowDownDecimal.floatValue();
+ mBrightnessRampSlowIncrease = slowUpDecimal.floatValue();
+ } else {
+ if (fastDownDecimal != null || fastUpDecimal != null || slowDownDecimal != null
+ || slowUpDecimal != null) {
+ Slog.w(TAG, "Per display brightness ramp values ignored because not all "
+ + "values are present in display device config");
+ }
+ loadBrightnessRampsFromConfigXml();
+ }
+ }
+
+ private void loadBrightnessRampsFromConfigXml() {
+ mBrightnessRampFastIncrease = BrightnessSynchronizer.brightnessIntToFloat(
+ mContext.getResources().getInteger(R.integer.config_brightness_ramp_rate_fast));
+ mBrightnessRampSlowIncrease = BrightnessSynchronizer.brightnessIntToFloat(
+ mContext.getResources().getInteger(R.integer.config_brightness_ramp_rate_slow));
+ // config.xml uses the same values for both increasing and decreasing brightness
+ // transitions so we assign them to the same values here.
+ mBrightnessRampFastDecrease = mBrightnessRampFastIncrease;
+ mBrightnessRampSlowDecrease = mBrightnessRampSlowIncrease;
+ }
+
/**
* Container for high brightness mode configuration data.
*/
diff --git a/services/core/java/com/android/server/display/DisplayGroup.java b/services/core/java/com/android/server/display/DisplayGroup.java
index 2ba8758..1b5065a 100644
--- a/services/core/java/com/android/server/display/DisplayGroup.java
+++ b/services/core/java/com/android/server/display/DisplayGroup.java
@@ -21,7 +21,8 @@
/**
* Represents a collection of {@link LogicalDisplay}s which act in unison for certain behaviors and
- * operations.
+ * operations; particularly display-state.
+ *
* @hide
*/
public class DisplayGroup {
@@ -35,17 +36,44 @@
mGroupId = groupId;
}
+ /** Returns the identifier for the Group. */
int getGroupId() {
return mGroupId;
}
- void addDisplay(LogicalDisplay display) {
+ /**
+ * Adds the provided {@code display} to the Group
+ *
+ * @param display the {@link LogicalDisplay} to add to the Group
+ */
+ void addDisplayLocked(LogicalDisplay display) {
if (!mDisplays.contains(display)) {
mDisplays.add(display);
}
}
- boolean removeDisplay(LogicalDisplay display) {
+ /**
+ * Removes the provided {@code display} from the Group.
+ *
+ * @param display The {@link LogicalDisplay} to remove from the Group.
+ * @return {@code true} if the {@code display} was removed; otherwise {@code false}
+ */
+ boolean removeDisplayLocked(LogicalDisplay display) {
return mDisplays.remove(display);
}
+
+ /** Returns {@code true} if there are no {@link LogicalDisplay LogicalDisplays} in the Group. */
+ boolean isEmptyLocked() {
+ return mDisplays.isEmpty();
+ }
+
+ /** Returns the number of {@link LogicalDisplay LogicalDisplays} in the Group. */
+ int getSizeLocked() {
+ return mDisplays.size();
+ }
+
+ /** Returns the ID of the {@link LogicalDisplay} at the provided {@code index}. */
+ int getIdLocked(int index) {
+ return mDisplays.get(index).getDisplayIdLocked();
+ }
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 55103ca..bb4c9dd 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -57,6 +57,7 @@
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerGlobal;
import android.hardware.display.DisplayManagerInternal;
+import android.hardware.display.DisplayManagerInternal.DisplayGroupListener;
import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener;
import android.hardware.display.DisplayViewport;
import android.hardware.display.DisplayedContentSample;
@@ -190,6 +191,7 @@
private static final int MSG_UPDATE_VIEWPORT = 5;
private static final int MSG_LOAD_BRIGHTNESS_CONFIGURATION = 6;
private static final int MSG_DELIVER_DISPLAY_EVENT_FRAME_RATE_OVERRIDE = 7;
+ private static final int MSG_DELIVER_DISPLAY_GROUP_EVENT = 8;
private final Context mContext;
private final DisplayManagerHandler mHandler;
@@ -237,36 +239,54 @@
private final CopyOnWriteArrayList<DisplayTransactionListener> mDisplayTransactionListeners =
new CopyOnWriteArrayList<DisplayTransactionListener>();
+ /** List of all display group listeners. */
+ private final CopyOnWriteArrayList<DisplayGroupListener> mDisplayGroupListeners =
+ new CopyOnWriteArrayList<>();
+
/** All {@link DisplayPowerController}s indexed by {@link LogicalDisplay} ID. */
private final SparseArray<DisplayPowerController> mDisplayPowerControllers =
new SparseArray<>();
/** {@link DisplayBlanker} used by all {@link DisplayPowerController}s. */
private final DisplayBlanker mDisplayBlanker = new DisplayBlanker() {
+ // Synchronized to avoid race conditions when updating multiple display states.
@Override
- public void requestDisplayState(int displayId, int state, float brightness) {
- // TODO (b/168210494): Stop applying default display state to all displays.
- if (displayId != Display.DEFAULT_DISPLAY) {
- return;
- }
- final int[] displayIds;
+ public synchronized void requestDisplayState(int displayId, int state, float brightness) {
+ boolean allInactive = true;
+ boolean allOff = true;
+ final boolean stateChanged;
synchronized (mSyncRoot) {
- displayIds = mLogicalDisplayMapper.getDisplayIdsLocked();
+ final int index = mDisplayStates.indexOfKey(displayId);
+ final int newState = mDisplayStates.valueAt(index);
+ stateChanged = index == -1 || state != newState;
+ if (stateChanged) {
+ final int size = mDisplayStates.size();
+ for (int i = 0; i < size; i++) {
+ final int displayState = i == index ? newState : state;
+ if (displayState != Display.STATE_OFF) {
+ allOff = false;
+ }
+ if (Display.isActiveState(displayState)) {
+ allInactive = false;
+ }
+ if (!allOff && !allInactive) {
+ break;
+ }
+ }
+ }
}
// The order of operations is important for legacy reasons.
if (state == Display.STATE_OFF) {
- for (int id : displayIds) {
- requestDisplayStateInternal(id, state, brightness);
- }
+ requestDisplayStateInternal(displayId, state, brightness);
}
- mDisplayPowerCallbacks.onDisplayStateChange(state);
+ if (stateChanged) {
+ mDisplayPowerCallbacks.onDisplayStateChange(allInactive, allOff);
+ }
if (state != Display.STATE_OFF) {
- for (int id : displayIds) {
- requestDisplayStateInternal(id, state, brightness);
- }
+ requestDisplayStateInternal(displayId, state, brightness);
}
}
};
@@ -1152,7 +1172,7 @@
private void handleLogicalDisplayRemovedLocked(@NonNull LogicalDisplay display) {
final int displayId = display.getDisplayIdLocked();
- mDisplayPowerControllers.delete(displayId);
+ mDisplayPowerControllers.removeReturnOld(displayId).stop();
mDisplayStates.delete(displayId);
mDisplayBrightnesses.delete(displayId);
DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
@@ -1669,6 +1689,11 @@
mHandler.sendMessage(msg);
}
+ private void sendDisplayGroupEvent(int groupId, int event) {
+ Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_GROUP_EVENT, groupId, event);
+ mHandler.sendMessage(msg);
+ }
+
private void sendDisplayEventFrameRateOverrideLocked(int displayId) {
Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_EVENT_FRAME_RATE_OVERRIDE,
displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
@@ -1713,6 +1738,35 @@
mTempCallbacks.clear();
}
+ // Runs on Handler thread.
+ // Delivers display group event notifications to callbacks.
+ private void deliverDisplayGroupEvent(int groupId, int event) {
+ if (DEBUG) {
+ Slog.d(TAG, "Delivering display group event: groupId=" + groupId + ", event="
+ + event);
+ }
+
+ switch (event) {
+ case LogicalDisplayMapper.DISPLAY_GROUP_EVENT_ADDED:
+ for (DisplayGroupListener listener : mDisplayGroupListeners) {
+ listener.onDisplayGroupAdded(groupId);
+ }
+ break;
+
+ case LogicalDisplayMapper.DISPLAY_GROUP_EVENT_CHANGED:
+ for (DisplayGroupListener listener : mDisplayGroupListeners) {
+ listener.onDisplayGroupChanged(groupId);
+ }
+ break;
+
+ case LogicalDisplayMapper.DISPLAY_GROUP_EVENT_REMOVED:
+ for (DisplayGroupListener listener : mDisplayGroupListeners) {
+ listener.onDisplayGroupRemoved(groupId);
+ }
+ break;
+ }
+ }
+
private IMediaProjectionManager getProjectionService() {
if (mProjectionService == null) {
IBinder b = ServiceManager.getService(Context.MEDIA_PROJECTION_SERVICE);
@@ -1935,6 +1989,11 @@
}
deliverDisplayEvent(msg.arg1, uids, msg.arg2);
break;
+
+ case MSG_DELIVER_DISPLAY_GROUP_EVENT:
+ deliverDisplayGroupEvent(msg.arg1, msg.arg2);
+ break;
+
}
}
}
@@ -1966,6 +2025,11 @@
}
@Override
+ public void onDisplayGroupEventLocked(int groupId, int event) {
+ sendDisplayGroupEvent(groupId, event);
+ }
+
+ @Override
public void onTraversalRequested() {
synchronized (mSyncRoot) {
scheduleTraversalLocked(false);
@@ -2700,11 +2764,25 @@
}
@Override
- public boolean requestPowerState(DisplayPowerRequest request,
+ public boolean requestPowerState(int groupId, DisplayPowerRequest request,
boolean waitForNegativeProximity) {
synchronized (mSyncRoot) {
- return mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY)
- .requestPowerState(request, waitForNegativeProximity);
+ final DisplayGroup displayGroup = mLogicalDisplayMapper.getDisplayGroupLocked(
+ groupId);
+ if (displayGroup == null) {
+ return true;
+ }
+
+ final int size = displayGroup.getSizeLocked();
+ boolean ready = true;
+ for (int i = 0; i < size; i++) {
+ final DisplayPowerController displayPowerController =
+ mDisplayPowerControllers.get(displayGroup.getIdLocked(i));
+ ready &= displayPowerController.requestPowerState(request,
+ waitForNegativeProximity);
+ }
+
+ return ready;
}
}
@@ -2717,10 +2795,13 @@
}
@Override
- public int getDisplayGroupId(int displayId) {
- synchronized (mSyncRoot) {
- return mLogicalDisplayMapper.getDisplayGroupIdLocked(displayId);
- }
+ public void registerDisplayGroupListener(DisplayGroupListener listener) {
+ mDisplayGroupListeners.add(listener);
+ }
+
+ @Override
+ public void unregisterDisplayGroupListener(DisplayGroupListener listener) {
+ mDisplayGroupListeners.remove(listener);
}
@Override
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 811625b..cb73c09 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -331,8 +331,10 @@
private BrightnessReason mBrightnessReasonTemp = new BrightnessReason();
// Brightness animation ramp rates in brightness units per second
- private final float mBrightnessRampRateSlow;
- private final float mBrightnessRampRateFast;
+ private float mBrightnessRampRateFastDecrease;
+ private float mBrightnessRampRateFastIncrease;
+ private float mBrightnessRampRateSlowDecrease;
+ private float mBrightnessRampRateSlowIncrease;
// Whether or not to skip the initial brightness ramps into STATE_ON.
@@ -459,10 +461,21 @@
mAllowAutoBrightnessWhileDozingConfig = resources.getBoolean(
com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing);
- mBrightnessRampRateFast = BrightnessSynchronizer.brightnessIntToFloat(resources.getInteger(
- com.android.internal.R.integer.config_brightness_ramp_rate_fast));
- mBrightnessRampRateSlow = BrightnessSynchronizer.brightnessIntToFloat(resources.getInteger(
- com.android.internal.R.integer.config_brightness_ramp_rate_slow));
+
+ DisplayDeviceConfig displayDeviceConfig = logicalDisplay
+ .getPrimaryDisplayDeviceLocked().getDisplayDeviceConfig();
+ // TODO: (b/178183143) Ensure that the ddc is not null
+ if (displayDeviceConfig != null) {
+ mBrightnessRampRateFastDecrease = displayDeviceConfig.getBrightnessRampFastDecrease();
+ mBrightnessRampRateFastIncrease = displayDeviceConfig.getBrightnessRampFastIncrease();
+ mBrightnessRampRateSlowDecrease = displayDeviceConfig.getBrightnessRampSlowDecrease();
+ mBrightnessRampRateSlowIncrease = displayDeviceConfig.getBrightnessRampSlowIncrease();
+ } else {
+ mBrightnessRampRateFastDecrease = 1.0f;
+ mBrightnessRampRateFastIncrease = 1.0f;
+ mBrightnessRampRateSlowDecrease = 1.0f;
+ mBrightnessRampRateSlowIncrease = 1.0f;
+ }
mSkipScreenOnBrightnessRamp = resources.getBoolean(
com.android.internal.R.bool.config_skipScreenOnBrightnessRamp);
@@ -683,6 +696,17 @@
// TODO: b/175821789 - Support high brightness on multiple (folding) displays
}
+ /**
+ * Unregisters all listeners and interrupts all running threads; halting future work.
+ *
+ * This method should be called when the DisplayPowerController is no longer in use; i.e. when
+ * the {@link #mDisplayId display} has been removed.
+ */
+ public void stop() {
+ mContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
+ mPowerState.stop();
+ }
+
private void sendUpdatePowerState() {
synchronized (mLock) {
sendUpdatePowerStateLocked();
@@ -772,7 +796,6 @@
boolean mustInitialize = false;
int brightnessAdjustmentFlags = 0;
mBrightnessReasonTemp.set(null);
-
synchronized (mLock) {
mPendingUpdatePowerStateLocked = false;
if (mPendingRequestLocked == null) {
@@ -1111,13 +1134,25 @@
// user even when the display is all black.
float animateValue = brightnessState == PowerManager.BRIGHTNESS_OFF_FLOAT
? PowerManager.BRIGHTNESS_MIN : brightnessState;
- if (isValidBrightnessValue(animateValue)) {
+ final float currentBrightness = mPowerState.getScreenBrightness();
+ if (isValidBrightnessValue(animateValue)
+ && !BrightnessSynchronizer.floatEquals(animateValue, currentBrightness)) {
if (initialRampSkip || hasBrightnessBuckets
|| wasOrWillBeInVr || !isDisplayContentVisible || brightnessIsTemporary) {
animateScreenBrightness(animateValue, SCREEN_ANIMATION_RATE_MINIMUM);
} else {
- animateScreenBrightness(animateValue,
- slowChange ? mBrightnessRampRateSlow : mBrightnessRampRateFast);
+ boolean isIncreasing = animateValue > currentBrightness;
+ final float rampSpeed;
+ if (isIncreasing && slowChange) {
+ rampSpeed = mBrightnessRampRateSlowIncrease;
+ } else if (isIncreasing && !slowChange) {
+ rampSpeed = mBrightnessRampRateFastIncrease;
+ } else if (!isIncreasing && slowChange) {
+ rampSpeed = mBrightnessRampRateSlowDecrease;
+ } else {
+ rampSpeed = mBrightnessRampRateFastDecrease;
+ }
+ animateScreenBrightness(animateValue, rampSpeed);
}
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index 54f30a9..51ba065 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -72,6 +72,8 @@
private Runnable mCleanListener;
+ private volatile boolean mStopped;
+
public DisplayPowerState(DisplayBlanker blanker, ColorFade colorFade, int displayId) {
mHandler = new Handler(true /*async*/);
mChoreographer = Choreographer.getInstance();
@@ -263,6 +265,18 @@
}
}
+ /**
+ * Interrupts all running threads; halting future work.
+ *
+ * This method should be called when the DisplayPowerState is no longer in use; i.e. when
+ * the {@link #mDisplayId display} has been removed.
+ */
+ public void stop() {
+ mHandler.removeCallbacksAndMessages(null);
+ mStopped = true;
+ mPhotonicModulator.interrupt();
+ }
+
public void dump(PrintWriter pw) {
pw.println();
pw.println("Display Power State:");
@@ -427,7 +441,11 @@
if (!stateChanged && !backlightChanged) {
try {
mLock.wait();
- } catch (InterruptedException ex) { }
+ } catch (InterruptedException ex) {
+ if (mStopped) {
+ return;
+ }
+ }
continue;
}
mActualState = state;
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index bb2fbed..ecb837d 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -17,7 +17,6 @@
package com.android.server.display;
import android.content.Context;
-import android.os.Process;
import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.IndentingPrintWriter;
@@ -55,6 +54,10 @@
public static final int LOGICAL_DISPLAY_EVENT_SWAPPED = 4;
public static final int LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED = 5;
+ public static final int DISPLAY_GROUP_EVENT_ADDED = 1;
+ public static final int DISPLAY_GROUP_EVENT_CHANGED = 2;
+ public static final int DISPLAY_GROUP_EVENT_REMOVED = 3;
+
/**
* Temporary display info, used for comparing display configurations.
*/
@@ -99,7 +102,7 @@
private int mNextNonDefaultGroupId = DisplayGroup.DEFAULT + 1;
/** A mapping from logical display id to display group. */
- private final SparseArray<DisplayGroup> mDisplayGroups = new SparseArray<>();
+ private final SparseArray<DisplayGroup> mDisplayIdToGroupMap = new SparseArray<>();
private final DisplayDeviceRepository mDisplayDeviceRepo;
private final Listener mListener;
@@ -154,10 +157,6 @@
return null;
}
- public int[] getDisplayIdsLocked() {
- return getDisplayIdsLocked(Process.SYSTEM_UID);
- }
-
public int[] getDisplayIdsLocked(int callingUid) {
final int count = mLogicalDisplays.size();
int[] displayIds = new int[count];
@@ -182,13 +181,16 @@
}
}
- public int getDisplayGroupIdLocked(int displayId) {
- final DisplayGroup displayGroup = mDisplayGroups.get(displayId);
- if (displayGroup != null) {
- return displayGroup.getGroupId();
+ public DisplayGroup getDisplayGroupLocked(int groupId) {
+ final int size = mDisplayIdToGroupMap.size();
+ for (int i = 0; i < size; i++) {
+ final DisplayGroup displayGroup = mDisplayIdToGroupMap.valueAt(i);
+ if (displayGroup.getGroupId() == groupId) {
+ return displayGroup;
+ }
}
- return -1;
+ return null;
}
public void dumpLocked(PrintWriter pw) {
@@ -325,17 +327,31 @@
mLogicalDisplays.put(displayId, display);
final DisplayGroup displayGroup;
- if (isDefault || (deviceInfo.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP) != 0) {
+ final boolean addNewDisplayGroup =
+ isDefault || (deviceInfo.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP) != 0;
+ if (addNewDisplayGroup) {
final int groupId = assignDisplayGroupIdLocked(isDefault);
displayGroup = new DisplayGroup(groupId);
} else {
- displayGroup = mDisplayGroups.get(Display.DEFAULT_DISPLAY);
+ displayGroup = mDisplayIdToGroupMap.get(Display.DEFAULT_DISPLAY);
}
- displayGroup.addDisplay(display);
- mDisplayGroups.append(displayId, displayGroup);
+ displayGroup.addDisplayLocked(display);
+ mDisplayIdToGroupMap.append(displayId, displayGroup);
+
+ if (addNewDisplayGroup) {
+ // Group added events happen before Logical Display added events.
+ mListener.onDisplayGroupEventLocked(displayGroup.getGroupId(),
+ LogicalDisplayMapper.DISPLAY_GROUP_EVENT_ADDED);
+ }
mListener.onLogicalDisplayEventLocked(display,
LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_ADDED);
+
+ if (!addNewDisplayGroup) {
+ // Group changed events happen after Logical Display added events.
+ mListener.onDisplayGroupEventLocked(displayGroup.getGroupId(),
+ LogicalDisplayMapper.DISPLAY_GROUP_EVENT_CHANGED);
+ }
}
/**
@@ -352,31 +368,45 @@
DisplayEventReceiver.FrameRateOverride[] frameRatesOverrides =
display.getFrameRateOverrides();
display.updateLocked(mDisplayDeviceRepo);
+ final DisplayGroup changedDisplayGroup;
if (!display.isValidLocked()) {
mLogicalDisplays.removeAt(i);
- mDisplayGroups.removeReturnOld(displayId).removeDisplay(display);
+ final DisplayGroup displayGroup = mDisplayIdToGroupMap.removeReturnOld(displayId);
+ displayGroup.removeDisplayLocked(display);
mListener.onLogicalDisplayEventLocked(display,
LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_REMOVED);
+
+ changedDisplayGroup = displayGroup;
} else if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) {
final int flags = display.getDisplayInfoLocked().flags;
- final DisplayGroup defaultDisplayGroup = mDisplayGroups.get(
+ final DisplayGroup defaultDisplayGroup = mDisplayIdToGroupMap.get(
Display.DEFAULT_DISPLAY);
if ((flags & Display.FLAG_OWN_DISPLAY_GROUP) != 0) {
// The display should have its own DisplayGroup.
- if (defaultDisplayGroup.removeDisplay(display)) {
+ if (defaultDisplayGroup.removeDisplayLocked(display)) {
final int groupId = assignDisplayGroupIdLocked(false);
final DisplayGroup displayGroup = new DisplayGroup(groupId);
- displayGroup.addDisplay(display);
- mDisplayGroups.append(display.getDisplayIdLocked(), displayGroup);
+ displayGroup.addDisplayLocked(display);
+ mDisplayIdToGroupMap.append(display.getDisplayIdLocked(), displayGroup);
+ mListener.onDisplayGroupEventLocked(displayGroup.getGroupId(),
+ LogicalDisplayMapper.DISPLAY_GROUP_EVENT_ADDED);
+ changedDisplayGroup = defaultDisplayGroup;
+ } else {
+ changedDisplayGroup = null;
}
} else {
// The display should be a part of the default DisplayGroup.
- final DisplayGroup displayGroup = mDisplayGroups.get(displayId);
+ final DisplayGroup displayGroup = mDisplayIdToGroupMap.get(displayId);
if (displayGroup != defaultDisplayGroup) {
- displayGroup.removeDisplay(display);
- defaultDisplayGroup.addDisplay(display);
- mDisplayGroups.put(displayId, defaultDisplayGroup);
+ displayGroup.removeDisplayLocked(display);
+ defaultDisplayGroup.addDisplayLocked(display);
+ mListener.onDisplayGroupEventLocked(displayGroup.getGroupId(),
+ LogicalDisplayMapper.DISPLAY_GROUP_EVENT_CHANGED);
+ mDisplayIdToGroupMap.put(displayId, defaultDisplayGroup);
+ changedDisplayGroup = displayGroup;
+ } else {
+ changedDisplayGroup = null;
}
}
@@ -388,6 +418,7 @@
} else if (!display.getPendingFrameRateOverrideUids().isEmpty()) {
mListener.onLogicalDisplayEventLocked(display,
LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED);
+ changedDisplayGroup = null;
} else {
// While applications shouldn't know nor care about the non-overridden info, we
// still need to let WindowManager know so it can update its own internal state for
@@ -397,6 +428,15 @@
mListener.onLogicalDisplayEventLocked(display,
LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_CHANGED);
}
+ changedDisplayGroup = null;
+ }
+
+ // CHANGED and REMOVED DisplayGroup events should always fire after Display events.
+ if (changedDisplayGroup != null) {
+ final int event = changedDisplayGroup.isEmptyLocked()
+ ? LogicalDisplayMapper.DISPLAY_GROUP_EVENT_REMOVED
+ : LogicalDisplayMapper.DISPLAY_GROUP_EVENT_CHANGED;
+ mListener.onDisplayGroupEventLocked(changedDisplayGroup.getGroupId(), event);
}
}
}
@@ -432,6 +472,7 @@
public interface Listener {
void onLogicalDisplayEventLocked(LogicalDisplay display, int event);
+ void onDisplayGroupEventLocked(int groupId, int event);
void onTraversalRequested();
}
}
diff --git a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
index a0d9e8e..425e3ab 100644
--- a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
+++ b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
@@ -31,6 +31,8 @@
import com.android.internal.annotations.GuardedBy;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.security.FileIntegrityService;
+import com.android.server.security.VerityUtils;
import java.io.File;
import java.io.FileDescriptor;
@@ -39,6 +41,7 @@
import java.nio.ByteBuffer;
import java.nio.NioUtils;
import java.nio.channels.FileChannel;
+import java.util.Arrays;
import java.util.Map;
/** A service for managing system fonts. */
@@ -78,7 +81,17 @@
private static class OtfFontFileParser implements UpdatableFontDir.FontFileParser {
@Override
- public long getVersion(File file) throws IOException {
+ public String getPostScriptName(File file) throws IOException {
+ ByteBuffer buffer = mmap(file);
+ try {
+ return FontFileUtil.getPostScriptName(buffer, 0);
+ } finally {
+ NioUtils.freeDirectBuffer(buffer);
+ }
+ }
+
+ @Override
+ public long getRevision(File file) throws IOException {
ByteBuffer buffer = mmap(file);
try {
return FontFileUtil.getRevision(buffer, 0);
@@ -95,18 +108,48 @@
}
}
+ private static class FsverityUtilImpl implements UpdatableFontDir.FsverityUtil {
+ @Override
+ public boolean hasFsverity(String filePath) {
+ return VerityUtils.hasFsverity(filePath);
+ }
+
+ @Override
+ public void setUpFsverity(String filePath, byte[] pkcs7Signature) throws IOException {
+ VerityUtils.setUpFsverity(filePath, pkcs7Signature);
+ }
+
+ @Override
+ public boolean rename(File src, File dest) {
+ // rename system call preserves fs-verity bit.
+ return src.renameTo(dest);
+ }
+ }
+
@Nullable
private final UpdatableFontDir mUpdatableFontDir;
@GuardedBy("FontManagerService.this")
- @Nullable SystemFontSettings mCurrentFontSettings = null;
+ @Nullable
+ private SystemFontSettings mCurrentFontSettings = null;
private FontManagerService() {
- mUpdatableFontDir = ENABLE_FONT_UPDATES
- ? new UpdatableFontDir(new File(FONT_FILES_DIR), new OtfFontFileParser()) : null;
+ mUpdatableFontDir = createUpdatableFontDir();
}
- @NonNull private SystemFontSettings getCurrentFontSettings() {
+ @Nullable
+ private static UpdatableFontDir createUpdatableFontDir() {
+ if (!ENABLE_FONT_UPDATES) return null;
+ // If apk verity is supported, fs-verity should be available.
+ if (!FileIntegrityService.isApkVeritySupported()) return null;
+ return new UpdatableFontDir(new File(FONT_FILES_DIR),
+ Arrays.asList(new File(SystemFonts.SYSTEM_FONT_DIR),
+ new File(SystemFonts.OEM_FONT_DIR)),
+ new OtfFontFileParser(), new FsverityUtilImpl());
+ }
+
+ @NonNull
+ private SystemFontSettings getCurrentFontSettings() {
synchronized (FontManagerService.this) {
if (mCurrentFontSettings == null) {
mCurrentFontSettings = SystemFontSettings.create(mUpdatableFontDir);
@@ -115,13 +158,14 @@
}
}
- private boolean installFontFile(String name, FileDescriptor fd) {
+ // TODO(b/173619554): Expose as API.
+ private boolean installFontFile(FileDescriptor fd, byte[] pkcs7Signature) {
if (mUpdatableFontDir == null) return false;
synchronized (FontManagerService.this) {
try {
- mUpdatableFontDir.installFontFile(name, fd);
+ mUpdatableFontDir.installFontFile(fd, pkcs7Signature);
} catch (IOException e) {
- Slog.w(TAG, "Failed to install font file: " + name, e);
+ Slog.w(TAG, "Failed to install font file");
return false;
}
// Create updated font map in the next getSerializedSystemFontMap() call.
@@ -194,5 +238,5 @@
}
return null;
}
- };
+ }
}
diff --git a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
index 7306471..8da579f 100644
--- a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
+++ b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
@@ -16,6 +16,7 @@
package com.android.server.graphics.fonts;
+import android.annotation.Nullable;
import android.os.FileUtils;
import android.util.Base64;
import android.util.Slog;
@@ -28,71 +29,158 @@
import java.io.IOException;
import java.security.SecureRandom;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
final class UpdatableFontDir {
private static final String TAG = "UpdatableFontDir";
private static final String RANDOM_DIR_PREFIX = "~~";
+ // TODO: Support .otf
+ private static final String ALLOWED_EXTENSION = ".ttf";
/** Interface to mock font file access in tests. */
interface FontFileParser {
- long getVersion(File file) throws IOException;
+ String getPostScriptName(File file) throws IOException;
+
+ long getRevision(File file) throws IOException;
}
- /** Data class to hold font file path and version. */
- static final class FontFileInfo {
- final File mFile;
- final long mVersion;
+ /** Interface to mock fs-verity in tests. */
+ interface FsverityUtil {
+ boolean hasFsverity(String path);
- FontFileInfo(File file, long version) {
+ void setUpFsverity(String path, byte[] pkcs7Signature) throws IOException;
+
+ boolean rename(File src, File dest);
+ }
+
+ /** Data class to hold font file path and revision. */
+ private static final class FontFileInfo {
+ private final File mFile;
+ private final long mRevision;
+
+ FontFileInfo(File file, long revision) {
mFile = file;
- mVersion = version;
+ mRevision = revision;
+ }
+
+ public File getFile() {
+ return mFile;
+ }
+
+ /** Returns the unique randomized font dir containing this font file. */
+ public File getRandomizedFontDir() {
+ return mFile.getParentFile();
+ }
+
+ public long getRevision() {
+ return mRevision;
}
}
/**
- * Root directory for storing updated font files. Each font file is stored in a unique random
- * dir. The font file path would be {@code mFilesDir/~~{randomStr}/{fontFileName}}.
+ * Root directory for storing updated font files. Each font file is stored in a unique
+ * randomized dir. The font file path would be {@code mFilesDir/~~{randomStr}/{fontFileName}}.
*/
private final File mFilesDir;
+ private final List<File> mPreinstalledFontDirs;
private final FontFileParser mParser;
+ private final FsverityUtil mFsverityUtil;
+ /**
+ * A mutable map containing mapping from font file name (e.g. "NotoColorEmoji.ttf") to {@link
+ * FontFileInfo}. All files in this map are validated, and have higher revision numbers than
+ * corresponding font files in {@link #mPreinstalledFontDirs}.
+ */
@GuardedBy("UpdatableFontDir.this")
private final Map<String, FontFileInfo> mFontFileInfoMap = new HashMap<>();
- UpdatableFontDir(File filesDir, FontFileParser parser) {
+ UpdatableFontDir(File filesDir, List<File> preinstalledFontDirs, FontFileParser parser,
+ FsverityUtil fsverityUtil) {
mFilesDir = filesDir;
+ mPreinstalledFontDirs = preinstalledFontDirs;
mParser = parser;
+ mFsverityUtil = fsverityUtil;
loadFontFileMap();
}
private void loadFontFileMap() {
+ // TODO: SIGBUS crash protection
synchronized (UpdatableFontDir.this) {
+ boolean success = false;
mFontFileInfoMap.clear();
- File[] dirs = mFilesDir.listFiles();
- if (dirs == null) return;
- for (File dir : dirs) {
- if (!dir.getName().startsWith(RANDOM_DIR_PREFIX)) continue;
- File[] files = dir.listFiles();
- if (files == null || files.length != 1) continue;
- addFileToMapLocked(files[0], true);
+ try {
+ File[] dirs = mFilesDir.listFiles();
+ if (dirs == null) return;
+ for (File dir : dirs) {
+ if (!dir.getName().startsWith(RANDOM_DIR_PREFIX)) return;
+ File[] files = dir.listFiles();
+ if (files == null || files.length != 1) return;
+ FontFileInfo fontFileInfo = validateFontFile(files[0]);
+ if (fontFileInfo == null) {
+ Slog.w(TAG, "Broken file is found. Clearing files.");
+ return;
+ }
+ addFileToMapLocked(fontFileInfo, true /* deleteOldFile */);
+ }
+ success = true;
+ } finally {
+ // Delete all files just in case if we find a problematic file.
+ if (!success) {
+ mFontFileInfoMap.clear();
+ FileUtils.deleteContents(mFilesDir);
+ }
}
}
}
- void installFontFile(String name, FileDescriptor fd) throws IOException {
- // TODO: Validate name.
+ /**
+ * Installs a new font file, or updates an existing font file.
+ *
+ * <p>The new font will be immediately available for new Zygote-forked processes through
+ * {@link #getFontFileMap()}. Old font files will be kept until next system server reboot,
+ * because existing Zygote-forked processes have paths to old font files.
+ *
+ * @param fd A file descriptor to the font file.
+ * @param pkcs7Signature A PKCS#7 detached signature to enable fs-verity for the font file.
+ */
+ void installFontFile(FileDescriptor fd, byte[] pkcs7Signature) throws IOException {
synchronized (UpdatableFontDir.this) {
- // TODO: proper error handling
File newDir = getRandomDir(mFilesDir);
if (!newDir.mkdir()) {
+ // TODO: Define and return an error code for API
throw new IOException("Failed to create a new dir");
}
- File newFontFile = new File(newDir, name);
- try (FileOutputStream out = new FileOutputStream(newFontFile)) {
- FileUtils.copy(fd, out.getFD());
+ boolean success = false;
+ try {
+ File tempNewFontFile = new File(newDir, "font.ttf");
+ try (FileOutputStream out = new FileOutputStream(tempNewFontFile)) {
+ FileUtils.copy(fd, out.getFD());
+ }
+ // Do not parse font file before setting up fs-verity.
+ // setUpFsverity throws IOException if failed.
+ mFsverityUtil.setUpFsverity(tempNewFontFile.getAbsolutePath(), pkcs7Signature);
+ String postScriptName = mParser.getPostScriptName(tempNewFontFile);
+ File newFontFile = new File(newDir, postScriptName + ALLOWED_EXTENSION);
+ if (!mFsverityUtil.rename(tempNewFontFile, newFontFile)) {
+ // TODO: Define and return an error code for API
+ throw new IOException("Failed to rename");
+ }
+ FontFileInfo fontFileInfo = validateFontFile(newFontFile);
+ if (fontFileInfo == null) {
+ // TODO: Define and return an error code for API
+ throw new IllegalArgumentException("Invalid file");
+ }
+ if (!addFileToMapLocked(fontFileInfo, false)) {
+ // TODO: Define and return an error code for API
+ throw new IllegalArgumentException("Version downgrade");
+ }
+ success = true;
+ } finally {
+ if (!success) {
+ FileUtils.deleteContentsAndDir(newDir);
+ }
}
- addFileToMapLocked(newFontFile, false);
}
}
@@ -114,27 +202,110 @@
return dir;
}
- private void addFileToMapLocked(File file, boolean deleteOldFile) {
- final long version;
+ /**
+ * Add the given {@link FontFileInfo} to {@link #mFontFileInfoMap} if its font revision is
+ * higher than the currently used font file (either in {@link #mFontFileInfoMap} or {@link
+ * #mPreinstalledFontDirs}).
+ */
+ private boolean addFileToMapLocked(FontFileInfo fontFileInfo, boolean deleteOldFile) {
+ String name = fontFileInfo.getFile().getName();
+ FontFileInfo existingInfo = mFontFileInfoMap.get(name);
+ final boolean shouldAddToMap;
+ if (existingInfo == null) {
+ // We got a new updatable font. We need to check if it's newer than preinstalled fonts.
+ // Note that getPreinstalledFontRevision() returns -1 if there is no preinstalled font
+ // with 'name'.
+ shouldAddToMap = getPreinstalledFontRevision(name) < fontFileInfo.getRevision();
+ } else {
+ shouldAddToMap = existingInfo.getRevision() < fontFileInfo.getRevision();
+ }
+ if (shouldAddToMap) {
+ if (deleteOldFile && existingInfo != null) {
+ FileUtils.deleteContentsAndDir(existingInfo.getRandomizedFontDir());
+ }
+ mFontFileInfoMap.put(name, fontFileInfo);
+ return true;
+ } else {
+ if (deleteOldFile) {
+ FileUtils.deleteContentsAndDir(fontFileInfo.getRandomizedFontDir());
+ }
+ return false;
+ }
+ }
+
+ private long getPreinstalledFontRevision(String name) {
+ long maxRevision = -1;
+ for (File dir : mPreinstalledFontDirs) {
+ File preinstalledFontFile = new File(dir, name);
+ if (!preinstalledFontFile.exists()) continue;
+ long revision = getFontRevision(preinstalledFontFile);
+ if (revision == -1) {
+ Slog.w(TAG, "Invalid preinstalled font file");
+ continue;
+ }
+ if (revision > maxRevision) {
+ maxRevision = revision;
+ }
+ }
+ return maxRevision;
+ }
+
+ /**
+ * Checks the fs-verity protection status of the given font file, validates the file name, and
+ * returns a {@link FontFileInfo} on success. This method does not check if the font revision
+ * is higher than the currently used font.
+ */
+ @Nullable
+ private FontFileInfo validateFontFile(File file) {
+ if (!mFsverityUtil.hasFsverity(file.getAbsolutePath())) {
+ Slog.w(TAG, "Font validation failed. Fs-verity is not enabled: " + file);
+ return null;
+ }
+ if (!validateFontFileName(file)) {
+ Slog.w(TAG, "Font validation failed. Could not validate font file name: " + file);
+ return null;
+ }
+ long revision = getFontRevision(file);
+ if (revision == -1) {
+ Slog.w(TAG, "Font validation failed. Could not read font revision: " + file);
+ return null;
+ }
+ return new FontFileInfo(file, revision);
+ }
+
+ /**
+ * Returns true if the font file's file name matches with the PostScript name metadata in the
+ * font file.
+ *
+ * <p>We check the font file names because apps use file name to look up fonts.
+ * <p>Because PostScript name does not include extension, the extension is appended for
+ * comparison. For example, if the file name is "NotoColorEmoji.ttf", the PostScript name should
+ * be "NotoColorEmoji".
+ */
+ private boolean validateFontFileName(File file) {
+ String fileName = file.getName();
+ String postScriptName = getPostScriptName(file);
+ return (postScriptName + ALLOWED_EXTENSION).equals(fileName);
+ }
+
+ /** Returns the PostScript name of the given font file, or null. */
+ @Nullable
+ private String getPostScriptName(File file) {
try {
- version = mParser.getVersion(file);
+ return mParser.getPostScriptName(file);
} catch (IOException e) {
Slog.e(TAG, "Failed to read font file", e);
- return;
+ return null;
}
- if (version == -1) {
- Slog.e(TAG, "Invalid font file");
- return;
- }
- FontFileInfo info = mFontFileInfoMap.get(file.getName());
- if (info == null) {
- // TODO: check version of font in /system/fonts and /product/fonts
- mFontFileInfoMap.put(file.getName(), new FontFileInfo(file, version));
- } else if (info.mVersion < version) {
- if (deleteOldFile) {
- FileUtils.deleteContentsAndDir(info.mFile.getParentFile());
- }
- mFontFileInfoMap.put(file.getName(), new FontFileInfo(file, version));
+ }
+
+ /** Returns the non-negative font revision of the given font file, or -1. */
+ private long getFontRevision(File file) {
+ try {
+ return mParser.getRevision(file);
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to read font file", e);
+ return -1;
}
}
@@ -142,7 +313,7 @@
Map<String, File> map = new HashMap<>();
synchronized (UpdatableFontDir.this) {
for (Map.Entry<String, FontFileInfo> entry : mFontFileInfoMap.entrySet()) {
- map.put(entry.getKey(), entry.getValue().mFile);
+ map.put(entry.getKey(), entry.getValue().getFile());
}
}
return map;
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index ab7e3b0..143ec15 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -167,6 +167,7 @@
import com.android.internal.inputmethod.IInputMethodSubtypeListResultCallback;
import com.android.internal.inputmethod.IInputMethodSubtypeResultCallback;
import com.android.internal.inputmethod.IIntResultCallback;
+import com.android.internal.inputmethod.IVoidResultCallback;
import com.android.internal.inputmethod.InputMethodDebug;
import com.android.internal.inputmethod.SoftInputShowHideReason;
import com.android.internal.inputmethod.StartInputFlags;
@@ -3720,38 +3721,43 @@
}
@Override
- public void showInputMethodPickerFromClient(
- IInputMethodClient client, int auxiliarySubtypeMode) {
- synchronized (mMethodMap) {
- if (!calledFromValidUserLocked()) {
- return;
- }
- if(!canShowInputMethodPickerLocked(client)) {
- Slog.w(TAG, "Ignoring showInputMethodPickerFromClient of uid "
- + Binder.getCallingUid() + ": " + client);
- return;
- }
+ public void showInputMethodPickerFromClient(IInputMethodClient client, int auxiliarySubtypeMode,
+ IVoidResultCallback resultCallback) {
+ CallbackUtils.onResult(resultCallback, () -> {
+ synchronized (mMethodMap) {
+ if (!calledFromValidUserLocked()) {
+ return;
+ }
+ if (!canShowInputMethodPickerLocked(client)) {
+ Slog.w(TAG, "Ignoring showInputMethodPickerFromClient of uid "
+ + Binder.getCallingUid() + ": " + client);
+ return;
+ }
- // Always call subtype picker, because subtype picker is a superset of input method
- // picker.
- mHandler.sendMessage(mCaller.obtainMessageII(
- MSG_SHOW_IM_SUBTYPE_PICKER, auxiliarySubtypeMode,
- (mCurClient != null) ? mCurClient.selfReportedDisplayId : DEFAULT_DISPLAY));
- }
+ // Always call subtype picker, because subtype picker is a superset of input method
+ // picker.
+ mHandler.sendMessage(mCaller.obtainMessageII(
+ MSG_SHOW_IM_SUBTYPE_PICKER, auxiliarySubtypeMode,
+ (mCurClient != null) ? mCurClient.selfReportedDisplayId : DEFAULT_DISPLAY));
+ }
+ });
}
@Override
public void showInputMethodPickerFromSystem(IInputMethodClient client, int auxiliarySubtypeMode,
- int displayId) {
- if (mContext.checkCallingPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException(
- "showInputMethodPickerFromSystem requires WRITE_SECURE_SETTINGS permission");
- }
- // Always call subtype picker, because subtype picker is a superset of input method
- // picker.
- mHandler.sendMessage(mCaller.obtainMessageII(
- MSG_SHOW_IM_SUBTYPE_PICKER, auxiliarySubtypeMode, displayId));
+ int displayId, IVoidResultCallback resultCallback) {
+ CallbackUtils.onResult(resultCallback, () -> {
+ if (mContext.checkCallingPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException(
+ "showInputMethodPickerFromSystem requires WRITE_SECURE_SETTINGS "
+ + "permission");
+ }
+ // Always call subtype picker, because subtype picker is a superset of input method
+ // picker.
+ mHandler.sendMessage(mCaller.obtainMessageII(
+ MSG_SHOW_IM_SUBTYPE_PICKER, auxiliarySubtypeMode, displayId));
+ });
}
/**
@@ -3795,15 +3801,17 @@
@Override
public void showInputMethodAndSubtypeEnablerFromClient(
- IInputMethodClient client, String inputMethodId) {
- synchronized (mMethodMap) {
- // TODO(yukawa): Should we verify the display ID?
- if (!calledFromValidUserLocked()) {
- return;
+ IInputMethodClient client, String inputMethodId, IVoidResultCallback resultCallback) {
+ CallbackUtils.onResult(resultCallback, () -> {
+ synchronized (mMethodMap) {
+ // TODO(yukawa): Should we verify the display ID?
+ if (!calledFromValidUserLocked()) {
+ return;
+ }
+ executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
+ MSG_SHOW_IM_SUBTYPE_ENABLER, inputMethodId));
}
- executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
- MSG_SHOW_IM_SUBTYPE_ENABLER, inputMethodId));
- }
+ });
}
@BinderThread
@@ -4011,84 +4019,87 @@
@Override
public void reportActivityView(IInputMethodClient parentClient, int childDisplayId,
- float[] matrixValues) {
- final DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(childDisplayId);
- if (displayInfo == null) {
- throw new IllegalArgumentException(
- "Cannot find display for non-existent displayId: " + childDisplayId);
- }
- final int callingUid = Binder.getCallingUid();
- if (callingUid != displayInfo.ownerUid) {
- throw new SecurityException("The caller doesn't own the display.");
- }
-
- synchronized (mMethodMap) {
- final ClientState cs = mClients.get(parentClient.asBinder());
- if (cs == null) {
- return;
+ float[] matrixValues, IVoidResultCallback resultCallback) {
+ CallbackUtils.onResult(resultCallback, () -> {
+ final DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(childDisplayId);
+ if (displayInfo == null) {
+ throw new IllegalArgumentException(
+ "Cannot find display for non-existent displayId: " + childDisplayId);
+ }
+ final int callingUid = Binder.getCallingUid();
+ if (callingUid != displayInfo.ownerUid) {
+ throw new SecurityException("The caller doesn't own the display.");
}
- // null matrixValues means that the entry needs to be removed.
- if (matrixValues == null) {
- final ActivityViewInfo info = mActivityViewDisplayIdToParentMap.get(childDisplayId);
- if (info == null) {
+ synchronized (mMethodMap) {
+ final ClientState cs = mClients.get(parentClient.asBinder());
+ if (cs == null) {
return;
}
- if (info.mParentClient != cs) {
- throw new SecurityException("Only the owner client can clear"
- + " ActivityViewGeometry for display #" + childDisplayId);
- }
- mActivityViewDisplayIdToParentMap.remove(childDisplayId);
- return;
- }
- ActivityViewInfo info = mActivityViewDisplayIdToParentMap.get(childDisplayId);
- if (info != null && info.mParentClient != cs) {
- throw new InvalidParameterException("Display #" + childDisplayId
- + " is already registered by " + info.mParentClient);
- }
- if (info == null) {
- if (!mWindowManagerInternal.isUidAllowedOnDisplay(childDisplayId, cs.uid)) {
- throw new SecurityException(cs + " cannot access to display #"
- + childDisplayId);
- }
- info = new ActivityViewInfo(cs, new Matrix());
- mActivityViewDisplayIdToParentMap.put(childDisplayId, info);
- }
- info.mMatrix.setValues(matrixValues);
-
- if (mCurClient == null || mCurClient.curSession == null) {
- return;
- }
-
- Matrix matrix = null;
- int displayId = mCurClient.selfReportedDisplayId;
- boolean needToNotify = false;
- while (true) {
- needToNotify |= (displayId == childDisplayId);
- final ActivityViewInfo next = mActivityViewDisplayIdToParentMap.get(displayId);
- if (next == null) {
- break;
- }
- if (matrix == null) {
- matrix = new Matrix(next.mMatrix);
- } else {
- matrix.postConcat(next.mMatrix);
- }
- if (next.mParentClient.selfReportedDisplayId == mCurTokenDisplayId) {
- if (needToNotify) {
- final float[] values = new float[9];
- matrix.getValues(values);
- try {
- mCurClient.client.updateActivityViewToScreenMatrix(mCurSeq, values);
- } catch (RemoteException e) {
- }
+ // null matrixValues means that the entry needs to be removed.
+ if (matrixValues == null) {
+ final ActivityViewInfo info =
+ mActivityViewDisplayIdToParentMap.get(childDisplayId);
+ if (info == null) {
+ return;
}
- break;
+ if (info.mParentClient != cs) {
+ throw new SecurityException("Only the owner client can clear"
+ + " ActivityViewGeometry for display #" + childDisplayId);
+ }
+ mActivityViewDisplayIdToParentMap.remove(childDisplayId);
+ return;
}
- displayId = info.mParentClient.selfReportedDisplayId;
+
+ ActivityViewInfo info = mActivityViewDisplayIdToParentMap.get(childDisplayId);
+ if (info != null && info.mParentClient != cs) {
+ throw new InvalidParameterException("Display #" + childDisplayId
+ + " is already registered by " + info.mParentClient);
+ }
+ if (info == null) {
+ if (!mWindowManagerInternal.isUidAllowedOnDisplay(childDisplayId, cs.uid)) {
+ throw new SecurityException(cs + " cannot access to display #"
+ + childDisplayId);
+ }
+ info = new ActivityViewInfo(cs, new Matrix());
+ mActivityViewDisplayIdToParentMap.put(childDisplayId, info);
+ }
+ info.mMatrix.setValues(matrixValues);
+
+ if (mCurClient == null || mCurClient.curSession == null) {
+ return;
+ }
+
+ Matrix matrix = null;
+ int displayId = mCurClient.selfReportedDisplayId;
+ boolean needToNotify = false;
+ while (true) {
+ needToNotify |= (displayId == childDisplayId);
+ final ActivityViewInfo next = mActivityViewDisplayIdToParentMap.get(displayId);
+ if (next == null) {
+ break;
+ }
+ if (matrix == null) {
+ matrix = new Matrix(next.mMatrix);
+ } else {
+ matrix.postConcat(next.mMatrix);
+ }
+ if (next.mParentClient.selfReportedDisplayId == mCurTokenDisplayId) {
+ if (needToNotify) {
+ final float[] values = new float[9];
+ matrix.getValues(values);
+ try {
+ mCurClient.client.updateActivityViewToScreenMatrix(mCurSeq, values);
+ } catch (RemoteException e) {
+ }
+ }
+ break;
+ }
+ displayId = info.mParentClient.selfReportedDisplayId;
+ }
}
- }
+ });
}
@Override
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index 3485881..2dd7096 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -82,6 +82,7 @@
import com.android.internal.inputmethod.IMultiClientInputMethod;
import com.android.internal.inputmethod.IMultiClientInputMethodPrivilegedOperations;
import com.android.internal.inputmethod.IMultiClientInputMethodSession;
+import com.android.internal.inputmethod.IVoidResultCallback;
import com.android.internal.inputmethod.SoftInputShowHideReason;
import com.android.internal.inputmethod.StartInputFlags;
import com.android.internal.inputmethod.StartInputReason;
@@ -1776,23 +1777,26 @@
@BinderThread
@Override
- public void showInputMethodPickerFromClient(
- IInputMethodClient client, int auxiliarySubtypeMode) {
+ public void showInputMethodPickerFromClient(IInputMethodClient client,
+ int auxiliarySubtypeMode, IVoidResultCallback resultCallback) {
reportNotSupported();
+ CallbackUtils.onResult(resultCallback, () -> { });
}
@BinderThread
@Override
- public void showInputMethodPickerFromSystem(
- IInputMethodClient client, int auxiliarySubtypeMode, int displayId) {
+ public void showInputMethodPickerFromSystem(IInputMethodClient client,
+ int auxiliarySubtypeMode, int displayId, IVoidResultCallback resultCallback) {
reportNotSupported();
+ CallbackUtils.onResult(resultCallback, () -> { });
}
@BinderThread
@Override
- public void showInputMethodAndSubtypeEnablerFromClient(
- IInputMethodClient client, String inputMethodId) {
+ public void showInputMethodAndSubtypeEnablerFromClient(IInputMethodClient client,
+ String inputMethodId, IVoidResultCallback resultCallback) {
reportNotSupported();
+ CallbackUtils.onResult(resultCallback, () -> { });
}
@BinderThread
@@ -1825,8 +1829,9 @@
@BinderThread
@Override
public void reportActivityView(IInputMethodClient parentClient, int childDisplayId,
- float[] matrixValues) {
+ float[] matrixValues, IVoidResultCallback resultCallback) {
reportNotSupported();
+ CallbackUtils.onResult(resultCallback, () -> { });
}
@BinderThread
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 9f351a3..28c90e9 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -88,6 +88,7 @@
import android.provider.Settings;
import android.provider.Settings.Secure;
import android.provider.Settings.SettingNotFoundException;
+import android.security.Authorization;
import android.security.KeyStore;
import android.security.keystore.AndroidKeyStoreProvider;
import android.security.keystore.KeyProperties;
@@ -1268,6 +1269,7 @@
private void unlockKeystore(byte[] password, int userHandle) {
if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle);
+ new Authorization().onLockScreenEvent(false, userHandle, password);
// TODO(b/120484642): Update keystore to accept byte[] passwords
String passwordString = password == null ? null : new String(password);
final KeyStore ks = KeyStore.getInstance();
diff --git a/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java b/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java
new file mode 100644
index 0000000..8399f54
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.locksettings;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ParcelableException;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.DeviceConfig;
+import android.service.resumeonreboot.IResumeOnRebootService;
+import android.service.resumeonreboot.ResumeOnRebootService;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/** @hide */
+public class ResumeOnRebootServiceProvider {
+
+ private static final String PROVIDER_PACKAGE = DeviceConfig.getString(
+ DeviceConfig.NAMESPACE_OTA, "resume_on_reboot_service_package", "");
+ private static final String PROVIDER_REQUIRED_PERMISSION =
+ Manifest.permission.BIND_RESUME_ON_REBOOT_SERVICE;
+ private static final String TAG = "ResumeOnRebootServiceProvider";
+
+ private final Context mContext;
+ private final PackageManager mPackageManager;
+
+ public ResumeOnRebootServiceProvider(Context context) {
+ this(context, context.getPackageManager());
+ }
+
+ @VisibleForTesting
+ public ResumeOnRebootServiceProvider(Context context, PackageManager packageManager) {
+ this.mContext = context;
+ this.mPackageManager = packageManager;
+ }
+
+ @Nullable
+ private ServiceInfo resolveService() {
+ Intent intent = new Intent();
+ intent.setAction(ResumeOnRebootService.SERVICE_INTERFACE);
+ if (PROVIDER_PACKAGE != null && !PROVIDER_PACKAGE.equals("")) {
+ intent.setPackage(PROVIDER_PACKAGE);
+ }
+
+ List<ResolveInfo> resolvedIntents =
+ mPackageManager.queryIntentServices(intent, PackageManager.MATCH_SYSTEM_ONLY);
+ for (ResolveInfo resolvedInfo : resolvedIntents) {
+ if (resolvedInfo.serviceInfo != null
+ && PROVIDER_REQUIRED_PERMISSION.equals(resolvedInfo.serviceInfo.permission)) {
+ return resolvedInfo.serviceInfo;
+ }
+ }
+ return null;
+ }
+
+ /** Creates a new {@link ResumeOnRebootServiceConnection} */
+ @Nullable
+ public ResumeOnRebootServiceConnection getServiceConnection() {
+ ServiceInfo serviceInfo = resolveService();
+ if (serviceInfo == null) {
+ return null;
+ }
+ return new ResumeOnRebootServiceConnection(mContext, serviceInfo.getComponentName());
+ }
+
+ /**
+ * Connection class used for contacting the registered {@link IResumeOnRebootService}
+ */
+ public static class ResumeOnRebootServiceConnection {
+
+ private static final String TAG = "ResumeOnRebootServiceConnection";
+ private final Context mContext;
+ private final ComponentName mComponentName;
+ private IResumeOnRebootService mBinder;
+
+ private ResumeOnRebootServiceConnection(Context context,
+ @NonNull ComponentName componentName) {
+ mContext = context;
+ mComponentName = componentName;
+ }
+
+ /** Unbind from the service */
+ public void unbindService() {
+ mContext.unbindService(new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mBinder = null;
+
+ }
+ });
+ }
+
+ /** Bind to the service */
+ public void bindToService(long timeOut) throws TimeoutException {
+ if (mBinder == null || !mBinder.asBinder().isBinderAlive()) {
+ CountDownLatch connectionLatch = new CountDownLatch(1);
+ Intent intent = new Intent();
+ intent.setComponent(mComponentName);
+ final boolean success = mContext.bindServiceAsUser(intent, new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ mBinder = IResumeOnRebootService.Stub.asInterface(service);
+ connectionLatch.countDown();
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ }
+ },
+ Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+ BackgroundThread.getHandler(), UserHandle.SYSTEM);
+
+ if (!success) {
+ Slog.e(TAG, "Binding: " + mComponentName + " u" + UserHandle.SYSTEM
+ + " failed.");
+ return;
+ }
+ waitForLatch(connectionLatch, "serviceConnection", timeOut);
+ }
+ }
+
+ /** Wrap opaque blob */
+ public byte[] wrapBlob(byte[] unwrappedBlob, long lifeTimeInMillis,
+ long timeOutInMillis)
+ throws RemoteException, TimeoutException, IOException {
+ if (mBinder == null || !mBinder.asBinder().isBinderAlive()) {
+ throw new RemoteException("Service not bound");
+ }
+ CountDownLatch binderLatch = new CountDownLatch(1);
+ ResumeOnRebootServiceCallback
+ resultCallback =
+ new ResumeOnRebootServiceCallback(
+ binderLatch);
+ mBinder.wrapSecret(unwrappedBlob, lifeTimeInMillis, new RemoteCallback(resultCallback));
+ waitForLatch(binderLatch, "wrapSecret", timeOutInMillis);
+ if (resultCallback.getResult().containsKey(ResumeOnRebootService.EXCEPTION_KEY)) {
+ throwTypedException(resultCallback.getResult().getParcelable(
+ ResumeOnRebootService.EXCEPTION_KEY));
+ }
+ return resultCallback.mResult.getByteArray(ResumeOnRebootService.WRAPPED_BLOB_KEY);
+ }
+
+ /** Unwrap wrapped blob */
+ public byte[] unwrap(byte[] wrappedBlob, long timeOut)
+ throws RemoteException, TimeoutException, IOException {
+ if (mBinder == null || !mBinder.asBinder().isBinderAlive()) {
+ throw new RemoteException("Service not bound");
+ }
+ CountDownLatch binderLatch = new CountDownLatch(1);
+ ResumeOnRebootServiceCallback
+ resultCallback =
+ new ResumeOnRebootServiceCallback(
+ binderLatch);
+ mBinder.unwrap(wrappedBlob, new RemoteCallback(resultCallback));
+ waitForLatch(binderLatch, "unWrapSecret", timeOut);
+ if (resultCallback.getResult().containsKey(ResumeOnRebootService.EXCEPTION_KEY)) {
+ throwTypedException(resultCallback.getResult().getParcelable(
+ ResumeOnRebootService.EXCEPTION_KEY));
+ }
+ return resultCallback.getResult().getByteArray(
+ ResumeOnRebootService.UNWRAPPED_BLOB_KEY);
+ }
+
+ private void throwTypedException(
+ ParcelableException exception)
+ throws IOException {
+ if (exception.getCause() instanceof IOException) {
+ exception.maybeRethrow(IOException.class);
+ } else if (exception.getCause() instanceof IllegalStateException) {
+ exception.maybeRethrow(IllegalStateException.class);
+ } else {
+ // This should not happen. Wrap the cause in IllegalStateException so that it
+ // doesn't disrupt the exception handling
+ throw new IllegalStateException(exception.getCause());
+ }
+ }
+
+ private void waitForLatch(CountDownLatch latch, String reason, long timeOut)
+ throws TimeoutException {
+ try {
+ if (!latch.await(timeOut, TimeUnit.SECONDS)) {
+ throw new TimeoutException("Latch wait for " + reason + " elapsed");
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new IllegalStateException("Latch wait for " + reason + " interrupted");
+ }
+ }
+ }
+
+ private static class ResumeOnRebootServiceCallback implements
+ RemoteCallback.OnResultListener {
+
+ private final CountDownLatch mResultLatch;
+ private Bundle mResult;
+
+ private ResumeOnRebootServiceCallback(CountDownLatch resultLatch) {
+ this.mResultLatch = resultLatch;
+ }
+
+ @Override
+ public void onResult(@Nullable Bundle result) {
+ this.mResult = result;
+ mResultLatch.countDown();
+ }
+
+ private Bundle getResult() {
+ return mResult;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
index 141fa6a..f92f3dc 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
@@ -39,11 +39,6 @@
public abstract void resetUserState(int userId);
/**
- * @return true if the given uid is restricted from doing networking on metered networks.
- */
- public abstract boolean isUidRestrictedOnMeteredNetworks(int uid);
-
- /**
* Figure out if networking is blocked for a given set of conditions.
*
* This is used by ConnectivityService via passing stale copies of conditions, so it must not
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 5ed7a96..29eaf4f 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -72,6 +72,7 @@
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
import static android.net.NetworkPolicyManager.RULE_REJECT_RESTRICTED_MODE;
import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;
+import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_UNMETERED;
import static android.net.NetworkPolicyManager.isProcStateAllowedWhileIdleOrPowerSaveMode;
import static android.net.NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground;
import static android.net.NetworkPolicyManager.resolveNetworkId;
@@ -234,6 +235,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
+import com.android.internal.os.SomeArgs;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.ConcurrentUtils;
@@ -3483,13 +3485,27 @@
@Override
public void setSubscriptionOverride(int subId, int overrideMask, int overrideValue,
- long timeoutMillis, String callingPackage) {
+ int[] networkTypes, long timeoutMillis, String callingPackage) {
enforceSubscriptionPlanAccess(subId, Binder.getCallingUid(), callingPackage);
- // We can only override when carrier told us about plans
+ final ArraySet<Integer> allNetworksSet = new ArraySet<>();
+ addAll(allNetworksSet, TelephonyManager.getAllNetworkTypes());
+ final IntArray applicableNetworks = new IntArray();
+
+ // ensure all network types are valid
+ for (int networkType : networkTypes) {
+ if (allNetworksSet.contains(networkType)) {
+ applicableNetworks.add(networkType);
+ } else {
+ Log.d(TAG, "setSubscriptionOverride removing invalid network type: " + networkType);
+ }
+ }
+
+ // We can only override when carrier told us about plans. For the unmetered case,
+ // allow override without having plans defined.
synchronized (mNetworkPoliciesSecondLock) {
final SubscriptionPlan plan = getPrimarySubscriptionPlanLocked(subId);
- if (plan == null
+ if (overrideMask != SUBSCRIPTION_OVERRIDE_UNMETERED && plan == null
|| plan.getDataLimitBehavior() == SubscriptionPlan.LIMIT_BEHAVIOR_UNKNOWN) {
throw new IllegalStateException(
"Must provide valid SubscriptionPlan to enable overriding");
@@ -3501,11 +3517,16 @@
final boolean overrideEnabled = Settings.Global.getInt(mContext.getContentResolver(),
NETPOLICY_OVERRIDE_ENABLED, 1) != 0;
if (overrideEnabled || overrideValue == 0) {
- mHandler.sendMessage(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE,
- overrideMask, overrideValue, subId));
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = subId;
+ args.arg2 = overrideMask;
+ args.arg3 = overrideValue;
+ args.arg4 = applicableNetworks.toArray();
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE, args));
if (timeoutMillis > 0) {
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE,
- overrideMask, 0, subId), timeoutMillis);
+ args.arg3 = 0;
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE, args),
+ timeoutMillis);
}
}
}
@@ -4773,10 +4794,10 @@
}
private void dispatchSubscriptionOverride(INetworkPolicyListener listener, int subId,
- int overrideMask, int overrideValue) {
+ int overrideMask, int overrideValue, int[] networkTypes) {
if (listener != null) {
try {
- listener.onSubscriptionOverride(subId, overrideMask, overrideValue);
+ listener.onSubscriptionOverride(subId, overrideMask, overrideValue, networkTypes);
} catch (RemoteException ignored) {
}
}
@@ -4908,13 +4929,16 @@
return true;
}
case MSG_SUBSCRIPTION_OVERRIDE: {
- final int overrideMask = msg.arg1;
- final int overrideValue = msg.arg2;
- final int subId = (int) msg.obj;
+ final SomeArgs args = (SomeArgs) msg.obj;
+ final int subId = (int) args.arg1;
+ final int overrideMask = (int) args.arg2;
+ final int overrideValue = (int) args.arg3;
+ final int[] networkTypes = (int[]) args.arg4;
final int length = mListeners.beginBroadcast();
for (int i = 0; i < length; i++) {
final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
- dispatchSubscriptionOverride(listener, subId, overrideMask, overrideValue);
+ dispatchSubscriptionOverride(listener, subId, overrideMask, overrideValue,
+ networkTypes);
}
mListeners.finishBroadcast();
return true;
@@ -5359,7 +5383,7 @@
public boolean isUidNetworkingBlocked(int uid, boolean isNetworkMetered) {
final long startTime = mStatLogger.getTime();
- enforceAnyPermissionOf(OBSERVE_NETWORK_POLICY, PERMISSION_MAINLINE_NETWORK_STACK);
+ mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
final int uidRules;
final boolean isBackgroundRestricted;
synchronized (mUidRulesFirstLock) {
@@ -5374,6 +5398,23 @@
return ret;
}
+ @Override
+ public boolean isUidRestrictedOnMeteredNetworks(int uid) {
+ mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
+ final int uidRules;
+ final boolean isBackgroundRestricted;
+ synchronized (mUidRulesFirstLock) {
+ uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
+ isBackgroundRestricted = mRestrictBackground;
+ }
+ //TODO(b/177490332): The logic here might not be correct because it doesn't consider
+ // RULE_REJECT_METERED condition. And it could be replaced by
+ // isUidNetworkingBlockedInternal().
+ return isBackgroundRestricted
+ && !hasRule(uidRules, RULE_ALLOW_METERED)
+ && !hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED);
+ }
+
private static boolean isSystem(int uid) {
return uid < Process.FIRST_APPLICATION_UID;
}
@@ -5442,22 +5483,6 @@
}
}
- /**
- * @return true if the given uid is restricted from doing networking on metered networks.
- */
- @Override
- public boolean isUidRestrictedOnMeteredNetworks(int uid) {
- final int uidRules;
- final boolean isBackgroundRestricted;
- synchronized (mUidRulesFirstLock) {
- uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
- isBackgroundRestricted = mRestrictBackground;
- }
- return isBackgroundRestricted
- && !hasRule(uidRules, RULE_ALLOW_METERED)
- && !hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED);
- }
-
@Override
public void onTempPowerSaveWhitelistChange(int appId, boolean added) {
synchronized (mUidRulesFirstLock) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index c397724..e604b5e 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -6432,7 +6432,6 @@
private final int mRank;
private final int mCount;
private final ManagedServiceInfo mListener;
- private final long mWhen;
CancelNotificationRunnable(final int callingUid, final int callingPid,
final String pkg, final String tag, final int id,
@@ -6452,7 +6451,6 @@
this.mRank = rank;
this.mCount = count;
this.mListener = listener;
- this.mWhen = System.currentTimeMillis();
}
@Override
@@ -6464,33 +6462,8 @@
}
synchronized (mNotificationLock) {
- // Check to see if there is a notification in the enqueued list that hasn't had a
- // chance to post yet.
- List<NotificationRecord> enqueued = findEnqueuedNotificationsForCriteria(
- mPkg, mTag, mId, mUserId);
- boolean repost = false;
- if (enqueued.size() > 0) {
- // Found something, let's see what it was
- repost = true;
- // If all enqueues happened before this cancel then wait for them to happen,
- // otherwise we should let this cancel through so the next enqueue happens
- for (NotificationRecord r : enqueued) {
- if (r.mUpdateTimeMs > mWhen) {
- // At least one enqueue was posted after the cancel, so we're invalid
- Slog.i(TAG, "notification cancel ignored due to newer enqueued entry"
- + "key=" + r.getSbn().getKey());
- return;
- }
- }
- }
- if (repost) {
- mHandler.post(this);
- return;
- }
-
- // Look for the notification in the posted list, since we already checked enqueued.
- NotificationRecord r =
- findNotificationByListLocked(mNotificationList, mPkg, mTag, mId, mUserId);
+ // Look for the notification, searching both the posted and enqueued lists.
+ NotificationRecord r = findNotificationLocked(mPkg, mTag, mId, mUserId);
if (r != null) {
// The notification was found, check if it should be removed.
@@ -6513,10 +6486,6 @@
if ((r.getNotification().flags & mMustNotHaveFlags) != 0) {
return;
}
- if (r.getUpdateTimeMs() > mWhen) {
- // In this case, a post must have slipped by when this runnable reposted
- return;
- }
// Bubbled children get to stick around if the summary was manually cancelled
// (user removed) from systemui.
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index d7a1ba2..50fb176 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -24,11 +24,15 @@
import static android.content.Intent.ACTION_USER_ADDED;
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.EXTRA_REASON;
+import static android.content.om.OverlayManagerTransaction.Request.TYPE_SET_DISABLED;
+import static android.content.om.OverlayManagerTransaction.Request.TYPE_SET_ENABLED;
import static android.content.pm.PackageManager.SIGNATURE_MATCH;
import static android.os.Trace.TRACE_TAG_RRO;
import static android.os.Trace.traceBegin;
import static android.os.Trace.traceEnd;
+import static com.android.server.om.OverlayManagerServiceImpl.OperationFailedException;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -40,6 +44,7 @@
import android.content.IntentFilter;
import android.content.om.IOverlayManager;
import android.content.om.OverlayInfo;
+import android.content.om.OverlayManagerTransaction;
import android.content.om.OverlayableInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
@@ -49,6 +54,7 @@
import android.net.Uri;
import android.os.Binder;
import android.os.Environment;
+import android.os.HandlerThread;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ResultReceiver;
@@ -65,7 +71,6 @@
import com.android.internal.content.om.OverlayConfig;
import com.android.server.FgThread;
-import com.android.server.IoThread;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
import com.android.server.SystemService;
@@ -84,12 +89,15 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Consumer;
/**
* Service to manage asset overlays.
@@ -238,7 +246,14 @@
private final OverlayActorEnforcer mActorEnforcer;
- private final AtomicBoolean mPersistSettingsScheduled = new AtomicBoolean(false);
+ private final Consumer<PackageAndUser> mPropagateOverlayChange = (pair) -> {
+ persistSettings();
+ FgThread.getHandler().post(() -> {
+ List<String> affectedTargets = updatePackageManager(pair.packageName, pair.userId);
+ updateActivityManager(affectedTargets, pair.userId);
+ broadcastActionOverlayChanged(pair.packageName, pair.userId);
+ });
+ };
public OverlayManagerService(@NonNull final Context context) {
super(context);
@@ -251,17 +266,19 @@
IdmapManager im = new IdmapManager(IdmapDaemon.getInstance(), mPackageManager);
mSettings = new OverlayManagerSettings();
mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings,
- OverlayConfig.getSystemInstance(), getDefaultOverlayPackages(),
- new OverlayChangeListener());
+ OverlayConfig.getSystemInstance(), getDefaultOverlayPackages());
mActorEnforcer = new OverlayActorEnforcer(mPackageManager);
+ HandlerThread packageReceiverThread = new HandlerThread(TAG);
+ packageReceiverThread.start();
+
final IntentFilter packageFilter = new IntentFilter();
packageFilter.addAction(ACTION_PACKAGE_ADDED);
packageFilter.addAction(ACTION_PACKAGE_CHANGED);
packageFilter.addAction(ACTION_PACKAGE_REMOVED);
packageFilter.addDataScheme("package");
getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL,
- packageFilter, null, null);
+ packageFilter, null, packageReceiverThread.getThreadHandler());
final IntentFilter userFilter = new IntentFilter();
userFilter.addAction(ACTION_USER_ADDED);
@@ -294,11 +311,11 @@
for (int i = 0; i < userCount; i++) {
final UserInfo userInfo = users.get(i);
if (!userInfo.supportsSwitchTo() && userInfo.id != UserHandle.USER_SYSTEM) {
- // Initialize any users that can't be switched to, as there state would
+ // Initialize any users that can't be switched to, as their state would
// never be setup in onSwitchUser(). We will switch to the system user right
// after this, and its state will be setup there.
final List<String> targets = mImpl.updateOverlaysForUser(users.get(i).id);
- updateOverlayPaths(users.get(i).id, targets);
+ updatePackageManager(targets, users.get(i).id);
}
}
}
@@ -316,9 +333,10 @@
// any asset changes to the rest of the system
synchronized (mLock) {
final List<String> targets = mImpl.updateOverlaysForUser(newUserId);
- updateAssets(newUserId, targets);
+ final List<String> affectedTargets = updatePackageManager(targets, newUserId);
+ updateActivityManager(affectedTargets, newUserId);
}
- schedulePersistSettings();
+ persistSettings();
} finally {
traceEnd(TRACE_TAG_RRO);
}
@@ -402,10 +420,17 @@
false);
if (pi != null && !pi.applicationInfo.isInstantApp()) {
mPackageManager.cachePackageInfo(packageName, userId, pi);
- if (pi.isOverlayPackage()) {
- mImpl.onOverlayPackageAdded(packageName, userId);
- } else {
- mImpl.onTargetPackageAdded(packageName, userId);
+
+ try {
+ if (pi.isOverlayPackage()) {
+ mImpl.onOverlayPackageAdded(packageName, userId)
+ .ifPresent(mPropagateOverlayChange);
+ } else {
+ mImpl.onTargetPackageAdded(packageName, userId)
+ .ifPresent(mPropagateOverlayChange);
+ }
+ } catch (OperationFailedException e) {
+ Slog.e(TAG, "onPackageAdded internal error", e);
}
}
}
@@ -425,10 +450,17 @@
false);
if (pi != null && pi.applicationInfo.isInstantApp()) {
mPackageManager.cachePackageInfo(packageName, userId, pi);
- if (pi.isOverlayPackage()) {
- mImpl.onOverlayPackageChanged(packageName, userId);
- } else {
- mImpl.onTargetPackageChanged(packageName, userId);
+
+ try {
+ if (pi.isOverlayPackage()) {
+ mImpl.onOverlayPackageChanged(packageName, userId)
+ .ifPresent(mPropagateOverlayChange);
+ } else {
+ mImpl.onTargetPackageChanged(packageName, userId)
+ .ifPresent(mPropagateOverlayChange);
+ }
+ } catch (OperationFailedException e) {
+ Slog.e(TAG, "onPackageChanged internal error", e);
}
}
}
@@ -447,7 +479,12 @@
mPackageManager.forgetPackageInfo(packageName, userId);
final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
if (oi != null) {
- mImpl.onOverlayPackageReplacing(packageName, userId);
+ try {
+ mImpl.onOverlayPackageReplacing(packageName, userId)
+ .ifPresent(mPropagateOverlayChange);
+ } catch (OperationFailedException e) {
+ Slog.e(TAG, "onPackageReplacing internal error", e);
+ }
}
}
}
@@ -466,10 +503,16 @@
false);
if (pi != null && !pi.applicationInfo.isInstantApp()) {
mPackageManager.cachePackageInfo(packageName, userId, pi);
- if (pi.isOverlayPackage()) {
- mImpl.onOverlayPackageReplaced(packageName, userId);
- } else {
- mImpl.onTargetPackageReplaced(packageName, userId);
+ try {
+ if (pi.isOverlayPackage()) {
+ mImpl.onOverlayPackageReplaced(packageName, userId)
+ .ifPresent(mPropagateOverlayChange);
+ } else {
+ mImpl.onTargetPackageReplaced(packageName, userId)
+ .ifPresent(mPropagateOverlayChange);
+ }
+ } catch (OperationFailedException e) {
+ Slog.e(TAG, "onPackageReplaced internal error", e);
}
}
}
@@ -487,10 +530,17 @@
synchronized (mLock) {
mPackageManager.forgetPackageInfo(packageName, userId);
final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
- if (oi != null) {
- mImpl.onOverlayPackageRemoved(packageName, userId);
- } else {
- mImpl.onTargetPackageRemoved(packageName, userId);
+
+ try {
+ if (oi != null) {
+ mImpl.onOverlayPackageRemoved(packageName, userId)
+ .ifPresent(mPropagateOverlayChange);
+ } else {
+ mImpl.onTargetPackageRemoved(packageName, userId)
+ .ifPresent(mPropagateOverlayChange);
+ }
+ } catch (OperationFailedException e) {
+ Slog.e(TAG, "onPackageRemoved internal error", e);
}
}
}
@@ -513,7 +563,7 @@
synchronized (mLock) {
targets = mImpl.updateOverlaysForUser(userId);
}
- updateOverlayPaths(userId, targets);
+ updatePackageManager(targets, userId);
} finally {
traceEnd(TRACE_TAG_RRO);
}
@@ -608,7 +658,13 @@
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- return mImpl.setEnabled(packageName, enable, realUserId);
+ try {
+ mImpl.setEnabled(packageName, enable, realUserId)
+ .ifPresent(mPropagateOverlayChange);
+ return true;
+ } catch (OperationFailedException e) {
+ return false;
+ }
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -633,8 +689,14 @@
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- return mImpl.setEnabledExclusive(packageName, false /* withinCategory */,
- realUserId);
+ try {
+ mImpl.setEnabledExclusive(packageName,
+ false /* withinCategory */, realUserId)
+ .ifPresent(mPropagateOverlayChange);
+ return true;
+ } catch (OperationFailedException e) {
+ return false;
+ }
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -660,8 +722,14 @@
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- return mImpl.setEnabledExclusive(packageName, true /* withinCategory */,
- realUserId);
+ try {
+ mImpl.setEnabledExclusive(packageName,
+ true /* withinCategory */, realUserId)
+ .ifPresent(mPropagateOverlayChange);
+ return true;
+ } catch (OperationFailedException e) {
+ return false;
+ }
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -687,7 +755,13 @@
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- return mImpl.setPriority(packageName, parentPackageName, realUserId);
+ try {
+ mImpl.setPriority(packageName, parentPackageName, realUserId)
+ .ifPresent(mPropagateOverlayChange);
+ return true;
+ } catch (OperationFailedException e) {
+ return false;
+ }
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -711,7 +785,13 @@
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- return mImpl.setHighestPriority(packageName, realUserId);
+ try {
+ mImpl.setHighestPriority(packageName, realUserId)
+ .ifPresent(mPropagateOverlayChange);
+ return true;
+ } catch (OperationFailedException e) {
+ return false;
+ }
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -735,7 +815,13 @@
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- return mImpl.setLowestPriority(packageName, realUserId);
+ try {
+ mImpl.setLowestPriority(packageName, realUserId)
+ .ifPresent(mPropagateOverlayChange);
+ return true;
+ } catch (OperationFailedException e) {
+ return false;
+ }
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -784,6 +870,129 @@
}
@Override
+ public void commit(@NonNull final OverlayManagerTransaction transaction)
+ throws RemoteException {
+ try {
+ traceBegin(TRACE_TAG_RRO, "OMS#commit " + transaction);
+ try {
+ executeAllRequests(transaction);
+ } catch (Exception e) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ restoreSettings();
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ Slog.d(TAG, "commit failed: " + e.getMessage(), e);
+ throw new SecurityException("commit failed"
+ + (DEBUG ? ": " + e.getMessage() : ""));
+ }
+ } finally {
+ traceEnd(TRACE_TAG_RRO);
+ }
+ }
+
+ private Optional<PackageAndUser> executeRequest(
+ @NonNull final OverlayManagerTransaction.Request request) throws Exception {
+ final int realUserId = handleIncomingUser(request.userId, request.typeToString());
+ enforceActor(request.packageName, request.typeToString(), realUserId);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ switch (request.type) {
+ case TYPE_SET_ENABLED:
+ Optional<PackageAndUser> opt1 =
+ mImpl.setEnabled(request.packageName, true, request.userId);
+ Optional<PackageAndUser> opt2 =
+ mImpl.setHighestPriority(request.packageName, request.userId);
+ // Both setEnabled and setHighestPriority affected the same
+ // target package and user: if both return non-empty
+ // Optionals, they are identical
+ return opt1.isPresent() ? opt1 : opt2;
+ case TYPE_SET_DISABLED:
+ return mImpl.setEnabled(request.packageName, false, request.userId);
+ default:
+ throw new IllegalArgumentException("unsupported request: " + request);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ private void executeAllRequests(@NonNull final OverlayManagerTransaction transaction)
+ throws Exception {
+ if (DEBUG) {
+ Slog.d(TAG, "commit " + transaction);
+ }
+ if (transaction == null) {
+ throw new IllegalArgumentException("null transaction");
+ }
+
+ // map: userId -> set<package-name>: target packages of overlays in
+ // this transaction
+ SparseArray<Set<String>> transactionTargets = new SparseArray<>();
+
+ // map: userId -> set<package-name>: packages that need to reload
+ // their resources due to changes to the overlays in this
+ // transaction
+ SparseArray<List<String>> affectedPackagesToUpdate = new SparseArray<>();
+
+ synchronized (mLock) {
+
+ // execute the requests (as calling user)
+ for (final OverlayManagerTransaction.Request request : transaction) {
+ executeRequest(request).ifPresent(target -> {
+ Set<String> userTargets = transactionTargets.get(target.userId);
+ if (userTargets == null) {
+ userTargets = new ArraySet<String>();
+ transactionTargets.put(target.userId, userTargets);
+ }
+ userTargets.add(target.packageName);
+ });
+ }
+
+ // past the point of no return: the entire transaction has been
+ // processed successfully, we can no longer fail: continue as
+ // system_server
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ persistSettings();
+
+ // inform the package manager about the new paths
+ for (int index = 0; index < transactionTargets.size(); index++) {
+ final int userId = transactionTargets.keyAt(index);
+ final List<String> affectedTargets =
+ updatePackageManager(transactionTargets.valueAt(index), userId);
+ affectedPackagesToUpdate.put(userId, affectedTargets);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ } // synchronized (mLock)
+
+ FgThread.getHandler().post(() -> {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ // schedule apps to refresh
+ for (int index = 0; index < affectedPackagesToUpdate.size(); index++) {
+ final int userId = affectedPackagesToUpdate.keyAt(index);
+ updateActivityManager(affectedPackagesToUpdate.valueAt(index), userId);
+ }
+
+ // broadcast the ACTION_OVERLAY_CHANGED intents
+ for (int index = 0; index < transactionTargets.size(); index++) {
+ final int userId = transactionTargets.keyAt(index);
+ for (String pkg: transactionTargets.valueAt(index)) {
+ broadcastActionOverlayChanged(pkg, userId);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ });
+ }
+
+ @Override
public void onShellCommand(@NonNull final FileDescriptor in,
@NonNull final FileDescriptor out, @NonNull final FileDescriptor err,
@NonNull final String[] args, @NonNull final ShellCallback callback,
@@ -904,162 +1113,7 @@
}
};
- private final class OverlayChangeListener
- implements OverlayManagerServiceImpl.OverlayChangeListener {
- @Override
- public void onOverlaysChanged(@NonNull final String targetPackageName, final int userId) {
- schedulePersistSettings();
- FgThread.getHandler().post(() -> {
- updateAssets(userId, targetPackageName);
-
- final Intent intent = new Intent(ACTION_OVERLAY_CHANGED,
- Uri.fromParts("package", targetPackageName, null));
- intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-
- if (DEBUG) {
- Slog.d(TAG, "send broadcast " + intent);
- }
-
- try {
- ActivityManager.getService().broadcastIntentWithFeature(null, null, intent,
- null, null, 0, null, null, null, android.app.AppOpsManager.OP_NONE,
- null, false, false, userId);
- } catch (RemoteException e) {
- // Intentionally left empty.
- }
- });
- }
- }
-
- /**
- * Updates the target packages' set of enabled overlays in PackageManager.
- */
- private ArrayList<String> updateOverlayPaths(int userId, List<String> targetPackageNames) {
- try {
- traceBegin(TRACE_TAG_RRO, "OMS#updateOverlayPaths " + targetPackageNames);
- if (DEBUG) {
- Slog.d(TAG, "Updating overlay assets");
- }
- final PackageManagerInternal pm =
- LocalServices.getService(PackageManagerInternal.class);
- final boolean updateFrameworkRes = targetPackageNames.contains("android");
- if (updateFrameworkRes) {
- targetPackageNames = pm.getTargetPackageNames(userId);
- }
-
- final Map<String, List<String>> pendingChanges =
- new ArrayMap<>(targetPackageNames.size());
- synchronized (mLock) {
- final List<String> frameworkOverlays =
- mImpl.getEnabledOverlayPackageNames("android", userId);
- final int n = targetPackageNames.size();
- for (int i = 0; i < n; i++) {
- final String targetPackageName = targetPackageNames.get(i);
- List<String> list = new ArrayList<>();
- if (!"android".equals(targetPackageName)) {
- list.addAll(frameworkOverlays);
- }
- list.addAll(mImpl.getEnabledOverlayPackageNames(targetPackageName, userId));
- pendingChanges.put(targetPackageName, list);
- }
- }
-
- final HashSet<String> updatedPackages = new HashSet<>();
- final int n = targetPackageNames.size();
- for (int i = 0; i < n; i++) {
- final String targetPackageName = targetPackageNames.get(i);
- if (DEBUG) {
- Slog.d(TAG, "-> Updating overlay: target=" + targetPackageName + " overlays=["
- + TextUtils.join(",", pendingChanges.get(targetPackageName))
- + "] userId=" + userId);
- }
-
- if (!pm.setEnabledOverlayPackages(
- userId, targetPackageName, pendingChanges.get(targetPackageName),
- updatedPackages)) {
- Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d",
- targetPackageName, userId));
- }
- }
- return new ArrayList<>(updatedPackages);
- } finally {
- traceEnd(TRACE_TAG_RRO);
- }
- }
-
- private void updateAssets(final int userId, final String targetPackageName) {
- updateAssets(userId, Collections.singletonList(targetPackageName));
- }
-
- private void updateAssets(final int userId, List<String> targetPackageNames) {
- final IActivityManager am = ActivityManager.getService();
- try {
- final ArrayList<String> updatedPaths = updateOverlayPaths(userId, targetPackageNames);
- am.scheduleApplicationInfoChanged(updatedPaths, userId);
- } catch (RemoteException e) {
- // Intentionally left empty.
- }
- }
-
- private void schedulePersistSettings() {
- if (mPersistSettingsScheduled.getAndSet(true)) {
- return;
- }
- IoThread.getHandler().post(() -> {
- mPersistSettingsScheduled.set(false);
- if (DEBUG) {
- Slog.d(TAG, "Writing overlay settings");
- }
- synchronized (mLock) {
- FileOutputStream stream = null;
- try {
- stream = mSettingsFile.startWrite();
- mSettings.persist(stream);
- mSettingsFile.finishWrite(stream);
- } catch (IOException | XmlPullParserException e) {
- mSettingsFile.failWrite(stream);
- Slog.e(TAG, "failed to persist overlay state", e);
- }
- }
- });
- }
-
- private void restoreSettings() {
- try {
- traceBegin(TRACE_TAG_RRO, "OMS#restoreSettings");
- synchronized (mLock) {
- if (!mSettingsFile.getBaseFile().exists()) {
- return;
- }
- try (FileInputStream stream = mSettingsFile.openRead()) {
- mSettings.restore(stream);
-
- // We might have data for dying users if the device was
- // restarted before we received USER_REMOVED. Remove data for
- // users that will not exist after the system is ready.
-
- final List<UserInfo> liveUsers = mUserManager.getUsers(true /*excludeDying*/);
- final int[] liveUserIds = new int[liveUsers.size()];
- for (int i = 0; i < liveUsers.size(); i++) {
- liveUserIds[i] = liveUsers.get(i).getUserHandle().getIdentifier();
- }
- Arrays.sort(liveUserIds);
-
- for (int userId : mSettings.getUsers()) {
- if (Arrays.binarySearch(liveUserIds, userId) < 0) {
- mSettings.removeUser(userId);
- }
- }
- } catch (IOException | XmlPullParserException e) {
- Slog.e(TAG, "failed to restore overlay state", e);
- }
- }
- } finally {
- traceEnd(TRACE_TAG_RRO);
- }
- }
-
- private static final class PackageManagerHelperImpl implements PackageManagerHelper {
+ private static final class PackageManagerHelperImpl implements PackageManagerHelper {
private final Context mContext;
private final IPackageManager mPackageManager;
@@ -1269,4 +1323,144 @@
}
}
}
+
+ // Helper methods to update other parts of the system or read/write
+ // settings: these methods should never call into each other!
+
+ private void broadcastActionOverlayChanged(@NonNull final String targetPackageName,
+ final int userId) {
+ final Intent intent = new Intent(ACTION_OVERLAY_CHANGED,
+ Uri.fromParts("package", targetPackageName, null));
+ intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ try {
+ ActivityManager.getService().broadcastIntent(null, intent, null, null, 0, null, null,
+ null, android.app.AppOpsManager.OP_NONE, null, false, false, userId);
+ } catch (RemoteException e) {
+ // Intentionally left empty.
+ }
+ }
+
+ /**
+ * Tell the activity manager to tell a set of packages to reload their
+ * resources.
+ */
+ private void updateActivityManager(List<String> targetPackageNames, final int userId) {
+ final IActivityManager am = ActivityManager.getService();
+ try {
+ am.scheduleApplicationInfoChanged(targetPackageNames, userId);
+ } catch (RemoteException e) {
+ // Intentionally left empty.
+ }
+ }
+
+ private ArrayList<String> updatePackageManager(String targetPackageNames, final int userId) {
+ return updatePackageManager(Collections.singletonList(targetPackageNames), userId);
+ }
+
+ /**
+ * Updates the target packages' set of enabled overlays in PackageManager.
+ * @return the package names of affected targets (a superset of
+ * targetPackageNames: the target themserlves and shared libraries)
+ */
+ private ArrayList<String> updatePackageManager(@NonNull Collection<String> targetPackageNames,
+ final int userId) {
+ try {
+ traceBegin(TRACE_TAG_RRO, "OMS#updatePackageManager " + targetPackageNames);
+ if (DEBUG) {
+ Slog.d(TAG, "Update package manager about changed overlays");
+ }
+ final PackageManagerInternal pm =
+ LocalServices.getService(PackageManagerInternal.class);
+ final boolean updateFrameworkRes = targetPackageNames.contains("android");
+ if (updateFrameworkRes) {
+ targetPackageNames = pm.getTargetPackageNames(userId);
+ }
+
+ final Map<String, List<String>> pendingChanges =
+ new ArrayMap<>(targetPackageNames.size());
+ synchronized (mLock) {
+ final List<String> frameworkOverlays =
+ mImpl.getEnabledOverlayPackageNames("android", userId);
+ for (final String targetPackageName : targetPackageNames) {
+ List<String> list = new ArrayList<>();
+ if (!"android".equals(targetPackageName)) {
+ list.addAll(frameworkOverlays);
+ }
+ list.addAll(mImpl.getEnabledOverlayPackageNames(targetPackageName, userId));
+ pendingChanges.put(targetPackageName, list);
+ }
+ }
+
+ final HashSet<String> updatedPackages = new HashSet<>();
+ for (final String targetPackageName : targetPackageNames) {
+ if (DEBUG) {
+ Slog.d(TAG, "-> Updating overlay: target=" + targetPackageName + " overlays=["
+ + TextUtils.join(",", pendingChanges.get(targetPackageName))
+ + "] userId=" + userId);
+ }
+
+ if (!pm.setEnabledOverlayPackages(
+ userId, targetPackageName, pendingChanges.get(targetPackageName),
+ updatedPackages)) {
+ Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d",
+ targetPackageName, userId));
+ }
+ }
+ return new ArrayList<>(updatedPackages);
+ } finally {
+ traceEnd(TRACE_TAG_RRO);
+ }
+ }
+
+ private void persistSettings() {
+ if (DEBUG) {
+ Slog.d(TAG, "Writing overlay settings");
+ }
+ synchronized (mLock) {
+ FileOutputStream stream = null;
+ try {
+ stream = mSettingsFile.startWrite();
+ mSettings.persist(stream);
+ mSettingsFile.finishWrite(stream);
+ } catch (IOException | XmlPullParserException e) {
+ mSettingsFile.failWrite(stream);
+ Slog.e(TAG, "failed to persist overlay state", e);
+ }
+ }
+ }
+
+ private void restoreSettings() {
+ try {
+ traceBegin(TRACE_TAG_RRO, "OMS#restoreSettings");
+ synchronized (mLock) {
+ if (!mSettingsFile.getBaseFile().exists()) {
+ return;
+ }
+ try (FileInputStream stream = mSettingsFile.openRead()) {
+ mSettings.restore(stream);
+
+ // We might have data for dying users if the device was
+ // restarted before we received USER_REMOVED. Remove data for
+ // users that will not exist after the system is ready.
+
+ final List<UserInfo> liveUsers = mUserManager.getUsers(true /*excludeDying*/);
+ final int[] liveUserIds = new int[liveUsers.size()];
+ for (int i = 0; i < liveUsers.size(); i++) {
+ liveUserIds[i] = liveUsers.get(i).getUserHandle().getIdentifier();
+ }
+ Arrays.sort(liveUserIds);
+
+ for (int userId : mSettings.getUsers()) {
+ if (Arrays.binarySearch(liveUserIds, userId) < 0) {
+ mSettings.removeUser(userId);
+ }
+ }
+ } catch (IOException | XmlPullParserException e) {
+ Slog.e(TAG, "failed to restore overlay state", e);
+ }
+ }
+ } finally {
+ traceEnd(TRACE_TAG_RRO);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 05a4a38..e60411bb 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -45,6 +45,7 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
/**
@@ -71,7 +72,6 @@
private final OverlayManagerSettings mSettings;
private final OverlayConfig mOverlayConfig;
private final String[] mDefaultOverlays;
- private final OverlayChangeListener mListener;
/**
* Helper method to merge the overlay manager's (as read from overlays.xml)
@@ -114,14 +114,12 @@
@NonNull final IdmapManager idmapManager,
@NonNull final OverlayManagerSettings settings,
@NonNull final OverlayConfig overlayConfig,
- @NonNull final String[] defaultOverlays,
- @NonNull final OverlayChangeListener listener) {
+ @NonNull final String[] defaultOverlays) {
mPackageManager = packageManager;
mIdmapManager = idmapManager;
mSettings = settings;
mOverlayConfig = overlayConfig;
mDefaultOverlays = defaultOverlays;
- mListener = listener;
}
/**
@@ -259,52 +257,58 @@
mSettings.removeUser(userId);
}
- void onTargetPackageAdded(@NonNull final String packageName, final int userId) {
+ Optional<PackageAndUser> onTargetPackageAdded(@NonNull final String packageName,
+ final int userId) throws OperationFailedException {
if (DEBUG) {
Slog.d(TAG, "onTargetPackageAdded packageName=" + packageName + " userId=" + userId);
}
- updateAndRefreshOverlaysForTarget(packageName, userId, 0);
+ return updateAndRefreshOverlaysForTarget(packageName, userId, 0);
}
- void onTargetPackageChanged(@NonNull final String packageName, final int userId) {
+ Optional<PackageAndUser> onTargetPackageChanged(@NonNull final String packageName,
+ final int userId) throws OperationFailedException {
if (DEBUG) {
Slog.d(TAG, "onTargetPackageChanged packageName=" + packageName + " userId=" + userId);
}
- updateAndRefreshOverlaysForTarget(packageName, userId, 0);
+ return updateAndRefreshOverlaysForTarget(packageName, userId, 0);
}
- void onTargetPackageReplacing(@NonNull final String packageName, final int userId) {
+ Optional<PackageAndUser> onTargetPackageReplacing(@NonNull final String packageName,
+ final int userId) throws OperationFailedException {
if (DEBUG) {
Slog.d(TAG, "onTargetPackageReplacing packageName=" + packageName + " userId="
+ userId);
}
- updateAndRefreshOverlaysForTarget(packageName, userId, 0);
+ return updateAndRefreshOverlaysForTarget(packageName, userId, 0);
}
- void onTargetPackageReplaced(@NonNull final String packageName, final int userId) {
+ Optional<PackageAndUser> onTargetPackageReplaced(@NonNull final String packageName,
+ final int userId) throws OperationFailedException {
if (DEBUG) {
Slog.d(TAG, "onTargetPackageReplaced packageName=" + packageName + " userId=" + userId);
}
- updateAndRefreshOverlaysForTarget(packageName, userId, 0);
+ return updateAndRefreshOverlaysForTarget(packageName, userId, 0);
}
- void onTargetPackageRemoved(@NonNull final String packageName, final int userId) {
+ Optional<PackageAndUser> onTargetPackageRemoved(@NonNull final String packageName,
+ final int userId) throws OperationFailedException {
if (DEBUG) {
Slog.d(TAG, "onTargetPackageRemoved packageName=" + packageName + " userId=" + userId);
}
- updateAndRefreshOverlaysForTarget(packageName, userId, 0);
+ return updateAndRefreshOverlaysForTarget(packageName, userId, 0);
}
/**
* Update the state of any overlays for this target.
*/
- private void updateAndRefreshOverlaysForTarget(@NonNull final String targetPackageName,
- final int userId, final int flags) {
+ private Optional<PackageAndUser> updateAndRefreshOverlaysForTarget(
+ @NonNull final String targetPackageName, final int userId, final int flags)
+ throws OperationFailedException {
final List<OverlayInfo> targetOverlays = mSettings.getOverlaysForTarget(targetPackageName,
userId);
@@ -364,11 +368,13 @@
}
if (modified) {
- mListener.onOverlaysChanged(targetPackageName, userId);
+ return Optional.of(new PackageAndUser(targetPackageName, userId));
}
+ return Optional.empty();
}
- void onOverlayPackageAdded(@NonNull final String packageName, final int userId) {
+ Optional<PackageAndUser> onOverlayPackageAdded(@NonNull final String packageName,
+ final int userId) throws OperationFailedException {
if (DEBUG) {
Slog.d(TAG, "onOverlayPackageAdded packageName=" + packageName + " userId=" + userId);
}
@@ -376,8 +382,7 @@
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
if (overlayPackage == null) {
Slog.w(TAG, "overlay package " + packageName + " was added, but couldn't be found");
- onOverlayPackageRemoved(packageName, userId);
- return;
+ return onOverlayPackageRemoved(packageName, userId);
}
mSettings.init(packageName, userId, overlayPackage.overlayTarget,
@@ -389,15 +394,17 @@
overlayPackage.overlayCategory);
try {
if (updateState(overlayPackage.overlayTarget, packageName, userId, 0)) {
- mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
+ return Optional.of(new PackageAndUser(overlayPackage.overlayTarget, userId));
}
+ return Optional.empty();
} catch (OverlayManagerSettings.BadKeyException e) {
- Slog.e(TAG, "failed to update settings", e);
mSettings.remove(packageName, userId);
+ throw new OperationFailedException("failed to update settings", e);
}
}
- void onOverlayPackageChanged(@NonNull final String packageName, final int userId) {
+ Optional<PackageAndUser> onOverlayPackageChanged(@NonNull final String packageName,
+ final int userId) throws OperationFailedException {
if (DEBUG) {
Slog.d(TAG, "onOverlayPackageChanged packageName=" + packageName + " userId=" + userId);
}
@@ -405,14 +412,16 @@
try {
final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId);
if (updateState(oi.targetPackageName, packageName, userId, 0)) {
- mListener.onOverlaysChanged(oi.targetPackageName, userId);
+ return Optional.of(new PackageAndUser(oi.targetPackageName, userId));
}
+ return Optional.empty();
} catch (OverlayManagerSettings.BadKeyException e) {
- Slog.e(TAG, "failed to update settings", e);
+ throw new OperationFailedException("failed to update settings", e);
}
}
- void onOverlayPackageReplacing(@NonNull final String packageName, final int userId) {
+ Optional<PackageAndUser> onOverlayPackageReplacing(@NonNull final String packageName,
+ final int userId) throws OperationFailedException {
if (DEBUG) {
Slog.d(TAG, "onOverlayPackageReplacing packageName=" + packageName + " userId="
+ userId);
@@ -423,14 +432,16 @@
if (updateState(oi.targetPackageName, packageName, userId,
FLAG_OVERLAY_IS_BEING_REPLACED)) {
removeIdmapIfPossible(oi);
- mListener.onOverlaysChanged(oi.targetPackageName, userId);
+ return Optional.of(new PackageAndUser(oi.targetPackageName, userId));
}
+ return Optional.empty();
} catch (OverlayManagerSettings.BadKeyException e) {
- Slog.e(TAG, "failed to update settings", e);
+ throw new OperationFailedException("failed to update settings", e);
}
}
- void onOverlayPackageReplaced(@NonNull final String packageName, final int userId) {
+ Optional<PackageAndUser> onOverlayPackageReplaced(@NonNull final String packageName,
+ final int userId) throws OperationFailedException {
if (DEBUG) {
Slog.d(TAG, "onOverlayPackageReplaced packageName=" + packageName + " userId="
+ userId);
@@ -439,16 +450,12 @@
final PackageInfo pkg = mPackageManager.getPackageInfo(packageName, userId);
if (pkg == null) {
Slog.w(TAG, "overlay package " + packageName + " was replaced, but couldn't be found");
- onOverlayPackageRemoved(packageName, userId);
- return;
+ return onOverlayPackageRemoved(packageName, userId);
}
try {
final OverlayInfo oldOi = mSettings.getOverlayInfo(packageName, userId);
if (mustReinitializeOverlay(pkg, oldOi)) {
- if (oldOi != null && !oldOi.targetPackageName.equals(pkg.overlayTarget)) {
- mListener.onOverlaysChanged(pkg.overlayTarget, userId);
- }
mSettings.init(packageName, userId, pkg.overlayTarget, pkg.targetOverlayableName,
pkg.applicationInfo.getBaseCodePath(),
isPackageConfiguredMutable(pkg.packageName),
@@ -457,22 +464,25 @@
}
if (updateState(pkg.overlayTarget, packageName, userId, 0)) {
- mListener.onOverlaysChanged(pkg.overlayTarget, userId);
+ return Optional.of(new PackageAndUser(pkg.overlayTarget, userId));
}
+ return Optional.empty();
} catch (OverlayManagerSettings.BadKeyException e) {
- Slog.e(TAG, "failed to update settings", e);
+ throw new OperationFailedException("failed to update settings", e);
}
}
- void onOverlayPackageRemoved(@NonNull final String packageName, final int userId) {
+ Optional<PackageAndUser> onOverlayPackageRemoved(@NonNull final String packageName,
+ final int userId) throws OperationFailedException {
try {
final OverlayInfo overlayInfo = mSettings.getOverlayInfo(packageName, userId);
if (mSettings.remove(packageName, userId)) {
removeIdmapIfPossible(overlayInfo);
- mListener.onOverlaysChanged(overlayInfo.targetPackageName, userId);
+ return Optional.of(new PackageAndUser(overlayInfo.targetPackageName, userId));
}
+ return Optional.empty();
} catch (OverlayManagerSettings.BadKeyException e) {
- Slog.e(TAG, "failed to remove overlay", e);
+ throw new OperationFailedException("failed to remove overlay", e);
}
}
@@ -493,8 +503,8 @@
return mSettings.getOverlaysForUser(userId);
}
- boolean setEnabled(@NonNull final String packageName, final boolean enable,
- final int userId) {
+ Optional<PackageAndUser> setEnabled(@NonNull final String packageName, final boolean enable,
+ final int userId) throws OperationFailedException {
if (DEBUG) {
Slog.d(TAG, String.format("setEnabled packageName=%s enable=%s userId=%d",
packageName, enable, userId));
@@ -502,30 +512,33 @@
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
if (overlayPackage == null) {
- return false;
+ throw new OperationFailedException(
+ String.format("failed to find overlay package %s for user %d",
+ packageName, userId));
}
try {
final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId);
if (!oi.isMutable) {
// Ignore immutable overlays.
- return false;
+ throw new OperationFailedException(
+ "cannot enable immutable overlay packages in runtime");
}
boolean modified = mSettings.setEnabled(packageName, userId, enable);
modified |= updateState(oi.targetPackageName, oi.packageName, userId, 0);
if (modified) {
- mListener.onOverlaysChanged(oi.targetPackageName, userId);
+ return Optional.of(new PackageAndUser(oi.targetPackageName, userId));
}
- return true;
+ return Optional.empty();
} catch (OverlayManagerSettings.BadKeyException e) {
- return false;
+ throw new OperationFailedException("failed to update settings", e);
}
}
- boolean setEnabledExclusive(@NonNull final String packageName, boolean withinCategory,
- final int userId) {
+ Optional<PackageAndUser> setEnabledExclusive(@NonNull final String packageName,
+ boolean withinCategory, final int userId) throws OperationFailedException {
if (DEBUG) {
Slog.d(TAG, String.format("setEnabledExclusive packageName=%s"
+ " withinCategory=%s userId=%d", packageName, withinCategory, userId));
@@ -533,7 +546,8 @@
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
if (overlayPackage == null) {
- return false;
+ throw new OperationFailedException(String.format(
+ "failed to find overlay package %s for user %d", packageName, userId));
}
try {
@@ -576,11 +590,11 @@
modified |= updateState(targetPackageName, packageName, userId, 0);
if (modified) {
- mListener.onOverlaysChanged(targetPackageName, userId);
+ return Optional.of(new PackageAndUser(targetPackageName, userId));
}
- return true;
+ return Optional.empty();
} catch (OverlayManagerSettings.BadKeyException e) {
- return false;
+ throw new OperationFailedException("failed to update settings", e);
}
}
@@ -596,66 +610,75 @@
return mOverlayConfig.isEnabled(packageName);
}
- boolean setPriority(@NonNull final String packageName,
- @NonNull final String newParentPackageName, final int userId) {
+ Optional<PackageAndUser> setPriority(@NonNull final String packageName,
+ @NonNull final String newParentPackageName, final int userId)
+ throws OperationFailedException {
if (DEBUG) {
Slog.d(TAG, "setPriority packageName=" + packageName + " newParentPackageName="
+ newParentPackageName + " userId=" + userId);
}
if (!isPackageConfiguredMutable(packageName)) {
- return false;
+ throw new OperationFailedException(String.format(
+ "overlay package %s user %d is not updatable", packageName, userId));
}
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
if (overlayPackage == null) {
- return false;
+ throw new OperationFailedException(String.format(
+ "failed to find overlay package %s for user %d", packageName, userId));
}
if (mSettings.setPriority(packageName, newParentPackageName, userId)) {
- mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
+ return Optional.of(new PackageAndUser(overlayPackage.overlayTarget, userId));
}
- return true;
+ return Optional.empty();
}
- boolean setHighestPriority(@NonNull final String packageName, final int userId) {
+ Optional<PackageAndUser> setHighestPriority(@NonNull final String packageName,
+ final int userId) throws OperationFailedException {
if (DEBUG) {
Slog.d(TAG, "setHighestPriority packageName=" + packageName + " userId=" + userId);
}
if (!isPackageConfiguredMutable(packageName)) {
- return false;
+ throw new OperationFailedException(String.format(
+ "overlay package %s user %d is not updatable", packageName, userId));
}
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
if (overlayPackage == null) {
- return false;
+ throw new OperationFailedException(String.format(
+ "failed to find overlay package %s for user %d", packageName, userId));
}
if (mSettings.setHighestPriority(packageName, userId)) {
- mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
+ return Optional.of(new PackageAndUser(overlayPackage.overlayTarget, userId));
}
- return true;
+ return Optional.empty();
}
- boolean setLowestPriority(@NonNull final String packageName, final int userId) {
+ Optional<PackageAndUser> setLowestPriority(@NonNull final String packageName, final int userId)
+ throws OperationFailedException {
if (DEBUG) {
Slog.d(TAG, "setLowestPriority packageName=" + packageName + " userId=" + userId);
}
if (!isPackageConfiguredMutable(packageName)) {
- return false;
+ throw new OperationFailedException(String.format(
+ "overlay package %s user %d is not updatable", packageName, userId));
}
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
if (overlayPackage == null) {
- return false;
+ throw new OperationFailedException(String.format(
+ "failed to find overlay package %s for user %d", packageName, userId));
}
if (mSettings.setLowestPriority(packageName, userId)) {
- mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
+ return Optional.of(new PackageAndUser(overlayPackage.overlayTarget, userId));
}
- return true;
+ return Optional.empty();
}
void dump(@NonNull final PrintWriter pw, @NonNull DumpState dumpState) {
@@ -797,12 +820,13 @@
mIdmapManager.removeIdmap(oi, oi.userId);
}
- interface OverlayChangeListener {
+ static final class OperationFailedException extends Exception {
+ OperationFailedException(@NonNull final String message) {
+ super(message);
+ }
- /**
- * An event triggered by changes made to overlay state or settings as well as changes that
- * add or remove target packages of overlays.
- **/
- void onOverlaysChanged(@NonNull String targetPackage, int userId);
+ OperationFailedException(@NonNull final String message, @NonNull Throwable cause) {
+ super(message, cause);
+ }
}
}
diff --git a/services/core/java/com/android/server/om/PackageAndUser.java b/services/core/java/com/android/server/om/PackageAndUser.java
new file mode 100644
index 0000000..5c38ba7
--- /dev/null
+++ b/services/core/java/com/android/server/om/PackageAndUser.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.om;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+
+final class PackageAndUser {
+ public final @NonNull String packageName;
+ public final @UserIdInt int userId;
+
+ PackageAndUser(@NonNull String packageName, @UserIdInt int userId) {
+ this.packageName = packageName;
+ this.userId = userId;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof PackageAndUser)) {
+ return false;
+ }
+ PackageAndUser other = (PackageAndUser) obj;
+ return packageName.equals(other.packageName) && userId == other.userId;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + packageName.hashCode();
+ result = prime * result + userId;
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("PackageAndUser{packageName=%s, userId=%d}", packageName, userId);
+ }
+}
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index ef0f0ee..4ff75fa 100644
--- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -336,6 +336,13 @@
@Override
public void binderDied() {
+ try {
+ // Allow a small amount of time for any error or finished callbacks to be made.
+ // This ensures that the listener does not receive an erroneous runtime error
+ // callback.
+ Thread.sleep(1000);
+ } catch (InterruptedException ignored) {
+ }
synchronized (mLock) {
if (!mDone) {
// If we have not gotten a "done" callback this must be a crash.
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 7952c25..bdff19b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -15071,8 +15071,12 @@
}
final IActivityManager am = ActivityManager.getService();
try {
- final long duration = LocalServices.getService(ActivityManagerInternal.class)
- .getBootTimeTempAllowListDuration();
+ long duration = 10_000;
+ final ActivityManagerInternal amInternal =
+ LocalServices.getService(ActivityManagerInternal.class);
+ if (amInternal != null) {
+ duration = amInternal.getBootTimeTempAllowListDuration();
+ }
final BroadcastOptions bOptions = BroadcastOptions.makeBasic();
bOptions.setTemporaryAppWhitelistDuration(
BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
@@ -21419,7 +21423,7 @@
mPermissionManager.onPackageInstalled(pkg,
PermissionManagerServiceInternal.PackageInstalledParams.DEFAULT, userId);
if (applyUserRestrictions) {
- mSettings.writeRuntimePermissionsForUserLPr(userId, false);
+ mSettings.writePermissionStateForUserLPr(userId, false);
}
}
@@ -27425,7 +27429,7 @@
public void writePermissionSettings(int[] userIds, boolean async) {
synchronized (mLock) {
for (int userId : userIds) {
- mSettings.writeRuntimePermissionsForUserLPr(userId, !async);
+ mSettings.writePermissionStateForUserLPr(userId, !async);
}
}
}
@@ -28065,13 +28069,12 @@
/**
* Temporary method that wraps mSettings.writeLPr() and calls mPermissionManager's
- * writeLegacyPermissionsTEMP() and writeLegacyPermissionStateTEMP() beforehand.
+ * writeLegacyPermissionsTEMP() beforehand.
*
* TODO(zhanghai): This should be removed once we finish migration of permission storage.
*/
private void writeSettingsLPrTEMP() {
mPermissionManager.writeLegacyPermissionsTEMP(mSettings.mPermissions);
- mPermissionManager.writeLegacyPermissionStateTEMP();
mSettings.writeLPr();
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 9eae117..446342a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -2732,7 +2732,7 @@
private int removeUserOrSetEphemeral(IUserManager um, @UserIdInt int userId)
throws RemoteException {
Slog.i(TAG, "Removing " + userId + " or set as ephemeral if in use.");
- int result = um.removeUserOrSetEphemeral(userId);
+ int result = um.removeUserOrSetEphemeral(userId, /* evenWhenDisallowed= */ false);
switch (result) {
case UserManager.REMOVE_RESULT_REMOVED:
getOutPrintWriter().printf("Success: user %d removed\n", userId);
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 83f6c52..ade087b 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -356,7 +356,7 @@
proto.write(PackageProto.UserPermissionsProto.ID, user.id);
runtimePermissionStates = dataProvider.getLegacyPermissionState(appId)
- .getRuntimePermissionStates(user.id);
+ .getPermissionStates(user.id);
for (LegacyPermissionState.PermissionState permission : runtimePermissionStates) {
if (permission.isGranted()) {
proto.write(PackageProto.UserPermissionsProto.GRANTED_PERMISSIONS,
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 50c1065..3416147 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2313,7 +2313,8 @@
}
void readInstallPermissionsLPr(TypedXmlPullParser parser,
- LegacyPermissionState permissionsState) throws IOException, XmlPullParserException {
+ LegacyPermissionState permissionsState, List<UserInfo> users)
+ throws IOException, XmlPullParserException {
int outerDepth = parser.getDepth();
int type;
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
@@ -2328,8 +2329,10 @@
String name = parser.getAttributeValue(null, ATTR_NAME);
final boolean granted = parser.getAttributeBoolean(null, ATTR_GRANTED, true);
final int flags = parser.getAttributeIntHex(null, ATTR_FLAGS, 0);
- permissionsState.putInstallPermissionState(new PermissionState(name, granted,
- flags));
+ for (final UserInfo user : users) {
+ permissionsState.putPermissionState(new PermissionState(name, false, granted,
+ flags), user.id);
+ }
} else {
Slog.w(PackageManagerService.TAG, "Unknown element under <permissions>: "
+ parser.getName());
@@ -2338,25 +2341,6 @@
}
}
- void writePermissionsLPr(TypedXmlSerializer serializer, Collection<PermissionState> permissionStates)
- throws IOException {
- if (permissionStates.isEmpty()) {
- return;
- }
-
- serializer.startTag(null, TAG_PERMISSIONS);
-
- for (PermissionState permissionState : permissionStates) {
- serializer.startTag(null, TAG_ITEM);
- serializer.attributeInterned(null, ATTR_NAME, permissionState.getName());
- serializer.attributeBoolean(null, ATTR_GRANTED, permissionState.isGranted());
- serializer.attributeIntHex(null, ATTR_FLAGS, permissionState.getFlags());
- serializer.endTag(null, TAG_ITEM);
- }
-
- serializer.endTag(null, TAG_PERMISSIONS);
- }
-
void readUsesStaticLibLPw(TypedXmlPullParser parser, PackageSetting outPs)
throws IOException, XmlPullParserException {
String libName = parser.getAttributeValue(null, ATTR_NAME);
@@ -2572,8 +2556,6 @@
serializer.attribute(null, ATTR_NAME, usr.name);
serializer.attributeInt(null, "userId", usr.userId);
usr.signatures.writeXml(serializer, "sigs", mPastSignatures);
- writePermissionsLPr(serializer, usr.getLegacyPermissionState()
- .getInstallPermissionStates());
serializer.endTag(null, "shared-user");
}
@@ -2898,12 +2880,6 @@
writeUsesStaticLibLPw(serializer, pkg.usesStaticLibraries, pkg.usesStaticLibrariesVersions);
- // If this is a shared user, the permissions will be written there.
- if (pkg.sharedUser == null) {
- writePermissionsLPr(serializer, pkg.getLegacyPermissionState()
- .getInstallPermissionStates());
- }
-
serializer.endTag(null, "updated-package");
}
@@ -2991,9 +2967,6 @@
serializer, "install-initiator-sigs", mPastSignatures);
}
- writePermissionsLPr(serializer,
- pkg.getLegacyPermissionState().getInstallPermissionStates());
-
writeSigningKeySetLPr(serializer, pkg.keySetData);
writeUpgradeKeySetsLPr(serializer, pkg.keySetData);
writeKeySetAliasesLPr(serializer, pkg.keySetData);
@@ -3097,13 +3070,13 @@
String tagName = parser.getName();
if (tagName.equals("package")) {
- readPackageLPw(parser);
+ readPackageLPw(parser, users);
} else if (tagName.equals("permissions")) {
mPermissions.readPermissions(parser);
} else if (tagName.equals("permission-trees")) {
mPermissions.readPermissionTrees(parser);
} else if (tagName.equals("shared-user")) {
- readSharedUserLPw(parser);
+ readSharedUserLPw(parser, users);
} else if (tagName.equals("preferred-packages")) {
// no longer used.
} else if (tagName.equals("preferred-activities")) {
@@ -3121,7 +3094,7 @@
} else if (tagName.equals(TAG_DEFAULT_BROWSER)) {
readDefaultAppsLPw(parser, 0);
} else if (tagName.equals("updated-package")) {
- readDisabledSysPackageLPw(parser);
+ readDisabledSysPackageLPw(parser, users);
} else if (tagName.equals("renamed-package")) {
String nname = parser.getAttributeValue(null, "new");
String oname = parser.getAttributeValue(null, "old");
@@ -3627,7 +3600,7 @@
}
}
- private void readDisabledSysPackageLPw(TypedXmlPullParser parser)
+ private void readDisabledSysPackageLPw(TypedXmlPullParser parser, List<UserInfo> users)
throws XmlPullParserException, IOException {
String name = parser.getAttributeValue(null, ATTR_NAME);
String realName = parser.getAttributeValue(null, "realName");
@@ -3676,7 +3649,7 @@
}
if (parser.getName().equals(TAG_PERMISSIONS)) {
- readInstallPermissionsLPr(parser, ps.getLegacyPermissionState());
+ readInstallPermissionsLPr(parser, ps.getLegacyPermissionState(), users);
} else if (parser.getName().equals(TAG_USES_STATIC_LIB)) {
readUsesStaticLibLPw(parser, ps);
} else {
@@ -3693,7 +3666,7 @@
private static int PRE_M_APP_INFO_FLAG_CANT_SAVE_STATE = 1<<28;
private static int PRE_M_APP_INFO_FLAG_PRIVILEGED = 1<<30;
- private void readPackageLPw(TypedXmlPullParser parser)
+ private void readPackageLPw(TypedXmlPullParser parser, List<UserInfo> users)
throws XmlPullParserException, IOException {
String name = null;
String realName = null;
@@ -3935,7 +3908,7 @@
packageSetting.signatures.readXml(parser, mPastSignatures);
} else if (tagName.equals(TAG_PERMISSIONS)) {
readInstallPermissionsLPr(parser,
- packageSetting.getLegacyPermissionState());
+ packageSetting.getLegacyPermissionState(), users);
packageSetting.installPermissionsFixed = true;
} else if (tagName.equals("proper-signing-keyset")) {
long id = parser.getAttributeLong(null, "identifier");
@@ -4112,7 +4085,7 @@
}
}
- private void readSharedUserLPw(TypedXmlPullParser parser)
+ private void readSharedUserLPw(TypedXmlPullParser parser, List<UserInfo> users)
throws XmlPullParserException, IOException {
String name = null;
int pkgFlags = 0;
@@ -4156,7 +4129,7 @@
if (tagName.equals("sigs")) {
su.signatures.readXml(parser, mPastSignatures);
} else if (tagName.equals("perms")) {
- readInstallPermissionsLPr(parser, su.getLegacyPermissionState());
+ readInstallPermissionsLPr(parser, su.getLegacyPermissionState(), users);
} else {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Unknown element under <shared-user>: " + parser.getName());
@@ -4979,7 +4952,7 @@
dumpGidsLPr(pw, prefix + " ", mPermissionDataProvider.getGidsForUid(
UserHandle.getUid(user.id, ps.appId)));
dumpRuntimePermissionsLPr(pw, prefix + " ", permissionNames, permissionsState
- .getRuntimePermissionStates(user.id), dumpAll);
+ .getPermissionStates(user.id), dumpAll);
}
String harmfulAppWarning = ps.getHarmfulAppWarning(user.id);
@@ -5154,7 +5127,7 @@
final int[] gids = mPermissionDataProvider.getGidsForUid(UserHandle.getUid(
userId, su.userId));
final Collection<PermissionState> permissions =
- permissionsState.getRuntimePermissionStates(userId);
+ permissionsState.getPermissionStates(userId);
if (!ArrayUtils.isEmpty(gids) || !permissions.isEmpty()) {
pw.print(prefix); pw.print("User "); pw.print(userId); pw.println(": ");
dumpGidsLPr(pw, prefix + " ", gids);
@@ -5215,9 +5188,19 @@
void dumpRuntimePermissionsLPr(PrintWriter pw, String prefix, ArraySet<String> permissionNames,
Collection<PermissionState> permissionStates, boolean dumpAll) {
- if (!permissionStates.isEmpty() || dumpAll) {
+ boolean hasRuntimePermissions = false;
+ for (PermissionState permissionState : permissionStates) {
+ if (permissionState.isRuntime()) {
+ hasRuntimePermissions = true;
+ break;
+ }
+ }
+ if (hasRuntimePermissions || dumpAll) {
pw.print(prefix); pw.println("runtime permissions:");
for (PermissionState permissionState : permissionStates) {
+ if (!permissionState.isRuntime()) {
+ continue;
+ }
if (permissionNames != null
&& !permissionNames.contains(permissionState.getName())) {
continue;
@@ -5256,11 +5239,21 @@
void dumpInstallPermissionsLPr(PrintWriter pw, String prefix, ArraySet<String> permissionNames,
LegacyPermissionState permissionsState) {
- Collection<PermissionState> permissionStates =
- permissionsState.getInstallPermissionStates();
- if (!permissionStates.isEmpty()) {
+ Collection<PermissionState> permissionStates = permissionsState.getPermissionStates(
+ UserHandle.USER_SYSTEM);
+ boolean hasInstallPermissions = false;
+ for (PermissionState permissionState : permissionStates) {
+ if (!permissionState.isRuntime()) {
+ hasInstallPermissions = true;
+ break;
+ }
+ }
+ if (hasInstallPermissions) {
pw.print(prefix); pw.println("install permissions:");
for (PermissionState permissionState : permissionStates) {
+ if (permissionState.isRuntime()) {
+ continue;
+ }
if (permissionNames != null
&& !permissionNames.contains(permissionState.getName())) {
continue;
@@ -5295,7 +5288,7 @@
}
}
- public void writeRuntimePermissionsForUserLPr(int userId, boolean sync) {
+ public void writePermissionStateForUserLPr(int userId, boolean sync) {
if (sync) {
mRuntimePermissionsPersistence.writeStateForUserSyncLPr(userId);
} else {
@@ -5530,7 +5523,7 @@
private List<RuntimePermissionsState.PermissionState> getPermissionsFromPermissionsState(
@NonNull LegacyPermissionState permissionsState, @UserIdInt int userId) {
Collection<PermissionState> permissionStates =
- permissionsState.getRuntimePermissionStates(userId);
+ permissionsState.getPermissionStates(userId);
List<RuntimePermissionsState.PermissionState> permissions = new ArrayList<>();
for (PermissionState permissionState : permissionStates) {
RuntimePermissionsState.PermissionState permission =
@@ -5590,6 +5583,7 @@
if (permissions != null) {
readPermissionsStateLpr(permissions, packageSetting.getLegacyPermissionState(),
userId);
+ packageSetting.installPermissionsFixed = true;
} else if (packageSetting.sharedUser == null && !isUpgradeToR) {
Slog.w(TAG, "Missing permission state for package: " + packageName);
packageSetting.getLegacyPermissionState().setMissing(true, userId);
@@ -5624,7 +5618,7 @@
String name = permission.getName();
boolean granted = permission.isGranted();
int flags = permission.getFlags();
- permissionsState.putRuntimePermissionState(new PermissionState(name, granted,
+ permissionsState.putPermissionState(new PermissionState(name, true, granted,
flags), userId);
}
}
@@ -5646,7 +5640,7 @@
try {
final TypedXmlPullParser parser = Xml.resolvePullParser(in);
- parseRuntimePermissionsLPr(parser, userId);
+ parseLegacyRuntimePermissionsLPr(parser, userId);
} catch (XmlPullParserException | IOException e) {
throw new IllegalStateException("Failed parsing permissions file: "
@@ -5659,7 +5653,7 @@
// Private internals
@GuardedBy("Settings.this.mLock")
- private void parseRuntimePermissionsLPr(TypedXmlPullParser parser, int userId)
+ private void parseLegacyRuntimePermissionsLPr(TypedXmlPullParser parser, int userId)
throws IOException, XmlPullParserException {
final int outerDepth = parser.getDepth();
int type;
@@ -5687,7 +5681,7 @@
XmlUtils.skipCurrentTag(parser);
continue;
}
- parsePermissionsLPr(parser, ps.getLegacyPermissionState(), userId);
+ parseLegacyPermissionsLPr(parser, ps.getLegacyPermissionState(), userId);
} break;
case TAG_SHARED_USER: {
@@ -5698,13 +5692,13 @@
XmlUtils.skipCurrentTag(parser);
continue;
}
- parsePermissionsLPr(parser, sus.getLegacyPermissionState(), userId);
+ parseLegacyPermissionsLPr(parser, sus.getLegacyPermissionState(), userId);
} break;
}
}
}
- private void parsePermissionsLPr(TypedXmlPullParser parser,
+ private void parseLegacyPermissionsLPr(TypedXmlPullParser parser,
LegacyPermissionState permissionsState, int userId)
throws IOException, XmlPullParserException {
final int outerDepth = parser.getDepth();
@@ -5722,7 +5716,7 @@
parser.getAttributeBoolean(null, ATTR_GRANTED, true);
final int flags =
parser.getAttributeIntHex(null, ATTR_FLAGS, 0);
- permissionsState.putRuntimePermissionState(new PermissionState(name,
+ permissionsState.putPermissionState(new PermissionState(name, true,
granted, flags), userId);
}
break;
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 19a94b3..314510b 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -3843,7 +3843,6 @@
*/
@Override
public boolean removeUser(@UserIdInt int userId) {
- Slog.i(LOG_TAG, "removeUser u" + userId, new Exception());
checkManageOrCreateUsersPermission("Only the system can remove users");
final String restriction = getUserRemovalRestriction(userId);
@@ -3968,13 +3967,16 @@
}
@Override
- public @UserManager.RemoveResult int removeUserOrSetEphemeral(@UserIdInt int userId) {
- Slog.i(LOG_TAG, "removeUserOrSetEphemeral u" + userId);
+ public @UserManager.RemoveResult int removeUserOrSetEphemeral(@UserIdInt int userId,
+ boolean evenWhenDisallowed) {
checkManageOrCreateUsersPermission("Only the system can remove users");
- final String restriction = getUserRemovalRestriction(userId);
- if (getUserRestrictions(UserHandle.getCallingUserId()).getBoolean(restriction, false)) {
- Slog.w(LOG_TAG, "Cannot remove user. " + restriction + " is enabled.");
- return UserManager.REMOVE_RESULT_ERROR;
+
+ if (!evenWhenDisallowed) {
+ final String restriction = getUserRemovalRestriction(userId);
+ if (getUserRestrictions(UserHandle.getCallingUserId()).getBoolean(restriction, false)) {
+ Slog.w(LOG_TAG, "Cannot remove user. " + restriction + " is enabled.");
+ return UserManager.REMOVE_RESULT_ERROR;
+ }
}
if (userId == UserHandle.USER_SYSTEM) {
Slog.e(LOG_TAG, "System user cannot be removed.");
@@ -4003,7 +4005,7 @@
final int currentUser = ActivityManager.getCurrentUser();
if (currentUser != userId) {
// Attempt to remove the user. This will fail if the user is the current user
- if (removeUser(userId)) {
+ if (removeUserUnchecked(userId)) {
return UserManager.REMOVE_RESULT_REMOVED;
}
}
diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
index 252ba60..6e6d7c3 100644
--- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
+++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
@@ -327,17 +327,17 @@
final PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class);
// Check whether all allowlisted packages are indeed on the system.
- final String notPresentFmt = "%s is whitelisted but not present.";
- final String notSystemFmt = "%s is whitelisted and present but not a system package.";
- final String overlayPackageFmt = "%s is whitelisted but it's auto-generated RRO package.";
+ final String notPresentFmt = "%s is allowlisted but not present.";
+ final String notSystemFmt = "%s is allowlisted and present but not a system package.";
+ final String overlayFmt = "%s is allowlisted unnecessarily since it's a static overlay.";
for (String pkgName : allWhitelistedPackages) {
final AndroidPackage pkg = pmInt.getPackage(pkgName);
if (pkg == null) {
warnings.add(String.format(notPresentFmt, pkgName));
} else if (!pkg.isSystem()) {
warnings.add(String.format(notSystemFmt, pkgName));
- } else if (isAutoGeneratedRRO(pkg)) {
- warnings.add(String.format(overlayPackageFmt, pkgName));
+ } else if (shouldUseOverlayTargetName(pkg)) {
+ warnings.add(String.format(overlayFmt, pkgName));
}
}
return warnings;
@@ -363,7 +363,7 @@
if (!pkg.isSystem()) return;
final String pkgName = pkg.getManifestPackageName();
if (!allWhitelistedPackages.contains(pkgName)
- && !isAutoGeneratedRRO(pmInt.getPackage(pkgName))) {
+ && !shouldUseOverlayTargetName(pmInt.getPackage(pkgName))) {
errors.add(String.format(logMessageFmt, pkgName));
}
});
@@ -413,22 +413,13 @@
}
/**
- * Whether package name has auto-generated RRO package name suffix.
+ * Returns whether the package is a static overlay, whose installation should depend on the
+ * allowlisting of the overlay's target's package name, rather than of its own package name.
+ *
+ * @param pkg A package (which need not be an overlay)
*/
- @VisibleForTesting
- static boolean hasAutoGeneratedRROSuffix(String name) {
- return name.endsWith(".auto_generated_rro_product__")
- // TODO(b/172956245): temporary workaround until OEMs can customize name
- || name.endsWith("carui.rro") || name.endsWith("carui.overlayable.rro")
- || name.endsWith(".auto_generated_rro_vendor__");
- }
-
- /**
- * Whether the package is auto-generated RRO package.
- */
- private static boolean isAutoGeneratedRRO(AndroidPackage pkg) {
- return pkg.isOverlay()
- && (hasAutoGeneratedRROSuffix(pkg.getManifestPackageName()));
+ private static boolean shouldUseOverlayTargetName(AndroidPackage pkg) {
+ return pkg.isOverlayIsStatic();
}
/** See {@link #isEnforceMode()}. */
@@ -542,18 +533,8 @@
static boolean shouldInstallPackage(AndroidPackage sysPkg,
@NonNull ArrayMap<String, Long> userTypeWhitelist,
@NonNull Set<String> userWhitelist, boolean implicitlyWhitelist) {
- final String pkgName;
- if (isAutoGeneratedRRO(sysPkg)) {
- pkgName = sysPkg.getOverlayTarget();
- if (DEBUG) {
- Slog.i(TAG, "shouldInstallPackage(): " + sysPkg.getManifestPackageName()
- + " is auto-generated RRO package, will look for overlay system package: "
- + pkgName);
- }
- } else {
- pkgName = sysPkg.getManifestPackageName();
- }
-
+ final String pkgName = shouldUseOverlayTargetName(sysPkg) ?
+ sysPkg.getOverlayTarget() : sysPkg.getManifestPackageName();
return (implicitlyWhitelist && !userTypeWhitelist.containsKey(pkgName))
|| userWhitelist.contains(pkgName);
}
diff --git a/services/core/java/com/android/server/pm/permission/LegacyPermissionState.java b/services/core/java/com/android/server/pm/permission/LegacyPermissionState.java
index 72d7628..92f22a4 100644
--- a/services/core/java/com/android/server/pm/permission/LegacyPermissionState.java
+++ b/services/core/java/com/android/server/pm/permission/LegacyPermissionState.java
@@ -19,7 +19,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
-import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -105,28 +104,14 @@
}
/**
- * Put a install permission state.
- *
- * @param permissionState the permission state
- */
- public void putInstallPermissionState(@NonNull PermissionState permissionState) {
- putPermissionState(permissionState, UserHandle.USER_ALL);
- }
-
- /**
- * Put a runtime permission state for a user.
+ * Put a permission state for a user.
*
* @param permissionState the permission state
* @param userId the user ID
*/
- public void putRuntimePermissionState(@NonNull PermissionState permissionState,
+ public void putPermissionState(@NonNull PermissionState permissionState,
@UserIdInt int userId) {
checkUserId(userId);
- putPermissionState(permissionState, userId);
- }
-
- private void putPermissionState(@NonNull PermissionState permissionState,
- @UserIdInt int userId) {
UserState userState = mUserStates.get(userId);
if (userState == null) {
userState = new UserState();
@@ -157,29 +142,14 @@
}
/**
- * Get all the install permission states.
- *
- * @return the install permission states
- */
- @NonNull
- public Collection<PermissionState> getInstallPermissionStates() {
- return getPermissionStates(UserHandle.USER_ALL);
- }
-
- /**
* Get all the runtime permission states for a user.
*
* @param userId the user ID
* @return the runtime permission states
*/
@NonNull
- public Collection<PermissionState> getRuntimePermissionStates(@UserIdInt int userId) {
+ public Collection<PermissionState> getPermissionStates(@UserIdInt int userId) {
checkUserId(userId);
- return getPermissionStates(userId);
- }
-
- @NonNull
- private Collection<PermissionState> getPermissionStates(@UserIdInt int userId) {
final UserState userState = mUserStates.get(userId);
if (userState == null) {
return Collections.emptyList();
@@ -265,6 +235,8 @@
@NonNull
private final String mName;
+ private final boolean mRuntime;
+
private final boolean mGranted;
private final int mFlags;
@@ -273,17 +245,20 @@
* Create a new instance of this class.
*
* @param name the name of the permission
+ * @param runtime whether the permission is runtime
* @param granted whether the permission is granted
* @param flags the permission flags
*/
- public PermissionState(@NonNull String name, boolean granted, int flags) {
+ public PermissionState(@NonNull String name, boolean runtime, boolean granted, int flags) {
mName = name;
+ mRuntime = runtime;
mGranted = granted;
mFlags = flags;
}
private PermissionState(@NonNull PermissionState other) {
mName = other.mName;
+ mRuntime = other.mRuntime;
mGranted = other.mGranted;
mFlags = other.mFlags;
}
@@ -299,6 +274,15 @@
}
/**
+ * Get whether the permission is a runtime permission.
+ *
+ * @return whether the permission is a runtime permission.
+ */
+ public boolean isRuntime() {
+ return mRuntime;
+ }
+
+ /**
* Get whether the permission is granted.
*
* @return whether the permission is granted
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 8f42289..2a646b5 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -3965,8 +3965,7 @@
if (!usedPermissions.contains(permissionState.getName())) {
Permission bp = mRegistry.getPermission(permissionState.getName());
if (bp != null) {
- if (uidState.removePermissionState(bp.getName())
- && permissionState.isRuntime()) {
+ if (uidState.removePermissionState(bp.getName()) && bp.isRuntime()) {
runtimePermissionChanged = true;
}
}
@@ -4573,9 +4572,7 @@
uidState.reset();
uidState.setMissing(legacyState.isMissing(userId));
readLegacyPermissionStatesLocked(uidState,
- legacyState.getInstallPermissionStates());
- readLegacyPermissionStatesLocked(uidState,
- legacyState.getRuntimePermissionStates(userId));
+ legacyState.getPermissionStates(userId));
}
}
});
@@ -4634,12 +4631,9 @@
final LegacyPermissionState.PermissionState legacyPermissionState =
new LegacyPermissionState.PermissionState(permissionState.getName(),
+ permissionState.getPermission().isRuntime(),
permissionState.isGranted(), permissionState.getFlags());
- if (permissionState.isRuntime()) {
- legacyState.putRuntimePermissionState(legacyPermissionState, userId);
- } else {
- legacyState.putInstallPermissionState(legacyPermissionState);
- }
+ legacyState.putPermissionState(legacyPermissionState, userId);
}
}
}
@@ -4904,12 +4898,9 @@
final LegacyPermissionState.PermissionState legacyPermissionState =
new LegacyPermissionState.PermissionState(permissionState.getName(),
+ permissionState.getPermission().isRuntime(),
permissionState.isGranted(), permissionState.getFlags());
- if (permissionState.isRuntime()) {
- legacyState.putRuntimePermissionState(legacyPermissionState, userId);
- } else if (userId == UserHandle.USER_SYSTEM) {
- legacyState.putInstallPermissionState(legacyPermissionState);
- }
+ legacyState.putPermissionState(legacyPermissionState, userId);
}
}
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionState.java b/services/core/java/com/android/server/pm/permission/PermissionState.java
index 12f29d0..9ad8a05 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionState.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionState.java
@@ -32,9 +32,6 @@
private final Object mLock = new Object();
@GuardedBy("mLock")
- private boolean mRuntime;
-
- @GuardedBy("mLock")
private boolean mGranted;
@GuardedBy("mLock")
@@ -66,12 +63,6 @@
return mPermission.computeGids(userId);
}
- public boolean isRuntime() {
- synchronized (mLock) {
- return mPermission.isRuntime();
- }
- }
-
public boolean isGranted() {
synchronized (mLock) {
return mGranted;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 607c165..69484b1 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -447,8 +447,25 @@
volatile int mPowerKeyPressCounter;
volatile boolean mEndCallKeyHandled;
volatile boolean mCameraGestureTriggeredDuringGoingToSleep;
- volatile boolean mGoingToSleep;
- volatile boolean mRequestedOrGoingToSleep;
+
+ /**
+ * {@code true} if the device is entering a low-power state; {@code false otherwise}.
+ *
+ * <p>This differs from {@link #mRequestedOrSleepingDefaultDisplay} which tracks the power state
+ * of the {@link #mDefaultDisplay default display} versus the power state of the entire device.
+ */
+ volatile boolean mDeviceGoingToSleep;
+
+ /**
+ * {@code true} if the {@link #mDefaultDisplay default display} is entering or was requested to
+ * enter a low-power state; {@code false otherwise}.
+ *
+ * <p>This differs from {@link #mDeviceGoingToSleep} which tracks the power state of the entire
+ * device versus the power state of the {@link #mDefaultDisplay default display}.
+ */
+ // TODO(b/178103325): Track sleep/requested sleep for every display.
+ volatile boolean mRequestedOrSleepingDefaultDisplay;
+
volatile boolean mRecentsVisible;
volatile boolean mNavBarVirtualKeyHapticFeedbackEnabled = true;
volatile boolean mPictureInPictureVisible;
@@ -916,7 +933,7 @@
if (gestureService != null) {
gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event, interactive,
mTmpBoolean);
- if (mTmpBoolean.value && mRequestedOrGoingToSleep) {
+ if (mTmpBoolean.value && mRequestedOrSleepingDefaultDisplay) {
mCameraGestureTriggeredDuringGoingToSleep = true;
}
}
@@ -1063,13 +1080,14 @@
case SHORT_PRESS_POWER_NOTHING:
break;
case SHORT_PRESS_POWER_GO_TO_SLEEP:
- goToSleepFromPowerButton(eventTime, 0);
+ sleepDefaultDisplayFromPowerButton(eventTime, 0);
break;
case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP:
- goToSleepFromPowerButton(eventTime, PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
+ sleepDefaultDisplayFromPowerButton(eventTime,
+ PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
break;
case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME:
- if (goToSleepFromPowerButton(eventTime,
+ if (sleepDefaultDisplayFromPowerButton(eventTime,
PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE)) {
launchHomeFromHotKey(DEFAULT_DISPLAY);
}
@@ -1097,11 +1115,11 @@
}
/**
- * Sends the device to sleep as a result of a power button press.
+ * Sends the default display to sleep as a result of a power button press.
*
- * @return True if the was device was sent to sleep, false if sleep was suppressed.
+ * @return True if the device was sent to sleep, false if the device did not sleep.
*/
- private boolean goToSleepFromPowerButton(long eventTime, int flags) {
+ private boolean sleepDefaultDisplayFromPowerButton(long eventTime, int flags) {
// Before we actually go to sleep, we check the last wakeup reason.
// If the device very recently woke up from a gesture (like user lifting their device)
// then ignore the sleep instruction. This is because users have developed
@@ -1121,12 +1139,12 @@
}
}
- goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, flags);
+ sleepDefaultDisplay(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, flags);
return true;
}
- private void goToSleep(long eventTime, int reason, int flags) {
- mRequestedOrGoingToSleep = true;
+ private void sleepDefaultDisplay(long eventTime, int reason, int flags) {
+ mRequestedOrSleepingDefaultDisplay = true;
mPowerManager.goToSleep(eventTime, reason, flags);
}
@@ -1163,7 +1181,8 @@
Settings.Global.THEATER_MODE_ON, 1);
if (mGoToSleepOnButtonPressTheaterMode && interactive) {
- goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
+ sleepDefaultDisplay(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
+ 0);
}
}
break;
@@ -1271,7 +1290,7 @@
case SHORT_PRESS_SLEEP_GO_TO_SLEEP:
case SHORT_PRESS_SLEEP_GO_TO_SLEEP_AND_GO_HOME:
Slog.i(TAG, "sleepRelease() calling goToSleep(GO_TO_SLEEP_REASON_SLEEP_BUTTON)");
- goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON, 0);
+ sleepDefaultDisplay(eventTime, PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON, 0);
break;
}
}
@@ -1897,8 +1916,8 @@
// Match current screen state.
if (!mPowerManager.isInteractive()) {
- startedGoingToSleep(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
- finishedGoingToSleep(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
+ startedGoingToSleep(PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
+ finishedGoingToSleep(PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
}
mWindowManagerInternal.registerAppTransitionListener(new AppTransitionListener() {
@@ -3686,7 +3705,7 @@
}
if ((mEndcallBehavior
& Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
- goToSleep(event.getEventTime(),
+ sleepDefaultDisplay(event.getEventTime(),
PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
isWakeKey = false;
}
@@ -3729,10 +3748,12 @@
// Any activity on the power button stops the accessibility shortcut
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
+ final boolean isDefaultDisplayOn = Display.isOnState(mDefaultDisplay.getState());
+ final boolean interactiveAndOn = interactive && isDefaultDisplayOn;
if (down) {
- interceptPowerKeyDown(event, interactive);
+ interceptPowerKeyDown(event, interactiveAndOn);
} else {
- interceptPowerKeyUp(event, interactive, canceled);
+ interceptPowerKeyUp(event, interactiveAndOn, canceled);
}
break;
}
@@ -4234,32 +4255,34 @@
// Called on the PowerManager's Notifier thread.
@Override
- public void startedGoingToSleep(int why) {
+ public void startedGoingToSleep(@PowerManager.GoToSleepReason int pmSleepReason) {
if (DEBUG_WAKEUP) {
Slog.i(TAG, "Started going to sleep... (why="
- + WindowManagerPolicyConstants.offReasonToString(why) + ")");
+ + WindowManagerPolicyConstants.offReasonToString(
+ WindowManagerPolicyConstants.translateSleepReasonToOffReason(
+ pmSleepReason)) + ")");
}
- mGoingToSleep = true;
- mRequestedOrGoingToSleep = true;
+ mDeviceGoingToSleep = true;
if (mKeyguardDelegate != null) {
- mKeyguardDelegate.onStartedGoingToSleep(why);
+ mKeyguardDelegate.onStartedGoingToSleep(pmSleepReason);
}
}
// Called on the PowerManager's Notifier thread.
@Override
- public void finishedGoingToSleep(int why) {
+ public void finishedGoingToSleep(@PowerManager.GoToSleepReason int pmSleepReason) {
EventLogTags.writeScreenToggled(0);
if (DEBUG_WAKEUP) {
Slog.i(TAG, "Finished going to sleep... (why="
- + WindowManagerPolicyConstants.offReasonToString(why) + ")");
+ + WindowManagerPolicyConstants.offReasonToString(
+ WindowManagerPolicyConstants.translateSleepReasonToOffReason(
+ pmSleepReason)) + ")");
}
MetricsLogger.histogram(mContext, "screen_timeout", mLockScreenTimeout / 1000);
- mGoingToSleep = false;
- mRequestedOrGoingToSleep = false;
+ mDeviceGoingToSleep = false;
mDefaultDisplayPolicy.setAwake(false);
// We must get this work done here because the power manager will drop
@@ -4271,7 +4294,7 @@
mDefaultDisplayRotation.updateOrientationListener();
if (mKeyguardDelegate != null) {
- mKeyguardDelegate.onFinishedGoingToSleep(why,
+ mKeyguardDelegate.onFinishedGoingToSleep(pmSleepReason,
mCameraGestureTriggeredDuringGoingToSleep);
}
if (mDisplayFoldController != null) {
@@ -4282,11 +4305,13 @@
// Called on the PowerManager's Notifier thread.
@Override
- public void startedWakingUp(@OnReason int why) {
+ public void startedWakingUp(@PowerManager.WakeReason int pmWakeReason) {
EventLogTags.writeScreenToggled(1);
if (DEBUG_WAKEUP) {
Slog.i(TAG, "Started waking up... (why="
- + WindowManagerPolicyConstants.onReasonToString(why) + ")");
+ + WindowManagerPolicyConstants.onReasonToString(
+ WindowManagerPolicyConstants.translateWakeReasonToOnReason(
+ pmWakeReason)) + ")");
}
mDefaultDisplayPolicy.setAwake(true);
@@ -4302,16 +4327,18 @@
mDefaultDisplayRotation.updateOrientationListener();
if (mKeyguardDelegate != null) {
- mKeyguardDelegate.onStartedWakingUp();
+ mKeyguardDelegate.onStartedWakingUp(pmWakeReason);
}
}
// Called on the PowerManager's Notifier thread.
@Override
- public void finishedWakingUp(@OnReason int why) {
+ public void finishedWakingUp(@PowerManager.WakeReason int pmWakeReason) {
if (DEBUG_WAKEUP) {
Slog.i(TAG, "Finished waking up... (why="
- + WindowManagerPolicyConstants.onReasonToString(why) + ")");
+ + WindowManagerPolicyConstants.onReasonToString(
+ WindowManagerPolicyConstants.translateWakeReasonToOnReason(
+ pmWakeReason)) + ")");
}
if (mKeyguardDelegate != null) {
@@ -4405,6 +4432,7 @@
if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turned off...");
+ mRequestedOrSleepingDefaultDisplay = false;
updateScreenOffSleepToken(true);
mDefaultDisplayPolicy.screenTurnedOff();
synchronized (mLock) {
@@ -4471,6 +4499,7 @@
return;
}
+ mRequestedOrSleepingDefaultDisplay = true;
mWindowManagerFuncs.screenTurningOff(screenOffListener);
synchronized (mLock) {
if (mKeyguardDelegate != null) {
@@ -4556,7 +4585,7 @@
@Override
public boolean okToAnimate() {
- return mDefaultDisplayPolicy.isAwake() && !mGoingToSleep;
+ return mDefaultDisplayPolicy.isAwake() && !mDeviceGoingToSleep;
}
/** {@inheritDoc} */
@@ -4730,8 +4759,8 @@
mKeyguardDelegate.onBootCompleted();
}
}
- startedWakingUp(ON_BECAUSE_OF_UNKNOWN);
- finishedWakingUp(ON_BECAUSE_OF_UNKNOWN);
+ startedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
+ finishedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
screenTurningOn(DEFAULT_DISPLAY, null);
screenTurnedOn(DEFAULT_DISPLAY);
}
@@ -4932,7 +4961,7 @@
mWindowManagerFuncs.lockDeviceNow();
break;
case LID_BEHAVIOR_SLEEP:
- goToSleep(SystemClock.uptimeMillis(),
+ sleepDefaultDisplay(SystemClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH,
PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
break;
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 1553966..e9d6440 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -73,6 +73,7 @@
import android.graphics.Rect;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.PowerManager;
import android.os.RemoteException;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
@@ -803,29 +804,35 @@
/**
* Called when the device has started waking up.
+ *
+ * @param pmWakeReason One of PowerManager.WAKE_REASON_*, detailing the specific reason we're
+ * waking up, such as WAKE_REASON_POWER_BUTTON or WAKE_REASON_GESTURE.
*/
- void startedWakingUp(@OnReason int reason);
+ void startedWakingUp(@PowerManager.WakeReason int pmWakeReason);
/**
* Called when the device has finished waking up.
+ *
+ * @param pmWakeReason One of PowerManager.WAKE_REASON_*, detailing the specific reason we're
+ * waking up, such as WAKE_REASON_POWER_BUTTON or WAKE_REASON_GESTURE.
*/
- void finishedWakingUp(@OnReason int reason);
+ void finishedWakingUp(@PowerManager.WakeReason int pmWakeReason);
/**
* Called when the device has started going to sleep.
*
- * @param why {@link #OFF_BECAUSE_OF_USER}, {@link #OFF_BECAUSE_OF_ADMIN},
- * or {@link #OFF_BECAUSE_OF_TIMEOUT}.
+ * @param pmSleepReason One of PowerManager.GO_TO_SLEEP_REASON_*, detailing the specific reason
+ * we're going to sleep, such as GO_TO_SLEEP_REASON_POWER_BUTTON or GO_TO_SLEEP_REASON_TIMEOUT.
*/
- public void startedGoingToSleep(int why);
+ public void startedGoingToSleep(@PowerManager.GoToSleepReason int pmSleepReason);
/**
* Called when the device has finished going to sleep.
*
- * @param why {@link #OFF_BECAUSE_OF_USER}, {@link #OFF_BECAUSE_OF_ADMIN},
- * or {@link #OFF_BECAUSE_OF_TIMEOUT}.
+ * @param pmSleepReason One of PowerManager.GO_TO_SLEEP_REASON_*, detailing the specific reason
+ * we're going to sleep, such as GO_TO_SLEEP_REASON_POWER_BUTTON or GO_TO_SLEEP_REASON_TIMEOUT.
*/
- public void finishedGoingToSleep(int why);
+ public void finishedGoingToSleep(@PowerManager.GoToSleepReason int pmSleepReason);
/**
* Called when the display is about to turn on to show content.
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 9b67efe..c2a1c79 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -15,6 +15,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.PowerManager;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
@@ -176,7 +177,7 @@
// This is used to hide the scrim once keyguard displays.
if (mKeyguardState.interactiveState == INTERACTIVE_STATE_AWAKE
|| mKeyguardState.interactiveState == INTERACTIVE_STATE_WAKING) {
- mKeyguardService.onStartedWakingUp();
+ mKeyguardService.onStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
}
if (mKeyguardState.interactiveState == INTERACTIVE_STATE_AWAKE) {
mKeyguardService.onFinishedWakingUp();
@@ -291,10 +292,10 @@
mKeyguardState.dreaming = false;
}
- public void onStartedWakingUp() {
+ public void onStartedWakingUp(@PowerManager.WakeReason int pmWakeReason) {
if (mKeyguardService != null) {
if (DEBUG) Log.v(TAG, "onStartedWakingUp()");
- mKeyguardService.onStartedWakingUp();
+ mKeyguardService.onStartedWakingUp(pmWakeReason);
}
mKeyguardState.interactiveState = INTERACTIVE_STATE_WAKING;
}
@@ -345,17 +346,19 @@
mKeyguardState.screenState = SCREEN_STATE_ON;
}
- public void onStartedGoingToSleep(int why) {
+ public void onStartedGoingToSleep(@PowerManager.GoToSleepReason int pmSleepReason) {
if (mKeyguardService != null) {
- mKeyguardService.onStartedGoingToSleep(why);
+ mKeyguardService.onStartedGoingToSleep(pmSleepReason);
}
- mKeyguardState.offReason = why;
+ mKeyguardState.offReason =
+ WindowManagerPolicyConstants.translateSleepReasonToOffReason(pmSleepReason);
mKeyguardState.interactiveState = INTERACTIVE_STATE_GOING_TO_SLEEP;
}
- public void onFinishedGoingToSleep(int why, boolean cameraGestureTriggered) {
+ public void onFinishedGoingToSleep(
+ @PowerManager.GoToSleepReason int pmSleepReason, boolean cameraGestureTriggered) {
if (mKeyguardService != null) {
- mKeyguardService.onFinishedGoingToSleep(why, cameraGestureTriggered);
+ mKeyguardService.onFinishedGoingToSleep(pmSleepReason, cameraGestureTriggered);
}
mKeyguardState.interactiveState = INTERACTIVE_STATE_SLEEP;
}
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
index 4e84868..0872b3a 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.PowerManager;
import android.os.RemoteException;
import android.util.Slog;
@@ -101,27 +102,28 @@
}
@Override
- public void onStartedGoingToSleep(int reason) {
+ public void onStartedGoingToSleep(@PowerManager.GoToSleepReason int pmSleepReason) {
try {
- mService.onStartedGoingToSleep(reason);
+ mService.onStartedGoingToSleep(pmSleepReason);
} catch (RemoteException e) {
Slog.w(TAG , "Remote Exception", e);
}
}
@Override
- public void onFinishedGoingToSleep(int reason, boolean cameraGestureTriggered) {
+ public void onFinishedGoingToSleep(
+ @PowerManager.GoToSleepReason int pmSleepReason, boolean cameraGestureTriggered) {
try {
- mService.onFinishedGoingToSleep(reason, cameraGestureTriggered);
+ mService.onFinishedGoingToSleep(pmSleepReason, cameraGestureTriggered);
} catch (RemoteException e) {
Slog.w(TAG , "Remote Exception", e);
}
}
@Override
- public void onStartedWakingUp() {
+ public void onStartedWakingUp(@PowerManager.WakeReason int pmWakeReason) {
try {
- mService.onStartedWakingUp();
+ mService.onStartedWakingUp(pmWakeReason);
} catch (RemoteException e) {
Slog.w(TAG , "Remote Exception", e);
}
diff --git a/services/core/java/com/android/server/power/DisplayGroupPowerStateMapper.java b/services/core/java/com/android/server/power/DisplayGroupPowerStateMapper.java
new file mode 100644
index 0000000..8ebeea3
--- /dev/null
+++ b/services/core/java/com/android/server/power/DisplayGroupPowerStateMapper.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power;
+
+import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
+import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
+import static android.os.PowerManagerInternal.WAKEFULNESS_DOZING;
+import static android.os.PowerManagerInternal.WAKEFULNESS_DREAMING;
+
+import static com.android.server.power.DisplayGroupPowerStateMapper.DisplayGroupPowerChangeListener.DISPLAY_GROUP_ADDED;
+import static com.android.server.power.DisplayGroupPowerStateMapper.DisplayGroupPowerChangeListener.DISPLAY_GROUP_CHANGED;
+import static com.android.server.power.DisplayGroupPowerStateMapper.DisplayGroupPowerChangeListener.DISPLAY_GROUP_REMOVED;
+
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerInternal;
+import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
+import android.os.Handler;
+import android.os.PowerManagerInternal;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
+import com.android.server.display.DisplayGroup;
+
+/**
+ * Responsible for creating {@link DisplayPowerRequest}s and associating them with
+ * {@link com.android.server.display.DisplayGroup}s.
+ *
+ * Each {@link com.android.server.display.DisplayGroup} has a single {@link DisplayPowerRequest}
+ * which is used to request power state changes to every display in the group.
+ */
+public class DisplayGroupPowerStateMapper {
+
+ private static final String TAG = "DisplayPowerRequestMapper";
+
+ /** Lock obtained from {@link PowerManagerService}. */
+ private final Object mLock;
+
+ /** Listener to inform of changes to display groups. */
+ private final DisplayGroupPowerChangeListener mListener;
+
+ /** A mapping from DisplayGroup Id to DisplayGroup information. */
+ @GuardedBy("mLock")
+ private final SparseArray<DisplayGroupInfo> mDisplayGroupInfos = new SparseArray<>();
+
+ /** A cached array of DisplayGroup Ids. */
+ @GuardedBy("mLock")
+ private int[] mDisplayGroupIds;
+
+ private final DisplayManagerInternal.DisplayGroupListener mDisplayGroupListener =
+ new DisplayManagerInternal.DisplayGroupListener() {
+ @Override
+ public void onDisplayGroupAdded(int groupId) {
+ synchronized (mLock) {
+ if (mDisplayGroupInfos.contains(groupId)) {
+ Slog.e(TAG, "Tried to add already existing group:" + groupId);
+ return;
+ }
+ // For now, only the default group supports sandman.
+ final boolean supportsSandman = groupId == DisplayGroup.DEFAULT;
+ final DisplayGroupInfo displayGroupInfo = new DisplayGroupInfo(
+ new DisplayPowerRequest(),
+ getGlobalWakefulnessLocked(), /* ready= */ false,
+ supportsSandman);
+ mDisplayGroupInfos.append(groupId, displayGroupInfo);
+ mDisplayGroupIds = ArrayUtils.appendInt(mDisplayGroupIds, groupId);
+ mListener.onDisplayGroupEventLocked(DISPLAY_GROUP_ADDED, groupId);
+ }
+ }
+
+ @Override
+ public void onDisplayGroupRemoved(int groupId) {
+ synchronized (mLock) {
+ if (!mDisplayGroupInfos.contains(groupId)) {
+ Slog.e(TAG, "Tried to remove non-existent group:" + groupId);
+ return;
+ }
+ mDisplayGroupInfos.delete(groupId);
+ mDisplayGroupIds = ArrayUtils.removeInt(mDisplayGroupIds, groupId);
+ mListener.onDisplayGroupEventLocked(DISPLAY_GROUP_REMOVED, groupId);
+ }
+ }
+
+ @Override
+ public void onDisplayGroupChanged(int groupId) {
+ synchronized (mLock) {
+ mListener.onDisplayGroupEventLocked(DISPLAY_GROUP_CHANGED, groupId);
+ }
+ }
+ };
+
+ DisplayGroupPowerStateMapper(Object lock, DisplayManagerInternal displayManagerInternal,
+ DisplayGroupPowerChangeListener listener) {
+ mLock = lock;
+ mListener = listener;
+ displayManagerInternal.registerDisplayGroupListener(mDisplayGroupListener);
+
+ final DisplayGroupInfo displayGroupInfo = new DisplayGroupInfo(
+ new DisplayPowerRequest(), WAKEFULNESS_AWAKE, /* ready= */
+ false, /* supportsSandman= */ true);
+ mDisplayGroupInfos.append(DisplayGroup.DEFAULT, displayGroupInfo);
+ mDisplayGroupIds = new int[]{DisplayGroup.DEFAULT};
+ }
+
+ DisplayPowerRequest getPowerRequestLocked(int groupId) {
+ return mDisplayGroupInfos.get(groupId).displayPowerRequest;
+ }
+
+ int[] getDisplayGroupIdsLocked() {
+ return mDisplayGroupIds;
+ }
+
+ int getWakefulnessLocked(int groupId) {
+ return mDisplayGroupInfos.get(groupId).wakefulness;
+ }
+
+ void setLastPowerOnTimeLocked(int groupId, long eventTime) {
+ mDisplayGroupInfos.get(groupId).lastPowerOnTime = eventTime;
+ }
+
+ long getLastPowerOnTimeLocked(int groupId) {
+ return mDisplayGroupInfos.get(groupId).lastPowerOnTime;
+ }
+
+ /**
+ * Returns the amalgamated wakefulness of all {@link DisplayGroup DisplayGroups}.
+ *
+ * <p>This will be the highest wakeful state of all {@link DisplayGroup DisplayGroups}; ordered
+ * from highest to lowest:
+ * <ol>
+ * <li>{@link PowerManagerInternal#WAKEFULNESS_AWAKE}
+ * <li>{@link PowerManagerInternal#WAKEFULNESS_DREAMING}
+ * <li>{@link PowerManagerInternal#WAKEFULNESS_DOZING}
+ * <li>{@link PowerManagerInternal#WAKEFULNESS_ASLEEP}
+ * </ol>
+ */
+ int getGlobalWakefulnessLocked() {
+ final int size = mDisplayGroupInfos.size();
+ int deviceWakefulness = WAKEFULNESS_ASLEEP;
+ for (int i = 0; i < size; i++) {
+ final int wakefulness = mDisplayGroupInfos.valueAt(i).wakefulness;
+ if (wakefulness == WAKEFULNESS_AWAKE) {
+ return WAKEFULNESS_AWAKE;
+ } else if (wakefulness == WAKEFULNESS_DREAMING
+ && (deviceWakefulness == WAKEFULNESS_ASLEEP
+ || deviceWakefulness == WAKEFULNESS_DOZING)) {
+ deviceWakefulness = WAKEFULNESS_DREAMING;
+ } else if (wakefulness == WAKEFULNESS_DOZING
+ && deviceWakefulness == WAKEFULNESS_ASLEEP) {
+ deviceWakefulness = WAKEFULNESS_DOZING;
+ }
+ }
+
+ return deviceWakefulness;
+ }
+
+ /**
+ * Sets the {@code wakefulness} value for the {@link DisplayGroup} specified by the provided
+ * {@code groupId}.
+ *
+ * @return {@code true} if the wakefulness value was changed; {@code false} otherwise.
+ */
+ boolean setWakefulnessLocked(int groupId, int wakefulness) {
+ final DisplayGroupInfo displayGroupInfo = mDisplayGroupInfos.get(groupId);
+ if (displayGroupInfo.wakefulness != wakefulness) {
+ displayGroupInfo.wakefulness = wakefulness;
+ return true;
+ }
+
+ return false;
+ }
+
+ boolean isSandmanSummoned(int groupId) {
+ return mDisplayGroupInfos.get(groupId).sandmanSummoned;
+ }
+
+ boolean isSandmanSupported(int groupId) {
+ return mDisplayGroupInfos.get(groupId).supportsSandman;
+ }
+
+ /**
+ * Sets whether or not the sandman is summoned for the given {@code groupId}.
+ *
+ * @param groupId Signifies the DisplayGroup for which to summon or unsummon the
+ * sandman.
+ * @param sandmanSummoned {@code true} to summon the sandman; {@code false} to unsummon.
+ */
+ void setSandmanSummoned(int groupId, boolean sandmanSummoned) {
+ final DisplayGroupInfo displayGroupInfo = mDisplayGroupInfos.get(groupId);
+ displayGroupInfo.sandmanSummoned = displayGroupInfo.supportsSandman && sandmanSummoned;
+ }
+
+ /**
+ * Returns {@code true} if every display in the specified group has its requested state matching
+ * its actual state.
+ *
+ * @param groupId The identifier for the display group to check for readiness.
+ */
+ boolean isReady(int groupId) {
+ return mDisplayGroupInfos.get(groupId).ready;
+ }
+
+ /** Returns {@code true} if every display has its requested state matching its actual state. */
+ boolean areAllDisplaysReadyLocked() {
+ final int size = mDisplayGroupInfos.size();
+ for (int i = 0; i < size; i++) {
+ if (!mDisplayGroupInfos.valueAt(i).ready) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Sets whether the displays specified by the provided {@code groupId} are all ready.
+ *
+ * <p>A display is ready if its reported
+ * {@link DisplayManagerInternal.DisplayPowerCallbacks#onStateChanged() actual state} matches
+ * its {@link DisplayManagerInternal#requestPowerState requested state}.
+ *
+ * @param groupId The identifier for the display group.
+ * @param ready {@code true} if every display in the group is ready; otherwise {@code false}.
+ * @return {@code true} if the ready state changed; otherwise {@code false}.
+ */
+ boolean setDisplayGroupReadyLocked(int groupId, boolean ready) {
+ final DisplayGroupInfo displayGroupInfo = mDisplayGroupInfos.get(groupId);
+ if (displayGroupInfo.ready != ready) {
+ displayGroupInfo.ready = ready;
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Interface through which an interested party may be informed of {@link DisplayGroup} events.
+ */
+ interface DisplayGroupPowerChangeListener {
+ int DISPLAY_GROUP_ADDED = 0;
+ int DISPLAY_GROUP_REMOVED = 1;
+ int DISPLAY_GROUP_CHANGED = 2;
+
+ void onDisplayGroupEventLocked(int event, int groupId);
+ }
+
+ private static final class DisplayGroupInfo {
+ final DisplayPowerRequest displayPowerRequest;
+ int wakefulness;
+ boolean ready;
+ long lastPowerOnTime;
+ boolean sandmanSummoned;
+
+ /** {@code true} if this DisplayGroup supports dreaming; otherwise {@code false}. */
+ boolean supportsSandman;
+
+ DisplayGroupInfo(DisplayPowerRequest displayPowerRequest, int wakefulness, boolean ready,
+ boolean supportsSandman) {
+ this.displayPowerRequest = displayPowerRequest;
+ this.wakefulness = wakefulness;
+ this.ready = ready;
+ this.supportsSandman = supportsSandman;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/power/DisplayPowerRequestMapper.java b/services/core/java/com/android/server/power/DisplayPowerRequestMapper.java
deleted file mode 100644
index 6477552..0000000
--- a/services/core/java/com/android/server/power/DisplayPowerRequestMapper.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.power;
-
-import android.hardware.display.DisplayManager;
-import android.hardware.display.DisplayManagerInternal;
-import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
-import android.os.Handler;
-import android.util.SparseArray;
-import android.util.SparseIntArray;
-import android.view.Display;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.server.display.DisplayGroup;
-
-/**
- * Responsible for creating {@link DisplayPowerRequest}s and associating them with
- * {@link com.android.server.display.DisplayGroup}s.
- *
- * Each {@link com.android.server.display.DisplayGroup} has a single {@link DisplayPowerRequest}
- * which is used to request power state changes to every display in the group.
- */
-class DisplayPowerRequestMapper {
-
- private final Object mLock = new Object();
-
- /** A mapping from LogicalDisplay Id to DisplayGroup Id. */
- @GuardedBy("mLock")
- private final SparseIntArray mDisplayGroupIds = new SparseIntArray();
-
- /** A mapping from DisplayGroup Id to DisplayPowerRequest. */
- @GuardedBy("mLock")
- private final SparseArray<DisplayPowerRequest> mDisplayPowerRequests = new SparseArray<>();
-
- private final DisplayManagerInternal mDisplayManagerInternal;
-
- private final DisplayManager.DisplayListener mDisplayListener =
- new DisplayManager.DisplayListener() {
-
- @Override
- public void onDisplayAdded(int displayId) {
- synchronized (mLock) {
- if (mDisplayGroupIds.indexOfKey(displayId) >= 0) {
- return;
- }
- final int displayGroupId = mDisplayManagerInternal.getDisplayGroupId(
- displayId);
- if (!mDisplayPowerRequests.contains(displayGroupId)) {
- // A new DisplayGroup was created; create a new DisplayPowerRequest.
- mDisplayPowerRequests.append(displayGroupId, new DisplayPowerRequest());
- }
- mDisplayGroupIds.append(displayId, displayGroupId);
- }
- }
-
- @Override
- public void onDisplayRemoved(int displayId) {
- synchronized (mLock) {
- final int index = mDisplayGroupIds.indexOfKey(displayId);
- if (index < 0) {
- return;
- }
- final int displayGroupId = mDisplayGroupIds.valueAt(index);
- mDisplayGroupIds.removeAt(index);
-
- if (mDisplayGroupIds.indexOfValue(displayGroupId) < 0) {
- // The DisplayGroup no longer exists; delete the DisplayPowerRequest.
- mDisplayPowerRequests.delete(displayGroupId);
- }
- }
- }
-
- @Override
- public void onDisplayChanged(int displayId) {
- synchronized (mLock) {
- final int newDisplayGroupId = mDisplayManagerInternal.getDisplayGroupId(
- displayId);
- final int oldDisplayGroupId = mDisplayGroupIds.get(displayId);
-
- if (!mDisplayPowerRequests.contains(newDisplayGroupId)) {
- // A new DisplayGroup was created; create a new DisplayPowerRequest.
- mDisplayPowerRequests.append(newDisplayGroupId,
- new DisplayPowerRequest());
- }
- mDisplayGroupIds.put(displayId, newDisplayGroupId);
-
- if (mDisplayGroupIds.indexOfValue(oldDisplayGroupId) < 0) {
- // The DisplayGroup no longer exists; delete the DisplayPowerRequest.
- mDisplayPowerRequests.delete(oldDisplayGroupId);
- }
- }
- }
- };
-
- DisplayPowerRequestMapper(DisplayManager displayManager,
- DisplayManagerInternal displayManagerInternal, Handler handler) {
- mDisplayManagerInternal = displayManagerInternal;
- displayManager.registerDisplayListener(mDisplayListener, handler);
- mDisplayPowerRequests.append(DisplayGroup.DEFAULT, new DisplayPowerRequest());
- mDisplayGroupIds.append(Display.DEFAULT_DISPLAY, DisplayGroup.DEFAULT);
- }
-
- DisplayPowerRequest get(int displayId) {
- synchronized (mLock) {
- return mDisplayPowerRequests.get(mDisplayGroupIds.get(displayId));
- }
- }
-}
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index d4375eb..b8e0156 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -36,7 +36,6 @@
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
-import android.os.PowerManager.WakeReason;
import android.os.PowerManagerInternal;
import android.os.Process;
import android.os.RemoteException;
@@ -49,7 +48,7 @@
import android.telephony.TelephonyManager;
import android.util.EventLog;
import android.util.Slog;
-import android.view.WindowManagerPolicyConstants.OnReason;
+import android.view.WindowManagerPolicyConstants;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
@@ -455,13 +454,7 @@
synchronized (mLock) {
if (mInteractive) {
// Waking up...
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- final int why = translateOnReason(mInteractiveChangeReason);
- mPolicy.startedWakingUp(why);
- }
- });
+ mHandler.post(() -> mPolicy.startedWakingUp(mInteractiveChangeReason));
// Send interactive broadcast.
mPendingInteractiveState = INTERACTIVE_STATE_AWAKE;
@@ -470,13 +463,7 @@
} else {
// Going to sleep...
// Tell the policy that we started going to sleep.
- final int why = translateOffReason(mInteractiveChangeReason);
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mPolicy.startedGoingToSleep(why);
- }
- });
+ mHandler.post(() -> mPolicy.startedGoingToSleep(mInteractiveChangeReason));
}
}
}
@@ -492,20 +479,17 @@
(int) (SystemClock.uptimeMillis() - mInteractiveChangeStartTime);
if (mInteractive) {
// Finished waking up...
- final int why = translateOnReason(mInteractiveChangeReason);
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- LogMaker log = new LogMaker(MetricsEvent.SCREEN);
- log.setType(MetricsEvent.TYPE_OPEN);
- log.setSubtype(why);
- log.setLatency(interactiveChangeLatency);
- log.addTaggedData(
- MetricsEvent.FIELD_SCREEN_WAKE_REASON, mInteractiveChangeReason);
- MetricsLogger.action(log);
- EventLogTags.writePowerScreenState(1, 0, 0, 0, interactiveChangeLatency);
- mPolicy.finishedWakingUp(why);
- }
+ mHandler.post(() -> {
+ LogMaker log = new LogMaker(MetricsEvent.SCREEN);
+ log.setType(MetricsEvent.TYPE_OPEN);
+ log.setSubtype(WindowManagerPolicyConstants.translateWakeReasonToOnReason(
+ mInteractiveChangeReason));
+ log.setLatency(interactiveChangeLatency);
+ log.addTaggedData(
+ MetricsEvent.FIELD_SCREEN_WAKE_REASON, mInteractiveChangeReason);
+ MetricsLogger.action(log);
+ EventLogTags.writePowerScreenState(1, 0, 0, 0, interactiveChangeLatency);
+ mPolicy.finishedWakingUp(mInteractiveChangeReason);
});
} else {
// Finished going to sleep...
@@ -521,20 +505,19 @@
}
// Tell the policy we finished going to sleep.
- final int why = translateOffReason(mInteractiveChangeReason);
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- LogMaker log = new LogMaker(MetricsEvent.SCREEN);
- log.setType(MetricsEvent.TYPE_CLOSE);
- log.setSubtype(why);
- log.setLatency(interactiveChangeLatency);
- log.addTaggedData(
- MetricsEvent.FIELD_SCREEN_SLEEP_REASON, mInteractiveChangeReason);
- MetricsLogger.action(log);
- EventLogTags.writePowerScreenState(0, why, 0, 0, interactiveChangeLatency);
- mPolicy.finishedGoingToSleep(why);
- }
+ final int offReason = WindowManagerPolicyConstants.translateSleepReasonToOffReason(
+ mInteractiveChangeReason);
+ mHandler.post(() -> {
+ LogMaker log = new LogMaker(MetricsEvent.SCREEN);
+ log.setType(MetricsEvent.TYPE_CLOSE);
+ log.setSubtype(offReason);
+ log.setLatency(interactiveChangeLatency);
+ log.addTaggedData(
+ MetricsEvent.FIELD_SCREEN_SLEEP_REASON, mInteractiveChangeReason);
+ MetricsLogger.action(log);
+ EventLogTags.writePowerScreenState(
+ 0, offReason, 0, 0, interactiveChangeLatency);
+ mPolicy.finishedGoingToSleep(mInteractiveChangeReason);
});
// Send non-interactive broadcast.
@@ -545,35 +528,6 @@
}
}
- private static int translateOffReason(int reason) {
- switch (reason) {
- case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:
- return WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN;
- case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:
- case PowerManager.GO_TO_SLEEP_REASON_INATTENTIVE:
- return WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT;
- default:
- return WindowManagerPolicy.OFF_BECAUSE_OF_USER;
- }
- }
-
- private static @OnReason int translateOnReason(@WakeReason int reason) {
- switch (reason) {
- case PowerManager.WAKE_REASON_POWER_BUTTON:
- case PowerManager.WAKE_REASON_PLUGGED_IN:
- case PowerManager.WAKE_REASON_GESTURE:
- case PowerManager.WAKE_REASON_CAMERA_LAUNCH:
- case PowerManager.WAKE_REASON_WAKE_KEY:
- case PowerManager.WAKE_REASON_WAKE_MOTION:
- case PowerManager.WAKE_REASON_LID:
- return WindowManagerPolicy.ON_BECAUSE_OF_USER;
- case PowerManager.WAKE_REASON_APPLICATION:
- return WindowManagerPolicy.ON_BECAUSE_OF_APPLICATION;
- default:
- return WindowManagerPolicy.ON_BECAUSE_OF_UNKNOWN;
- }
- }
-
/**
* Called when there has been user activity.
*/
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 084dc32..f14ff3c 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -18,6 +18,10 @@
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_DEFAULT;
+import static android.os.PowerManager.GO_TO_SLEEP_REASON_DISPLAY_GROUP_REMOVED;
+import static android.os.PowerManager.GO_TO_SLEEP_REASON_DISPLAY_GROUPS_TURNED_OFF;
+import static android.os.PowerManager.WAKE_REASON_DISPLAY_GROUP_ADDED;
+import static android.os.PowerManager.WAKE_REASON_DISPLAY_GROUP_TURNED_ON;
import static android.os.PowerManagerInternal.MODE_DEVICE_IDLE;
import static android.os.PowerManagerInternal.MODE_DISPLAY_INACTIVE;
import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
@@ -42,7 +46,6 @@
import android.hardware.SensorManager;
import android.hardware.SystemSensorManager;
import android.hardware.display.AmbientDisplayConfiguration;
-import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
import android.hardware.power.Boost;
@@ -107,6 +110,7 @@
import com.android.server.UserspaceRebootLogger;
import com.android.server.Watchdog;
import com.android.server.am.BatteryStatsService;
+import com.android.server.display.DisplayGroup;
import com.android.server.lights.LightsManager;
import com.android.server.lights.LogicalLight;
import com.android.server.policy.WindowManagerPolicy;
@@ -176,6 +180,8 @@
private static final int DIRTY_VR_MODE_CHANGED = 1 << 13;
// Dirty bit: attentive timer may have timed out
private static final int DIRTY_ATTENTIVE = 1 << 14;
+ // Dirty bit: display group power state has changed
+ private static final int DIRTY_DISPLAY_GROUP_POWER_UPDATED = 1 << 15;
// Summarizes the state of all active wakelocks.
private static final int WAKE_LOCK_CPU = 1 << 0;
@@ -297,10 +303,6 @@
private int mWakefulnessRaw;
private boolean mWakefulnessChanging;
- // True if the sandman has just been summoned for the first time since entering the
- // dreaming or dozing state. Indicates whether a new dream should begin.
- private boolean mSandmanSummoned;
-
// True if MSG_SANDMAN has been scheduled.
private boolean mSandmanScheduled;
@@ -351,11 +353,7 @@
// Manages the desired power state of displays. The actual state may lag behind the
// requested because it is updated asynchronously by the display power controller.
- private DisplayPowerRequestMapper mDisplayPowerRequestMapper;
-
- // True if the display power state has been fully applied, which means the display
- // is actually on or actually off or whatever was requested.
- private boolean mDisplayReady;
+ private DisplayGroupPowerStateMapper mDisplayGroupPowerStateMapper;
// The suspend blocker used to keep the CPU alive when an application has acquired
// a wake lock.
@@ -625,6 +623,39 @@
// but the DreamService has not yet been told to start (it's an async process).
private boolean mDozeStartInProgress;
+ private final class DisplayGroupPowerChangeListener implements
+ DisplayGroupPowerStateMapper.DisplayGroupPowerChangeListener {
+ @Override
+ public void onDisplayGroupEventLocked(int event, int groupId) {
+ final int oldWakefulness = getWakefulnessLocked();
+ final int newWakefulness = mDisplayGroupPowerStateMapper.getGlobalWakefulnessLocked();
+ if (oldWakefulness != newWakefulness) {
+ final int reason;
+ switch (newWakefulness) {
+ case WAKEFULNESS_AWAKE:
+ reason = event == DISPLAY_GROUP_ADDED ? WAKE_REASON_DISPLAY_GROUP_ADDED
+ : WAKE_REASON_DISPLAY_GROUP_TURNED_ON;
+ break;
+ case WAKEFULNESS_DOZING:
+ reason = event == DISPLAY_GROUP_REMOVED
+ ? GO_TO_SLEEP_REASON_DISPLAY_GROUP_REMOVED
+ : GO_TO_SLEEP_REASON_DISPLAY_GROUPS_TURNED_OFF;
+ break;
+ default:
+ reason = 0;
+ }
+
+ setGlobalWakefulnessLocked(
+ mDisplayGroupPowerStateMapper.getGlobalWakefulnessLocked(),
+ mClock.uptimeMillis(), reason, Process.SYSTEM_UID, Process.SYSTEM_UID,
+ mContext.getOpPackageName(), "groupId: " + groupId);
+ }
+
+ mDirty |= DIRTY_DISPLAY_GROUP_POWER_UPDATED;
+ updatePowerStateLocked();
+ }
+ }
+
private final class ForegroundProfileObserver extends SynchronousUserSwitchObserver {
@Override
public void onUserSwitching(@UserIdInt int newUserId) throws RemoteException {
@@ -868,6 +899,12 @@
void invalidateIsInteractiveCaches() {
PowerManager.invalidateIsInteractiveCaches();
}
+
+ DisplayGroupPowerStateMapper createDisplayPowerRequestMapper(Object lock,
+ DisplayManagerInternal displayManagerInternal,
+ DisplayGroupPowerStateMapper.DisplayGroupPowerChangeListener listener) {
+ return new DisplayGroupPowerStateMapper(lock, displayManagerInternal, listener);
+ }
}
final Constants mConstants;
@@ -1037,7 +1074,7 @@
now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
if (sQuiescent) {
- goToSleepNoUpdateLocked(mClock.uptimeMillis(),
+ sleepDisplayGroupNoUpdateLocked(DisplayGroup.DEFAULT, mClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_QUIESCENT,
PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE, Process.SYSTEM_UID);
}
@@ -1055,8 +1092,8 @@
mPolicy = getLocalService(WindowManagerPolicy.class);
mBatteryManagerInternal = getLocalService(BatteryManagerInternal.class);
mAttentionDetector.systemReady(mContext);
- mDisplayPowerRequestMapper = new DisplayPowerRequestMapper(mContext.getSystemService(
- DisplayManager.class), mDisplayManagerInternal, mHandler);
+ mDisplayGroupPowerStateMapper = mInjector.createDisplayPowerRequestMapper(mLock,
+ mDisplayManagerInternal, new DisplayGroupPowerChangeListener());
SensorManager sensorManager = new SystemSensorManager(mContext, mHandler.getLooper());
@@ -1373,9 +1410,11 @@
opPackageName = wakeLock.mPackageName;
opUid = wakeLock.mOwnerUid;
}
- wakeUpNoUpdateLocked(mClock.uptimeMillis(),
- PowerManager.WAKE_REASON_APPLICATION, wakeLock.mTag,
- opUid, opPackageName, opUid);
+ for (int id : mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked()) {
+ wakeDisplayGroupNoUpdateLocked(id, mClock.uptimeMillis(),
+ PowerManager.WAKE_REASON_APPLICATION, wakeLock.mTag,
+ opUid, opPackageName, opUid);
+ }
}
}
@@ -1664,74 +1703,69 @@
}
}
- private void wakeUpInternal(long eventTime, @WakeReason int reason, String details, int uid,
- String opPackageName, int opUid) {
+ private void wakeDisplayGroup(int groupId, long eventTime, @WakeReason int reason,
+ String details, int uid, String opPackageName, int opUid) {
synchronized (mLock) {
- if (wakeUpNoUpdateLocked(eventTime, reason, details, uid, opPackageName, opUid)) {
+ if (wakeDisplayGroupNoUpdateLocked(groupId, eventTime, reason, details, uid,
+ opPackageName, opUid)) {
updatePowerStateLocked();
}
}
}
- private boolean wakeUpNoUpdateLocked(long eventTime, @WakeReason int reason, String details,
- int reasonUid, String opPackageName, int opUid) {
+ private boolean wakeDisplayGroupNoUpdateLocked(int groupId, long eventTime,
+ @WakeReason int reason, String details, int uid, String opPackageName, int opUid) {
if (DEBUG_SPEW) {
- Slog.d(TAG, "wakeUpNoUpdateLocked: eventTime=" + eventTime + ", uid=" + reasonUid);
+ Slog.d(TAG, "wakeDisplayGroupNoUpdateLocked: eventTime=" + eventTime
+ +", groupId=" + groupId + ", uid=" + uid);
}
- if (eventTime < mLastSleepTime || getWakefulnessLocked() == WAKEFULNESS_AWAKE
- || mForceSuspendActive || !mSystemReady) {
+ if (eventTime < mLastSleepTime || mForceSuspendActive || !mSystemReady) {
return false;
}
- Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, 0);
+ final int currentState = mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId);
+ if (currentState == WAKEFULNESS_AWAKE) {
+ return false;
+ }
- Trace.traceBegin(Trace.TRACE_TAG_POWER, "wakeUp");
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "powerOnDisplay");
try {
- Slog.i(TAG, "Waking up from "
- + PowerManagerInternal.wakefulnessToString(getWakefulnessLocked())
- + " (uid=" + reasonUid
+ Slog.i(TAG, "Powering on display group from"
+ + PowerManagerInternal.wakefulnessToString(currentState)
+ + " (groupId=" + groupId
+ + ", uid=" + uid
+ ", reason=" + PowerManager.wakeReasonToString(reason)
+ ", details=" + details
+ ")...");
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, groupId);
- mLastWakeTime = eventTime;
- mLastWakeReason = reason;
- setWakefulnessLocked(WAKEFULNESS_AWAKE, reason, eventTime);
-
- mNotifier.onWakeUp(reason, details, reasonUid, opPackageName, opUid);
- userActivityNoUpdateLocked(
- eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);
-
- if (sQuiescent) {
- mDirty |= DIRTY_QUIESCENT;
- }
+ setWakefulnessLocked(groupId, WAKEFULNESS_AWAKE, eventTime, uid, reason, opUid,
+ opPackageName, details);
+ mDisplayGroupPowerStateMapper.setLastPowerOnTimeLocked(groupId, eventTime);
+ mDirty |= DIRTY_DISPLAY_GROUP_POWER_UPDATED;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
+
return true;
}
- private void goToSleepInternal(long eventTime, int reason, int flags, int uid) {
+ private void sleepDisplayGroup(int groupId, long eventTime, int reason, int flags,
+ int uid) {
synchronized (mLock) {
- if (goToSleepNoUpdateLocked(eventTime, reason, flags, uid)) {
+ if (sleepDisplayGroupNoUpdateLocked(groupId, eventTime, reason, flags, uid)) {
updatePowerStateLocked();
}
}
}
- /**
- * Puts the system in doze.
- *
- * This method is called goToSleep for historical reasons but actually attempts to DOZE,
- * and only tucks itself in to SLEEP if requested with the flag
- * {@link PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE}.
- */
- @SuppressWarnings("deprecation")
- private boolean goToSleepNoUpdateLocked(long eventTime, int reason, int flags, int uid) {
+ private boolean sleepDisplayGroupNoUpdateLocked(int groupId, long eventTime, int reason,
+ int flags, int uid) {
if (DEBUG_SPEW) {
- Slog.d(TAG, "goToSleepNoUpdateLocked: eventTime=" + eventTime
- + ", reason=" + reason + ", flags=" + flags + ", uid=" + uid);
+ Slog.d(TAG, "powerOffDisplayGroupNoUpdateLocked: eventTime=" + eventTime
+ + ", groupId=" + groupId + ", reason=" + reason + ", flags=" + flags
+ + ", uid=" + uid);
}
if (eventTime < mLastWakeTime
@@ -1742,55 +1776,44 @@
return false;
}
- Trace.traceBegin(Trace.TRACE_TAG_POWER, "goToSleep");
+ final int wakefulness = mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId);
+ if (!PowerManagerInternal.isInteractive(wakefulness)) {
+ return false;
+ }
+
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "powerOffDisplay");
try {
reason = Math.min(PowerManager.GO_TO_SLEEP_REASON_MAX,
Math.max(reason, PowerManager.GO_TO_SLEEP_REASON_MIN));
- Slog.i(TAG, "Going to sleep due to " + PowerManager.sleepReasonToString(reason)
- + " (uid " + uid + ")...");
+ Slog.i(TAG, "Powering off display group due to "
+ + PowerManager.sleepReasonToString(reason) + " (groupId= " + groupId
+ + ", uid= " + uid + ")...");
- mLastSleepTime = eventTime;
- mLastSleepReason = reason;
- mSandmanSummoned = true;
- mDozeStartInProgress = true;
- setWakefulnessLocked(WAKEFULNESS_DOZING, reason, eventTime);
-
- // Report the number of wake locks that will be cleared by going to sleep.
- int numWakeLocksCleared = 0;
- final int numWakeLocks = mWakeLocks.size();
- for (int i = 0; i < numWakeLocks; i++) {
- final WakeLock wakeLock = mWakeLocks.get(i);
- switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
- case PowerManager.FULL_WAKE_LOCK:
- case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
- case PowerManager.SCREEN_DIM_WAKE_LOCK:
- numWakeLocksCleared += 1;
- break;
- }
- }
- EventLogTags.writePowerSleepRequested(numWakeLocksCleared);
-
- // Skip dozing if requested.
+ mDisplayGroupPowerStateMapper.setSandmanSummoned(groupId, true);
+ setWakefulnessLocked(groupId, WAKEFULNESS_DOZING, eventTime, uid, reason,
+ /* opUid= */ 0, /* opPackageName= */ null, /* details= */ null);
if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) {
- reallyGoToSleepNoUpdateLocked(eventTime, uid);
+ reallySleepDisplayGroupNoUpdateLocked(groupId, eventTime, uid);
}
+ mDirty |= DIRTY_DISPLAY_GROUP_POWER_UPDATED;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}
- private void napInternal(long eventTime, int uid) {
+ private void dreamDisplayGroup(int groupId, long eventTime, int uid) {
synchronized (mLock) {
- if (napNoUpdateLocked(eventTime, uid)) {
+ if (dreamDisplayGroupNoUpdateLocked(groupId, eventTime, uid)) {
updatePowerStateLocked();
}
}
}
- private boolean napNoUpdateLocked(long eventTime, int uid) {
+ private boolean dreamDisplayGroupNoUpdateLocked(int groupId, long eventTime, int uid) {
if (DEBUG_SPEW) {
- Slog.d(TAG, "napNoUpdateLocked: eventTime=" + eventTime + ", uid=" + uid);
+ Slog.d(TAG, "dreamDisplayGroupNoUpdateLocked: eventTime=" + eventTime
+ + ", uid=" + uid);
}
if (eventTime < mLastWakeTime || getWakefulnessLocked() != WAKEFULNESS_AWAKE
@@ -1798,36 +1821,42 @@
return false;
}
- Trace.traceBegin(Trace.TRACE_TAG_POWER, "nap");
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "napDisplayGroup");
try {
- Slog.i(TAG, "Nap time (uid " + uid +")...");
+ Slog.i(TAG, "Napping display group (groupId=" + groupId + ", uid=" + uid + ")...");
- mSandmanSummoned = true;
- setWakefulnessLocked(WAKEFULNESS_DREAMING, 0, eventTime);
+ mDisplayGroupPowerStateMapper.setSandmanSummoned(groupId, true);
+ setWakefulnessLocked(groupId, WAKEFULNESS_DREAMING, eventTime, uid, /* reason= */
+ 0, /* opUid= */ 0, /* opPackageName= */ null, /* details= */ null);
+ mDirty |= DIRTY_DISPLAY_GROUP_POWER_UPDATED;
+
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}
- // Done dozing, drop everything and go to sleep.
- private boolean reallyGoToSleepNoUpdateLocked(long eventTime, int uid) {
+ private boolean reallySleepDisplayGroupNoUpdateLocked(int groupId, long eventTime, int uid) {
if (DEBUG_SPEW) {
- Slog.d(TAG, "reallyGoToSleepNoUpdateLocked: eventTime=" + eventTime
+ Slog.d(TAG, "reallySleepDisplayGroupNoUpdateLocked: eventTime=" + eventTime
+ ", uid=" + uid);
}
if (eventTime < mLastWakeTime || getWakefulnessLocked() == WAKEFULNESS_ASLEEP
- || !mBootCompleted || !mSystemReady) {
+ || !mBootCompleted || !mSystemReady
+ || mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId)
+ == WAKEFULNESS_ASLEEP) {
return false;
}
- Trace.traceBegin(Trace.TRACE_TAG_POWER, "reallyGoToSleep");
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "reallySleepDisplayGroup");
try {
- Slog.i(TAG, "Sleeping (uid " + uid +")...");
+ Slog.i(TAG, "Sleeping display group (groupId=" + groupId + ", uid=" + uid +")...");
- setWakefulnessLocked(WAKEFULNESS_ASLEEP, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT,
- eventTime);
+ setWakefulnessLocked(groupId, WAKEFULNESS_ASLEEP, eventTime, uid,
+ PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, /* opUid= */ 0,
+ /* opPackageName= */ null, /* details= */ null);
+ mDirty |= DIRTY_DISPLAY_GROUP_POWER_UPDATED;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
@@ -1835,8 +1864,62 @@
}
@VisibleForTesting
- void setWakefulnessLocked(int wakefulness, int reason, long eventTime) {
- if (getWakefulnessLocked() != wakefulness) {
+ void setWakefulnessLocked(int groupId, int wakefulness, long eventTime, int uid, int reason,
+ int opUid, String opPackageName, String details) {
+ if (mDisplayGroupPowerStateMapper.setWakefulnessLocked(groupId, wakefulness)) {
+ setGlobalWakefulnessLocked(mDisplayGroupPowerStateMapper.getGlobalWakefulnessLocked(),
+ eventTime, reason, uid, opUid, opPackageName, details);
+ }
+ }
+
+ private void setGlobalWakefulnessLocked(int wakefulness, long eventTime, int reason, int uid,
+ int opUid, String opPackageName, String details) {
+ if (getWakefulnessLocked() == wakefulness) {
+ return;
+ }
+
+ // Phase 1: Handle pre-wakefulness change bookkeeping.
+ final String traceMethodName;
+ switch (wakefulness) {
+ case WAKEFULNESS_ASLEEP:
+ traceMethodName = "reallyGoToSleep";
+ Slog.i(TAG, "Sleeping (uid " + uid + ")...");
+ break;
+
+ case WAKEFULNESS_AWAKE:
+ traceMethodName = "wakeUp";
+ Slog.i(TAG, "Waking up from "
+ + PowerManagerInternal.wakefulnessToString(getWakefulnessLocked())
+ + " (uid=" + uid
+ + ", reason=" + PowerManager.wakeReasonToString(reason)
+ + ", details=" + details
+ + ")...");
+ mLastWakeTime = eventTime;
+ mLastWakeReason = reason;
+ break;
+
+ case WAKEFULNESS_DREAMING:
+ traceMethodName = "nap";
+ Slog.i(TAG, "Nap time (uid " + uid + ")...");
+ break;
+
+ case WAKEFULNESS_DOZING:
+ traceMethodName = "goToSleep";
+ Slog.i(TAG, "Going to sleep due to " + PowerManager.sleepReasonToString(reason)
+ + " (uid " + uid + ")...");
+
+ mLastSleepTime = eventTime;
+ mLastSleepReason = reason;
+ mDozeStartInProgress = true;
+ break;
+
+ default:
+ throw new IllegalArgumentException("Unexpected wakefulness: " + wakefulness);
+ }
+
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, traceMethodName);
+ try {
+ // Phase 2: Handle wakefulness change and bookkeeping.
// Under lock, invalidate before set ensures caches won't return stale values.
mInjector.invalidateIsInteractiveCaches();
mWakefulnessRaw = wakefulness;
@@ -1850,6 +1933,37 @@
mNotifier.onWakefulnessChangeStarted(wakefulness, reason, eventTime);
}
mAttentionDetector.onWakefulnessChangeStarted(wakefulness);
+
+ // Phase 3: Handle post-wakefulness change bookkeeping.
+ switch (wakefulness) {
+ case WAKEFULNESS_AWAKE:
+ mNotifier.onWakeUp(reason, details, uid, opPackageName, opUid);
+ userActivityNoUpdateLocked(
+ eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, uid);
+ if (sQuiescent) {
+ mDirty |= DIRTY_QUIESCENT;
+ }
+ break;
+
+ case WAKEFULNESS_DOZING:
+ // Report the number of wake locks that will be cleared by going to sleep.
+ int numWakeLocksCleared = 0;
+ final int numWakeLocks = mWakeLocks.size();
+ for (int i = 0; i < numWakeLocks; i++) {
+ final WakeLock wakeLock = mWakeLocks.get(i);
+ switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
+ case PowerManager.FULL_WAKE_LOCK:
+ case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
+ case PowerManager.SCREEN_DIM_WAKE_LOCK:
+ numWakeLocksCleared += 1;
+ break;
+ }
+ }
+ EventLogTags.writePowerSleepRequested(numWakeLocksCleared);
+ break;
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
}
@@ -1872,7 +1986,7 @@
}
private void finishWakefulnessChangeIfNeededLocked() {
- if (mWakefulnessChanging && mDisplayReady) {
+ if (mWakefulnessChanging && mDisplayGroupPowerStateMapper.areAllDisplaysReadyLocked()) {
if (getWakefulnessLocked() == WAKEFULNESS_DOZING
&& (mWakeLockSummary & WAKE_LOCK_DOZE) == 0) {
return; // wait until dream has enabled dozing
@@ -1884,13 +1998,6 @@
|| getWakefulnessLocked() == WAKEFULNESS_ASLEEP) {
logSleepTimeoutRecapturedLocked();
}
- if (getWakefulnessLocked() == WAKEFULNESS_AWAKE) {
- Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, 0);
- final int latencyMs = (int) (mClock.uptimeMillis() - mLastWakeTime);
- if (latencyMs >= SCREEN_ON_LATENCY_WARNING_MS) {
- Slog.w(TAG, "Screen on took " + latencyMs + " ms");
- }
- }
mWakefulnessChanging = false;
mNotifier.onWakefulnessChangeFinished();
}
@@ -1989,7 +2096,6 @@
if ((dirty & DIRTY_BATTERY_STATE) != 0) {
final boolean wasPowered = mIsPowered;
final int oldPlugType = mPlugType;
- final boolean oldLevelLow = mBatteryLevelLow;
mIsPowered = mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
mPlugType = mBatteryManagerInternal.getPlugType();
mBatteryLevel = mBatteryManagerInternal.getBatteryLevel();
@@ -2018,7 +2124,8 @@
final long now = mClock.uptimeMillis();
if (shouldWakeUpWhenPluggedOrUnpluggedLocked(wasPowered, oldPlugType,
dockedOnWirelessCharger)) {
- wakeUpNoUpdateLocked(now, PowerManager.WAKE_REASON_PLUGGED_IN,
+ wakeDisplayGroupNoUpdateLocked(DisplayGroup.DEFAULT, now,
+ PowerManager.WAKE_REASON_PLUGGED_IN,
"android.server.power:PLUGGED:" + mIsPowered, Process.SYSTEM_UID,
mContext.getOpPackageName(), Process.SYSTEM_UID);
}
@@ -2300,7 +2407,8 @@
nextTimeout = mLastUserActivityTimeNoChangeLights + screenOffTimeout;
if (now < nextTimeout) {
final DisplayPowerRequest displayPowerRequest =
- mDisplayPowerRequestMapper.get(Display.DEFAULT_DISPLAY);
+ mDisplayGroupPowerStateMapper.getPowerRequestLocked(
+ DisplayGroup.DEFAULT);
if (displayPowerRequest.policy == DisplayPowerRequest.POLICY_BRIGHT
|| displayPowerRequest.policy == DisplayPowerRequest.POLICY_VR) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
@@ -2555,13 +2663,23 @@
}
final long time = mClock.uptimeMillis();
if (isAttentiveTimeoutExpired(time)) {
- changed = goToSleepNoUpdateLocked(time, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT,
- PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE, Process.SYSTEM_UID);
+ // TODO (b/175764389): Support per-display timeouts.
+ for (int id : mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked()) {
+ changed = sleepDisplayGroupNoUpdateLocked(id, time,
+ PowerManager.GO_TO_SLEEP_REASON_TIMEOUT,
+ PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE, Process.SYSTEM_UID);
+ }
} else if (shouldNapAtBedTimeLocked()) {
- changed = napNoUpdateLocked(time, Process.SYSTEM_UID);
+ // TODO (b/175764389): Support per-display timeouts.
+ for (int id : mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked()) {
+ changed = dreamDisplayGroupNoUpdateLocked(id, time, Process.SYSTEM_UID);
+ }
} else {
- changed = goToSleepNoUpdateLocked(time,
- PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);
+ // TODO (b/175764389): Support per-display timeouts.
+ for (int id : mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked()) {
+ changed = sleepDisplayGroupNoUpdateLocked(id, time,
+ PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);
+ }
}
}
}
@@ -2644,7 +2762,7 @@
| DIRTY_STAY_ON
| DIRTY_PROXIMITY_POSITIVE
| DIRTY_BATTERY_STATE)) != 0 || displayBecameReady) {
- if (mDisplayReady) {
+ if (mDisplayGroupPowerStateMapper.areAllDisplaysReadyLocked()) {
scheduleSandmanLocked();
}
}
@@ -2659,6 +2777,14 @@
}
}
+ private void handleSandman() {
+ for (int id : mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked()) {
+ if (mDisplayGroupPowerStateMapper.isSandmanSupported(id)) {
+ handleSandman(id);
+ }
+ }
+ }
+
/**
* Called when the device enters or exits a dreaming or dozing state.
*
@@ -2666,16 +2792,18 @@
* the dream and we don't want to hold our lock while doing so. There is a risk that
* the device will wake or go to sleep in the meantime so we have to handle that case.
*/
- private void handleSandman() { // runs on handler thread
+ private void handleSandman(int groupId) { // runs on handler thread
// Handle preconditions.
final boolean startDreaming;
final int wakefulness;
synchronized (mLock) {
mSandmanScheduled = false;
+ // TODO (b/175764708): Support per-display doze.
wakefulness = getWakefulnessLocked();
- if (mSandmanSummoned && mDisplayReady) {
- startDreaming = canDreamLocked() || canDozeLocked();
- mSandmanSummoned = false;
+ if (mDisplayGroupPowerStateMapper.isSandmanSummoned(groupId)
+ && mDisplayGroupPowerStateMapper.isReady(groupId)) {
+ startDreaming = canDreamLocked(groupId) || canDozeLocked();
+ mDisplayGroupPowerStateMapper.setSandmanSummoned(groupId, false);
} else {
startDreaming = false;
}
@@ -2714,14 +2842,15 @@
// If preconditions changed, wait for the next iteration to determine
// whether the dream should continue (or be restarted).
- if (mSandmanSummoned || getWakefulnessLocked() != wakefulness) {
+ if (mDisplayGroupPowerStateMapper.isSandmanSummoned(groupId)
+ || mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId) != wakefulness) {
return; // wait for next cycle
}
// Determine whether the dream should continue.
long now = mClock.uptimeMillis();
if (wakefulness == WAKEFULNESS_DREAMING) {
- if (isDreaming && canDreamLocked()) {
+ if (isDreaming && canDreamLocked(groupId)) {
if (mDreamsBatteryLevelDrainCutoffConfig >= 0
&& mBatteryLevel < mBatteryLevelWhenDreamStarted
- mDreamsBatteryLevelDrainCutoffConfig
@@ -2741,16 +2870,13 @@
// Dream has ended or will be stopped. Update the power state.
if (isItBedTimeYetLocked()) {
- int flags = 0;
- if (isAttentiveTimeoutExpired(now)) {
- flags |= PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE;
- }
- goToSleepNoUpdateLocked(now, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, flags,
- Process.SYSTEM_UID);
+ final int flags = isAttentiveTimeoutExpired(now)
+ ? PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE : 0;
+ sleepDisplayGroupNoUpdateLocked(groupId, now,
+ PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, flags, Process.SYSTEM_UID);
updatePowerStateLocked();
} else {
- wakeUpNoUpdateLocked(now,
- PowerManager.WAKE_REASON_UNKNOWN,
+ wakeDisplayGroupNoUpdateLocked(groupId, now, PowerManager.WAKE_REASON_UNKNOWN,
"android.server.power:DREAM_FINISHED", Process.SYSTEM_UID,
mContext.getOpPackageName(), Process.SYSTEM_UID);
updatePowerStateLocked();
@@ -2761,7 +2887,7 @@
}
// Doze has ended or will be stopped. Update the power state.
- reallyGoToSleepNoUpdateLocked(now, Process.SYSTEM_UID);
+ reallySleepDisplayGroupNoUpdateLocked(groupId, now, Process.SYSTEM_UID);
updatePowerStateLocked();
}
}
@@ -2773,11 +2899,11 @@
}
/**
- * Returns true if the device is allowed to dream in its current state.
+ * Returns true if the {@code groupId} is allowed to dream in its current state.
*/
- private boolean canDreamLocked() {
+ private boolean canDreamLocked(int groupId) {
final DisplayPowerRequest displayPowerRequest =
- mDisplayPowerRequestMapper.get(Display.DEFAULT_DISPLAY);
+ mDisplayGroupPowerStateMapper.getPowerRequestLocked(groupId);
if (getWakefulnessLocked() != WAKEFULNESS_DREAMING
|| !mDreamsSupportedConfig
|| !mDreamsEnabledSetting
@@ -2815,91 +2941,113 @@
/**
* Updates the display power state asynchronously.
- * When the update is finished, mDisplayReady will be set to true. The display
- * controller posts a message to tell us when the actual display power state
+ * When the update is finished, the ready state of the displays will be updated. The display
+ * controllers post a message to tell us when the actual display power state
* has been updated so we come back here to double-check and finish up.
*
* This function recalculates the display power state each time.
*
- * @return True if the display became ready.
+ * @return {@code true} if all displays became ready; {@code false} otherwise
*/
private boolean updateDisplayPowerStateLocked(int dirty) {
- final boolean oldDisplayReady = mDisplayReady;
+ final boolean oldDisplayReady = mDisplayGroupPowerStateMapper.areAllDisplaysReadyLocked();
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS
| DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED
| DIRTY_SETTINGS | DIRTY_SCREEN_BRIGHTNESS_BOOST | DIRTY_VR_MODE_CHANGED |
- DIRTY_QUIESCENT)) != 0) {
+ DIRTY_QUIESCENT | DIRTY_DISPLAY_GROUP_POWER_UPDATED)) != 0) {
if ((dirty & DIRTY_QUIESCENT) != 0) {
sQuiescent = false;
}
- final DisplayPowerRequest displayPowerRequest = mDisplayPowerRequestMapper.get(
- Display.DEFAULT_DISPLAY);
- displayPowerRequest.policy = getDesiredScreenPolicyLocked();
+ for (final int groupId : mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked()) {
+ final DisplayPowerRequest displayPowerRequest =
+ mDisplayGroupPowerStateMapper.getPowerRequestLocked(groupId);
+ displayPowerRequest.policy = getDesiredScreenPolicyLocked(groupId);
- // Determine appropriate screen brightness and auto-brightness adjustments.
- final boolean autoBrightness;
- final float screenBrightnessOverride;
- if (!mBootCompleted) {
- // Keep the brightness steady during boot. This requires the
- // bootloader brightness and the default brightness to be identical.
- autoBrightness = false;
- screenBrightnessOverride = mScreenBrightnessDefault;
- } else if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) {
- autoBrightness = false;
- screenBrightnessOverride = mScreenBrightnessOverrideFromWindowManager;
- } else {
- autoBrightness = (mScreenBrightnessModeSetting ==
- Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
- screenBrightnessOverride = PowerManager.BRIGHTNESS_INVALID_FLOAT;
- }
+ // Determine appropriate screen brightness and auto-brightness adjustments.
+ final boolean autoBrightness;
+ final float screenBrightnessOverride;
+ if (!mBootCompleted) {
+ // Keep the brightness steady during boot. This requires the
+ // bootloader brightness and the default brightness to be identical.
+ autoBrightness = false;
+ screenBrightnessOverride = mScreenBrightnessDefault;
+ } else if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) {
+ autoBrightness = false;
+ screenBrightnessOverride = mScreenBrightnessOverrideFromWindowManager;
+ } else {
+ autoBrightness = (mScreenBrightnessModeSetting ==
+ Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+ screenBrightnessOverride = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+ }
- // Update display power request.
- displayPowerRequest.screenBrightnessOverride = screenBrightnessOverride;
- displayPowerRequest.useAutoBrightness = autoBrightness;
- displayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
- displayPowerRequest.boostScreenBrightness = shouldBoostScreenBrightness();
+ // Update display power request.
+ displayPowerRequest.screenBrightnessOverride = screenBrightnessOverride;
+ displayPowerRequest.useAutoBrightness = autoBrightness;
+ displayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
+ displayPowerRequest.boostScreenBrightness = shouldBoostScreenBrightness();
- updatePowerRequestFromBatterySaverPolicy(displayPowerRequest);
+ updatePowerRequestFromBatterySaverPolicy(displayPowerRequest);
- if (displayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) {
- displayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager;
- if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0
- && !mDrawWakeLockOverrideFromSidekick) {
- if (displayPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND) {
- displayPowerRequest.dozeScreenState = Display.STATE_DOZE;
+ if (displayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) {
+ displayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager;
+ if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0
+ && !mDrawWakeLockOverrideFromSidekick) {
+ if (displayPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND) {
+ displayPowerRequest.dozeScreenState = Display.STATE_DOZE;
+ }
+ if (displayPowerRequest.dozeScreenState == Display.STATE_ON_SUSPEND) {
+ displayPowerRequest.dozeScreenState = Display.STATE_ON;
+ }
}
- if (displayPowerRequest.dozeScreenState == Display.STATE_ON_SUSPEND) {
- displayPowerRequest.dozeScreenState = Display.STATE_ON;
+ displayPowerRequest.dozeScreenBrightness =
+ mDozeScreenBrightnessOverrideFromDreamManagerFloat;
+ } else {
+ displayPowerRequest.dozeScreenState = Display.STATE_UNKNOWN;
+ displayPowerRequest.dozeScreenBrightness =
+ PowerManager.BRIGHTNESS_INVALID_FLOAT;
+ }
+
+ final boolean ready = mDisplayManagerInternal.requestPowerState(groupId,
+ displayPowerRequest, mRequestWaitForNegativeProximity);
+
+ if (DEBUG_SPEW) {
+ Slog.d(TAG, "updateDisplayPowerStateLocked: displayReady=" + ready
+ + ", groupId=" + groupId
+ + ", policy=" + displayPowerRequest.policy
+ + ", mWakefulness="
+ + mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId)
+ + ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary)
+ + ", mUserActivitySummary=0x" + Integer.toHexString(
+ mUserActivitySummary)
+ + ", mBootCompleted=" + mBootCompleted
+ + ", screenBrightnessOverride="
+ + displayPowerRequest.screenBrightnessOverride
+ + ", useAutoBrightness=" + displayPowerRequest.useAutoBrightness
+ + ", mScreenBrightnessBoostInProgress="
+ + mScreenBrightnessBoostInProgress
+ + ", mIsVrModeEnabled= " + mIsVrModeEnabled
+ + ", sQuiescent=" + sQuiescent);
+ }
+
+ final boolean displayReadyStateChanged =
+ mDisplayGroupPowerStateMapper.setDisplayGroupReadyLocked(groupId, ready);
+ if (ready && displayReadyStateChanged
+ && mDisplayGroupPowerStateMapper.getWakefulnessLocked(
+ groupId) == WAKEFULNESS_AWAKE) {
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, groupId);
+ final int latencyMs = (int) (mClock.uptimeMillis()
+ - mDisplayGroupPowerStateMapper.getLastPowerOnTimeLocked(groupId));
+ if (latencyMs >= SCREEN_ON_LATENCY_WARNING_MS) {
+ Slog.w(TAG, "Screen on took " + latencyMs + " ms");
}
}
- displayPowerRequest.dozeScreenBrightness =
- mDozeScreenBrightnessOverrideFromDreamManagerFloat;
- } else {
- displayPowerRequest.dozeScreenState = Display.STATE_UNKNOWN;
- displayPowerRequest.dozeScreenBrightness =
- PowerManager.BRIGHTNESS_INVALID_FLOAT;
}
- mDisplayReady = mDisplayManagerInternal.requestPowerState(displayPowerRequest,
- mRequestWaitForNegativeProximity);
mRequestWaitForNegativeProximity = false;
- if (DEBUG_SPEW) {
- Slog.d(TAG, "updateDisplayPowerStateLocked: mDisplayReady=" + mDisplayReady
- + ", policy=" + displayPowerRequest.policy
- + ", mWakefulness=" + getWakefulnessLocked()
- + ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary)
- + ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary)
- + ", mBootCompleted=" + mBootCompleted
- + ", screenBrightnessOverride=" + screenBrightnessOverride
- + ", useAutoBrightness=" + autoBrightness
- + ", mScreenBrightnessBoostInProgress=" + mScreenBrightnessBoostInProgress
- + ", mIsVrModeEnabled= " + mIsVrModeEnabled
- + ", sQuiescent=" + sQuiescent);
- }
}
- return mDisplayReady && !oldDisplayReady;
+ return mDisplayGroupPowerStateMapper.areAllDisplaysReadyLocked() && !oldDisplayReady;
}
private void updateScreenBrightnessBoostLocked(int dirty) {
@@ -2933,12 +3081,11 @@
}
@VisibleForTesting
- int getDesiredScreenPolicyLocked() {
- if (getWakefulnessLocked() == WAKEFULNESS_ASLEEP || sQuiescent) {
+ int getDesiredScreenPolicyLocked(int groupId) {
+ final int wakefulness = mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId);
+ if (wakefulness == WAKEFULNESS_ASLEEP || sQuiescent) {
return DisplayPowerRequest.POLICY_OFF;
- }
-
- if (getWakefulnessLocked() == WAKEFULNESS_DOZING) {
+ } else if (wakefulness == WAKEFULNESS_DOZING) {
if ((mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
return DisplayPowerRequest.POLICY_DOZE;
}
@@ -2968,7 +3115,6 @@
private final DisplayManagerInternal.DisplayPowerCallbacks mDisplayPowerCallbacks =
new DisplayManagerInternal.DisplayPowerCallbacks() {
- private int mDisplayState = Display.STATE_UNKNOWN;
@Override
public void onStateChanged() {
@@ -2999,29 +3145,25 @@
}
@Override
- public void onDisplayStateChange(int state) {
+ public void onDisplayStateChange(boolean allInactive, boolean allOff) {
// This method is only needed to support legacy display blanking behavior
// where the display's power state is coupled to suspend or to the power HAL.
// The order of operations matters here.
synchronized (mLock) {
- if (mDisplayState != state) {
- mDisplayState = state;
- setPowerModeInternal(MODE_DISPLAY_INACTIVE,
- !Display.isActiveState(state));
- if (state == Display.STATE_OFF) {
- if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
- setHalInteractiveModeLocked(false);
- }
- if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
- setHalAutoSuspendModeLocked(true);
- }
- } else {
- if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
- setHalAutoSuspendModeLocked(false);
- }
- if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
- setHalInteractiveModeLocked(true);
- }
+ setPowerModeInternal(MODE_DISPLAY_INACTIVE, allInactive);
+ if (allOff) {
+ if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
+ setHalInteractiveModeLocked(false);
+ }
+ if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+ setHalAutoSuspendModeLocked(true);
+ }
+ } else {
+ if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+ setHalAutoSuspendModeLocked(false);
+ }
+ if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
+ setHalInteractiveModeLocked(true);
}
}
}
@@ -3036,13 +3178,6 @@
public void releaseSuspendBlocker() {
mDisplaySuspendBlocker.release();
}
-
- @Override
- public String toString() {
- synchronized (this) {
- return "state=" + Display.stateToString(mDisplayState);
- }
- }
};
private boolean shouldUseProximitySensorLocked() {
@@ -3058,9 +3193,13 @@
final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0);
final boolean needDisplaySuspendBlocker = needDisplaySuspendBlockerLocked();
final boolean autoSuspend = !needDisplaySuspendBlocker;
- final DisplayPowerRequest displayPowerRequest = mDisplayPowerRequestMapper.get(
- Display.DEFAULT_DISPLAY);
- final boolean interactive = displayPowerRequest.isBrightOrDim();
+ final DisplayPowerRequest displayPowerRequest =
+ mDisplayGroupPowerStateMapper.getPowerRequestLocked(DisplayGroup.DEFAULT);
+ final int[] groupIds = mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked();
+ boolean interactive = false;
+ for (int id : groupIds) {
+ interactive |= mDisplayGroupPowerStateMapper.getPowerRequestLocked(id).isBrightOrDim();
+ }
// Disable auto-suspend if needed.
// FIXME We should consider just leaving auto-suspend enabled forever since
@@ -3090,7 +3229,7 @@
// until the display is actually ready so that all transitions have
// completed. This is probably a good sign that things have gotten
// too tangled over here...
- if (interactive || mDisplayReady) {
+ if (interactive || mDisplayGroupPowerStateMapper.areAllDisplaysReadyLocked()) {
setHalInteractiveModeLocked(interactive);
}
}
@@ -3116,29 +3255,10 @@
* We do so if the screen is on or is in transition between states.
*/
private boolean needDisplaySuspendBlockerLocked() {
- if (!mDisplayReady) {
+ if (!mDisplayGroupPowerStateMapper.areAllDisplaysReadyLocked()) {
return true;
}
- final DisplayPowerRequest displayPowerRequest = mDisplayPowerRequestMapper.get(
- Display.DEFAULT_DISPLAY);
- if (displayPowerRequest.isBrightOrDim()) {
- // If we asked for the screen to be on but it is off due to the proximity
- // sensor then we may suspend but only if the configuration allows it.
- // On some hardware it may not be safe to suspend because the proximity
- // sensor may not be correctly configured as a wake-up source.
- if (!displayPowerRequest.useProximitySensor || !mProximityPositive
- || !mSuspendWhenScreenOffDueToProximityConfig) {
- return true;
- }
- }
- if (displayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE
- && displayPowerRequest.dozeScreenState == Display.STATE_ON) {
- // Although we are in DOZE and would normally allow the device to suspend,
- // the doze service has explicitly requested the display to remain in the ON
- // state which means we should hold the display suspend blocker.
- return true;
- }
if (mScreenBrightnessBoostInProgress) {
return true;
}
@@ -3152,6 +3272,30 @@
return true;
}
+ final int[] groupIds = mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked();
+ for (int id : groupIds) {
+ final DisplayPowerRequest displayPowerRequest =
+ mDisplayGroupPowerStateMapper.getPowerRequestLocked(id);
+ if (displayPowerRequest.isBrightOrDim()) {
+ // If we asked for the screen to be on but it is off due to the proximity
+ // sensor then we may suspend but only if the configuration allows it.
+ // On some hardware it may not be safe to suspend because the proximity
+ // sensor may not be correctly configured as a wake-up source.
+ if (!displayPowerRequest.useProximitySensor || !mProximityPositive
+ || !mSuspendWhenScreenOffDueToProximityConfig) {
+ return true;
+ }
+ }
+
+ if (displayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE
+ && displayPowerRequest.dozeScreenState == Display.STATE_ON) {
+ // Although we are in DOZE and would normally allow the device to suspend,
+ // the doze service has explicitly requested the display to remain in the ON
+ // state which means we should hold the display suspend blocker.
+ return true;
+ }
+ }
+
// Let the system suspend if the screen is off or dozing.
return false;
}
@@ -3685,9 +3829,15 @@
synchronized (mLock) {
mForceSuspendActive = true;
// Place the system in an non-interactive state
- goToSleepInternal(mClock.uptimeMillis(),
- PowerManager.GO_TO_SLEEP_REASON_FORCE_SUSPEND,
- PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE, uid);
+ boolean updatePowerState = false;
+ for (int id : mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked()) {
+ updatePowerState |= sleepDisplayGroupNoUpdateLocked(id, mClock.uptimeMillis(),
+ PowerManager.GO_TO_SLEEP_REASON_FORCE_SUSPEND,
+ PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE, uid);
+ }
+ if (updatePowerState) {
+ updatePowerStateLocked();
+ }
// Disable all the partial wake locks as well
updateWakeLockDisabledStatesLocked();
@@ -3827,7 +3977,6 @@
pw.println(" mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary));
pw.println(" mRequestWaitForNegativeProximity=" + mRequestWaitForNegativeProximity);
pw.println(" mSandmanScheduled=" + mSandmanScheduled);
- pw.println(" mSandmanSummoned=" + mSandmanSummoned);
pw.println(" mBatteryLevelLow=" + mBatteryLevelLow);
pw.println(" mLightDeviceIdleMode=" + mLightDeviceIdleMode);
pw.println(" mDeviceIdleMode=" + mDeviceIdleMode);
@@ -3845,7 +3994,6 @@
+ TimeUtils.formatUptime(mLastScreenBrightnessBoostTime));
pw.println(" mScreenBrightnessBoostInProgress="
+ mScreenBrightnessBoostInProgress);
- pw.println(" mDisplayReady=" + mDisplayReady);
pw.println(" mHoldingWakeLockSuspendBlocker=" + mHoldingWakeLockSuspendBlocker);
pw.println(" mHoldingDisplaySuspendBlocker=" + mHoldingDisplaySuspendBlocker);
@@ -4080,7 +4228,6 @@
PowerManagerServiceDumpProto.IS_REQUEST_WAIT_FOR_NEGATIVE_PROXIMITY,
mRequestWaitForNegativeProximity);
proto.write(PowerManagerServiceDumpProto.IS_SANDMAN_SCHEDULED, mSandmanScheduled);
- proto.write(PowerManagerServiceDumpProto.IS_SANDMAN_SUMMONED, mSandmanSummoned);
proto.write(PowerManagerServiceDumpProto.IS_BATTERY_LEVEL_LOW, mBatteryLevelLow);
proto.write(PowerManagerServiceDumpProto.IS_LIGHT_DEVICE_IDLE_MODE, mLightDeviceIdleMode);
proto.write(PowerManagerServiceDumpProto.IS_DEVICE_IDLE_MODE, mDeviceIdleMode);
@@ -4107,7 +4254,6 @@
proto.write(
PowerManagerServiceDumpProto.IS_SCREEN_BRIGHTNESS_BOOST_IN_PROGRESS,
mScreenBrightnessBoostInProgress);
- proto.write(PowerManagerServiceDumpProto.IS_DISPLAY_READY, mDisplayReady);
proto.write(
PowerManagerServiceDumpProto.IS_HOLDING_WAKE_LOCK_SUSPEND_BLOCKER,
mHoldingWakeLockSuspendBlocker);
@@ -4921,7 +5067,8 @@
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
- wakeUpInternal(eventTime, reason, details, uid, opPackageName, uid);
+ wakeDisplayGroup(DisplayGroup.DEFAULT, eventTime, reason, details, uid,
+ opPackageName, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -4939,7 +5086,7 @@
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
- goToSleepInternal(eventTime, reason, flags, uid);
+ sleepDisplayGroup(DisplayGroup.DEFAULT, eventTime, reason, flags, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -4957,7 +5104,7 @@
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
- napInternal(eventTime, uid);
+ dreamDisplayGroup(DisplayGroup.DEFAULT, eventTime, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -5590,7 +5737,7 @@
// also tells us that we're not already ignoring the proximity sensor.
final DisplayPowerRequest displayPowerRequest =
- mDisplayPowerRequestMapper.get(Display.DEFAULT_DISPLAY);
+ mDisplayGroupPowerStateMapper.getPowerRequestLocked(DisplayGroup.DEFAULT);
if (displayPowerRequest.useProximitySensor && mProximityPositive) {
mDisplayManagerInternal.ignoreProximitySensorUntilChanged();
return true;
diff --git a/services/core/java/com/android/server/power/PreRebootLogger.java b/services/core/java/com/android/server/power/PreRebootLogger.java
index c9e81ed..2e4b054 100644
--- a/services/core/java/com/android/server/power/PreRebootLogger.java
+++ b/services/core/java/com/android/server/power/PreRebootLogger.java
@@ -19,6 +19,7 @@
import android.annotation.DurationMillisLong;
import android.annotation.NonNull;
import android.content.Context;
+import android.os.Binder;
import android.os.Environment;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
@@ -146,6 +147,7 @@
return;
}
+ final long token = Binder.clearCallingIdentity();
try {
final File dumpFile = new File(dumpDir, serviceName);
final ParcelFileDescriptor fd = ParcelFileDescriptor.open(dumpFile,
@@ -154,6 +156,8 @@
binder.dump(fd.getFileDescriptor(), ArrayUtils.emptyArray(String.class));
} catch (FileNotFoundException | RemoteException e) {
Slog.e(TAG, String.format("Failed to dump %s service before reboot", serviceName), e);
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
}
}
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
index 5c01e43..fd2d8e1 100644
--- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.IntentSender;
import android.content.pm.PackageManager;
+import android.hardware.boot.V1_0.IBootControl;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.os.Binder;
@@ -73,6 +74,8 @@
static final String INIT_SERVICE_SETUP_BCB = "init.svc.setup-bcb";
@VisibleForTesting
static final String INIT_SERVICE_CLEAR_BCB = "init.svc.clear-bcb";
+ @VisibleForTesting
+ static final String AB_UPDATE = "ro.build.ab_update";
private static final Object sRequestLock = new Object();
@@ -177,6 +180,25 @@
return socket;
}
+ /**
+ * Throws remote exception if there's an error getting the boot control HAL.
+ * Returns null if the boot control HAL's version is older than V1_2.
+ */
+ public android.hardware.boot.V1_2.IBootControl getBootControl() throws RemoteException {
+ IBootControl bootControlV10 = IBootControl.getService(true);
+ if (bootControlV10 == null) {
+ throw new RemoteException("Failed to get boot control HAL V1_0.");
+ }
+
+ android.hardware.boot.V1_2.IBootControl bootControlV12 =
+ android.hardware.boot.V1_2.IBootControl.castFrom(bootControlV10);
+ if (bootControlV12 == null) {
+ Slog.w(TAG, "Device doesn't implement boot control HAL V1_2.");
+ return null;
+ }
+ return bootControlV12;
+ }
+
public void threadSleep(long millis) throws InterruptedException {
Thread.sleep(millis);
}
@@ -476,6 +498,56 @@
return needClear ? ROR_REQUESTED_NEED_CLEAR : ROR_REQUESTED_SKIP_CLEAR;
}
+ private boolean isAbDevice() {
+ return "true".equalsIgnoreCase(mInjector.systemPropertiesGet(AB_UPDATE));
+ }
+
+ private boolean verifySlotForNextBoot(boolean slotSwitch) {
+ if (!isAbDevice()) {
+ Slog.w(TAG, "Device isn't a/b, skipping slot verification.");
+ return true;
+ }
+
+ android.hardware.boot.V1_2.IBootControl bootControl;
+ try {
+ bootControl = mInjector.getBootControl();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to get the boot control HAL " + e);
+ return false;
+ }
+
+ // TODO(xunchang) enforce boot control V1_2 HAL on devices using multi client RoR
+ if (bootControl == null) {
+ Slog.w(TAG, "Cannot get the boot control HAL, skipping slot verification.");
+ return true;
+ }
+
+ int current_slot;
+ int next_active_slot;
+ try {
+ current_slot = bootControl.getCurrentSlot();
+ if (current_slot != 0 && current_slot != 1) {
+ throw new IllegalStateException("Current boot slot should be 0 or 1, got "
+ + current_slot);
+ }
+ next_active_slot = bootControl.getActiveBootSlot();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to query the active slots", e);
+ return false;
+ }
+
+ int expected_active_slot = current_slot;
+ if (slotSwitch) {
+ expected_active_slot = current_slot == 0 ? 1 : 0;
+ }
+ if (next_active_slot != expected_active_slot) {
+ Slog.w(TAG, "The next active boot slot doesn't match the expected value, "
+ + "expected " + expected_active_slot + ", got " + next_active_slot);
+ return false;
+ }
+ return true;
+ }
+
private boolean rebootWithLskfImpl(String packageName, String reason, boolean slotSwitch) {
if (packageName == null) {
Slog.w(TAG, "Missing packageName when rebooting with lskf.");
@@ -485,7 +557,10 @@
return false;
}
- // TODO(xunchang) check the slot to boot into, and fail the reboot upon slot mismatch.
+ if (!verifySlotForNextBoot(slotSwitch)) {
+ return false;
+ }
+
// TODO(xunchang) write the vbmeta digest along with the escrowKey before reboot.
if (!mInjector.getLockSettingsService().armRebootEscrow()) {
Slog.w(TAG, "Failure to escrow key for reboot");
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemShellCommand.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemShellCommand.java
index f20d80d..ae71c1a 100644
--- a/services/core/java/com/android/server/recoverysystem/RecoverySystemShellCommand.java
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemShellCommand.java
@@ -76,7 +76,7 @@
private int rebootAndApply() throws RemoteException {
String packageName = getNextArgRequired();
String rebootReason = getNextArgRequired();
- boolean success = mService.rebootWithLskf(packageName, rebootReason, true);
+ boolean success = mService.rebootWithLskf(packageName, rebootReason, false);
PrintWriter pw = getOutPrintWriter();
// Keep the old message for cts test.
pw.printf("%s Reboot and apply status: %s\n", packageName,
diff --git a/services/core/java/com/android/server/security/FileIntegrityService.java b/services/core/java/com/android/server/security/FileIntegrityService.java
index 225bd82..6ec71b7 100644
--- a/services/core/java/com/android/server/security/FileIntegrityService.java
+++ b/services/core/java/com/android/server/security/FileIntegrityService.java
@@ -60,8 +60,7 @@
private final IBinder mService = new IFileIntegrityService.Stub() {
@Override
public boolean isApkVeritySupported() {
- return Build.VERSION.FIRST_SDK_INT >= Build.VERSION_CODES.R
- || SystemProperties.getInt("ro.apk_verity.mode", 0) == 2;
+ return FileIntegrityService.isApkVeritySupported();
}
@Override
@@ -111,6 +110,11 @@
}
};
+ public static boolean isApkVeritySupported() {
+ return Build.VERSION.FIRST_SDK_INT >= Build.VERSION_CODES.R
+ || SystemProperties.getInt("ro.apk_verity.mode", 0) == 2;
+ }
+
public FileIntegrityService(final Context context) {
super(context);
try {
diff --git a/services/core/java/com/android/server/security/OWNERS b/services/core/java/com/android/server/security/OWNERS
new file mode 100644
index 0000000..91b240b
--- /dev/null
+++ b/services/core/java/com/android/server/security/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 36824
+
+per-file FileIntegrityService.java = victorhsieh@google.com
+per-file VerityUtils.java = victorhsieh@google.com
diff --git a/services/core/java/com/android/server/security/VerityUtils.java b/services/core/java/com/android/server/security/VerityUtils.java
index f204aa2..09ee001 100644
--- a/services/core/java/com/android/server/security/VerityUtils.java
+++ b/services/core/java/com/android/server/security/VerityUtils.java
@@ -73,7 +73,12 @@
if (Files.size(Paths.get(signaturePath)) > MAX_SIGNATURE_FILE_SIZE_BYTES) {
throw new SecurityException("Signature file is unexpectedly large: " + signaturePath);
}
- byte[] pkcs7Signature = Files.readAllBytes(Paths.get(signaturePath));
+ setUpFsverity(filePath, Files.readAllBytes(Paths.get(signaturePath)));
+ }
+
+ /** Enables fs-verity for the file with a PKCS#7 detached signature bytes. */
+ public static void setUpFsverity(@NonNull String filePath, @NonNull byte[] pkcs7Signature)
+ throws IOException {
// This will fail if the public key is not already in .fs-verity kernel keyring.
int errno = enableFsverityNative(filePath, pkcs7Signature);
if (errno != 0) {
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Enforcer.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Enforcer.java
index eced894..90ac69a 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Enforcer.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Enforcer.java
@@ -42,7 +42,7 @@
static final String TAG = "SoundTriggerHw2Enforcer";
final ISoundTriggerHw2 mUnderlying;
- Map<Integer, Boolean> mModelStates = new HashMap<>();
+ final Map<Integer, Boolean> mModelStates = new HashMap<>();
public SoundTriggerHw2Enforcer(
ISoundTriggerHw2 underlying) {
@@ -62,12 +62,12 @@
public int loadSoundModel(ISoundTriggerHw.SoundModel soundModel, Callback callback,
int cookie) {
try {
- int handle = mUnderlying.loadSoundModel(soundModel, new CallbackEnforcer(callback),
- cookie);
synchronized (mModelStates) {
+ int handle = mUnderlying.loadSoundModel(soundModel, new CallbackEnforcer(callback),
+ cookie);
mModelStates.put(handle, false);
+ return handle;
}
- return handle;
} catch (RuntimeException e) {
throw handleException(e);
}
@@ -77,13 +77,13 @@
public int loadPhraseSoundModel(ISoundTriggerHw.PhraseSoundModel soundModel, Callback callback,
int cookie) {
try {
- int handle = mUnderlying.loadPhraseSoundModel(soundModel,
- new CallbackEnforcer(callback),
- cookie);
synchronized (mModelStates) {
+ int handle = mUnderlying.loadPhraseSoundModel(soundModel,
+ new CallbackEnforcer(callback),
+ cookie);
mModelStates.put(handle, false);
+ return handle;
}
- return handle;
} catch (RuntimeException e) {
throw handleException(e);
}
@@ -92,8 +92,8 @@
@Override
public void unloadSoundModel(int modelHandle) {
try {
- mUnderlying.unloadSoundModel(modelHandle);
synchronized (mModelStates) {
+ mUnderlying.unloadSoundModel(modelHandle);
mModelStates.remove(modelHandle);
}
} catch (RuntimeException e) {
@@ -104,8 +104,8 @@
@Override
public void stopRecognition(int modelHandle) {
try {
- mUnderlying.stopRecognition(modelHandle);
synchronized (mModelStates) {
+ mUnderlying.stopRecognition(modelHandle);
mModelStates.replace(modelHandle, false);
}
} catch (RuntimeException e) {
@@ -116,8 +116,8 @@
@Override
public void stopAllRecognitions() {
try {
- mUnderlying.stopAllRecognitions();
synchronized (mModelStates) {
+ mUnderlying.stopAllRecognitions();
for (Map.Entry<Integer, Boolean> entry : mModelStates.entrySet()) {
entry.setValue(false);
}
@@ -131,9 +131,9 @@
public void startRecognition(int modelHandle, RecognitionConfig config, Callback callback,
int cookie) {
try {
- mUnderlying.startRecognition(modelHandle, config, new CallbackEnforcer(callback),
- cookie);
synchronized (mModelStates) {
+ mUnderlying.startRecognition(modelHandle, config, new CallbackEnforcer(callback),
+ cookie);
mModelStates.replace(modelHandle, true);
}
} catch (RuntimeException e) {
diff --git a/services/core/java/com/android/server/textservices/OWNERS b/services/core/java/com/android/server/textservices/OWNERS
new file mode 100644
index 0000000..9fa9b29
--- /dev/null
+++ b/services/core/java/com/android/server/textservices/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 816455
+
+include /services/core/java/com/android/server/inputmethod/OWNERS
diff --git a/services/core/java/com/android/server/textservices/TextServicesManagerService.java b/services/core/java/com/android/server/textservices/TextServicesManagerService.java
index f39067b..cd2b8943 100644
--- a/services/core/java/com/android/server/textservices/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/textservices/TextServicesManagerService.java
@@ -45,6 +45,7 @@
import android.util.SparseArray;
import android.view.textservice.SpellCheckerInfo;
import android.view.textservice.SpellCheckerSubtype;
+import android.view.textservice.SuggestionsInfo;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
@@ -58,7 +59,6 @@
import com.android.internal.util.DumpUtils;
import com.android.server.LocalServices;
import com.android.server.SystemService;
-import com.android.server.SystemService.TargetUser;
import org.xmlpull.v1.XmlPullParserException;
@@ -567,7 +567,7 @@
@Override
public void getSpellCheckerService(@UserIdInt int userId, String sciId, String locale,
ITextServicesSessionListener tsListener, ISpellCheckerSessionListener scListener,
- Bundle bundle) {
+ Bundle bundle, @SuggestionsInfo.ResultAttrs int supportedAttributes) {
verifyUser(userId);
if (TextUtils.isEmpty(sciId) || tsListener == null || scListener == null) {
Slog.e(TAG, "getSpellCheckerService: Invalid input.");
@@ -603,7 +603,8 @@
// Start getISpellCheckerSession async IPC, or just queue the request until the spell
// checker service is bound.
bindGroup.getISpellCheckerSessionOrQueueLocked(
- new SessionRequest(uid, locale, tsListener, scListener, bundle));
+ new SessionRequest(uid, locale, tsListener, scListener, bundle,
+ supportedAttributes));
}
}
@@ -774,15 +775,18 @@
public final ISpellCheckerSessionListener mScListener;
@Nullable
public final Bundle mBundle;
+ public final int mSupportedAttributes;
SessionRequest(int uid, @Nullable String locale,
@NonNull ITextServicesSessionListener tsListener,
- @NonNull ISpellCheckerSessionListener scListener, @Nullable Bundle bundle) {
+ @NonNull ISpellCheckerSessionListener scListener, @Nullable Bundle bundle,
+ @SuggestionsInfo.ResultAttrs int supportedAttributes) {
mUid = uid;
mLocale = locale;
mTsListener = tsListener;
mScListener = scListener;
mBundle = bundle;
+ mSupportedAttributes = supportedAttributes;
}
}
@@ -825,6 +829,7 @@
final SessionRequest request = mPendingSessionRequests.get(i);
mSpellChecker.getISpellCheckerSession(
request.mLocale, request.mScListener, request.mBundle,
+ request.mSupportedAttributes,
new ISpellCheckerServiceCallbackBinder(this, request));
mOnGoingSessionRequests.add(request);
}
@@ -913,6 +918,7 @@
try {
mSpellChecker.getISpellCheckerSession(
request.mLocale, request.mScListener, request.mBundle,
+ request.mSupportedAttributes,
new ISpellCheckerServiceCallbackBinder(this, request));
mOnGoingSessionRequests.add(request);
} catch(RemoteException e) {
diff --git a/services/core/java/com/android/server/timedetector/GnssTimeUpdateService.java b/services/core/java/com/android/server/timedetector/GnssTimeUpdateService.java
new file mode 100644
index 0000000..fb75ae1
--- /dev/null
+++ b/services/core/java/com/android/server/timedetector/GnssTimeUpdateService.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timedetector;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AlarmManager;
+import android.app.timedetector.GnssTimeSuggestion;
+import android.app.timedetector.TimeDetector;
+import android.content.Context;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.location.LocationManagerInternal;
+import android.location.LocationRequest;
+import android.location.LocationTime;
+import android.os.Binder;
+import android.os.SystemClock;
+import android.os.TimestampedValue;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.DumpUtils;
+import com.android.server.FgThread;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.time.Duration;
+
+/**
+ * Monitors the GNSS time.
+ *
+ * <p>When available, the time is always suggested to the {@link
+ * com.android.server.timedetector.TimeDetectorService} where it may be used to set the device
+ * system clock, depending on user settings and what other signals are available.
+ */
+public final class GnssTimeUpdateService extends Binder {
+ private static final String TAG = "GnssTimeUpdateService";
+ private static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
+
+ /**
+ * Handles the lifecycle events for the GnssTimeUpdateService.
+ */
+ public static class Lifecycle extends SystemService {
+ private GnssTimeUpdateService mService;
+
+ public Lifecycle(@NonNull Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ mService = new GnssTimeUpdateService(getContext());
+ publishBinderService("gnss_time_update_service", mService);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ // Need to wait for some location providers to be enabled. If done at
+ // PHASE_SYSTEM_SERVICES_READY, error where "gps" provider does not exist could occur.
+ if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+ // Initiate location updates. On boot, GNSS might not be available right away.
+ // Instead of polling GNSS time periodically, passive location updates are enabled.
+ // Once an update is received, the gnss time will be queried and suggested to
+ // TimeDetectorService.
+ mService.requestGnssTimeUpdates();
+ }
+ }
+ }
+
+ private static final Duration GNSS_TIME_UPDATE_ALARM_INTERVAL = Duration.ofHours(4);
+ private static final String ATTRIBUTION_TAG = "GnssTimeUpdateService";
+
+ private final Context mContext;
+ private final TimeDetector mTimeDetector;
+ private final AlarmManager mAlarmManager;
+ private final LocationManager mLocationManager;
+ private final LocationManagerInternal mLocationManagerInternal;
+
+ @Nullable private AlarmManager.OnAlarmListener mAlarmListener;
+ @Nullable private LocationListener mLocationListener;
+ @Nullable private TimestampedValue<Long> mLastSuggestedGnssTime;
+
+ @VisibleForTesting
+ GnssTimeUpdateService(@NonNull Context context) {
+ mContext = context.createAttributionContext(ATTRIBUTION_TAG);
+ mTimeDetector = mContext.getSystemService(TimeDetector.class);
+ mLocationManager = mContext.getSystemService(LocationManager.class);
+ mAlarmManager = mContext.getSystemService(AlarmManager.class);
+ mLocationManagerInternal = LocalServices.getService(LocationManagerInternal.class);
+ }
+
+ /**
+ * Request passive location updates. Such a request will not trigger any active locations or
+ * power usage itself.
+ */
+ @VisibleForTesting
+ void requestGnssTimeUpdates() {
+ if (D) {
+ Log.d(TAG, "requestGnssTimeUpdates()");
+ }
+
+ // Location Listener triggers onLocationChanged() when GNSS data is available, so
+ // that the getGnssTimeMillis() function doesn't need to be continuously polled.
+ mLocationListener = new LocationListener() {
+ @Override
+ public void onLocationChanged(Location location) {
+ if (D) {
+ Log.d(TAG, "onLocationChanged()");
+ }
+
+ // getGnssTimeMillis() can return null when the Master Location Switch for the
+ // foreground user is disabled.
+ LocationTime locationTime = mLocationManagerInternal.getGnssTimeMillis();
+ if (locationTime != null) {
+ suggestGnssTime(locationTime);
+ } else {
+ if (D) {
+ Log.d(TAG, "getGnssTimeMillis() returned null");
+ }
+ }
+
+ mLocationManager.removeUpdates(mLocationListener);
+ mLocationListener = null;
+
+ mAlarmListener = new AlarmManager.OnAlarmListener() {
+ @Override
+ public void onAlarm() {
+ if (D) {
+ Log.d(TAG, "onAlarm()");
+ }
+ mAlarmListener = null;
+ requestGnssTimeUpdates();
+ }
+ };
+
+ // Set next alarm to re-enable location updates.
+ long next = SystemClock.elapsedRealtime()
+ + GNSS_TIME_UPDATE_ALARM_INTERVAL.toMillis();
+ mAlarmManager.set(
+ AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ next,
+ TAG,
+ mAlarmListener,
+ FgThread.getHandler());
+ }
+ };
+
+ mLocationManager.requestLocationUpdates(
+ LocationManager.GPS_PROVIDER,
+ new LocationRequest.Builder(LocationRequest.PASSIVE_INTERVAL)
+ .setMinUpdateIntervalMillis(0)
+ .build(),
+ FgThread.getExecutor(),
+ mLocationListener);
+ }
+
+ /**
+ * Convert LocationTime to TimestampedValue. Then suggest TimestampedValue to Time Detector.
+ */
+ private void suggestGnssTime(LocationTime locationTime) {
+ if (D) {
+ Log.d(TAG, "suggestGnssTime()");
+ }
+ long gnssTime = locationTime.getTime();
+ long elapsedRealtimeMs = locationTime.getElapsedRealtimeNanos() / 1_000_000L;
+
+ TimestampedValue<Long> timeSignal = new TimestampedValue<>(
+ elapsedRealtimeMs, gnssTime);
+ mLastSuggestedGnssTime = timeSignal;
+
+ GnssTimeSuggestion timeSuggestion = new GnssTimeSuggestion(timeSignal);
+ mTimeDetector.suggestGnssTime(timeSuggestion);
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+ pw.println("mLastSuggestedGnssTime: " + mLastSuggestedGnssTime);
+ pw.print("state: ");
+ if (mLocationListener != null) {
+ pw.println("time updates enabled");
+ } else {
+ pw.println("alarm enabled");
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 0e8fd8f..da3e48a 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -55,6 +55,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.security.Authorization;
import android.security.KeyStore;
import android.service.trust.TrustAgentService;
import android.text.TextUtils;
@@ -188,6 +189,8 @@
private boolean mTrustAgentsCanRun = false;
private int mCurrentUser = UserHandle.USER_SYSTEM;
+ private Authorization mAuthorizationService;
+
public TrustManagerService(Context context) {
super(context);
mContext = context;
@@ -197,6 +200,7 @@
mStrongAuthTracker = new StrongAuthTracker(context);
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
mSettingsObserver = new SettingsObserver(mHandler);
+ mAuthorizationService = new Authorization();
}
@Override
@@ -699,11 +703,13 @@
if (changed) {
dispatchDeviceLocked(userId, locked);
+ mAuthorizationService.onLockScreenEvent(locked, userId, null);
KeyStore.getInstance().onUserLockedStateChanged(userId, locked);
// Also update the user's profiles who have unified challenge, since they
// share the same unlocked state (see {@link #isDeviceLocked(int)})
for (int profileHandle : mUserManager.getEnabledProfileIds(userId)) {
if (mLockPatternUtils.isManagedProfileWithUnifiedChallenge(profileHandle)) {
+ mAuthorizationService.onLockScreenEvent(locked, profileHandle, null);
KeyStore.getInstance().onUserLockedStateChanged(profileHandle, locked);
}
}
@@ -1255,6 +1261,7 @@
mDeviceLockedForUser.put(userId, locked);
}
+ mAuthorizationService.onLockScreenEvent(locked, userId, null);
KeyStore.getInstance().onUserLockedStateChanged(userId, locked);
if (locked) {
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 7024e67..4e0c0c5 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -123,7 +123,7 @@
private static final String DISCONNECT_REASON_UNDERLYING_NETWORK_LOST =
"Underlying Network lost";
private static final String DISCONNECT_REASON_TEARDOWN = "teardown() called on VcnTunnel";
- private static final int TOKEN_ANY = Integer.MIN_VALUE;
+ private static final int TOKEN_ALL = Integer.MIN_VALUE;
private static final int NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS = 30;
private static final int TEARDOWN_TIMEOUT_SECONDS = 5;
@@ -139,7 +139,7 @@
*
* <p>In the Connected state, this MAY indicate a mobility even occurred.
*
- * @param arg1 The "any" token; this event is always applicable.
+ * @param arg1 The "all" token; this event is always applicable.
* @param obj @NonNull An EventUnderlyingNetworkChangedInfo instance with relevant data.
*/
private static final int EVENT_UNDERLYING_NETWORK_CHANGED = 1;
@@ -175,7 +175,7 @@
* <p>Upon receipt of this signal, the state machine will transition from the Retry-timeout
* state to the Connecting state.
*
- * @param arg1 The "any" token; no sessions are active in the RetryTimeoutState.
+ * @param arg1 The "all" token; no sessions are active in the RetryTimeoutState.
*/
private static final int EVENT_RETRY_TIMEOUT_EXPIRED = 2;
@@ -318,7 +318,7 @@
* <p>Upon receipt of this signal, the state machine MUST tear down all active sessions, cancel
* any pending work items, and move to the Disconnected state.
*
- * @param arg1 The "any" token; this signal is always honored.
+ * @param arg1 The "all" token; this signal is always honored.
* @param obj @NonNull An EventDisconnectRequestedInfo instance with relevant data.
*/
private static final int EVENT_DISCONNECT_REQUESTED = 7;
@@ -504,16 +504,9 @@
* <p>Once torn down, this VcnTunnel CANNOT be started again.
*/
public void teardownAsynchronously() {
- mUnderlyingNetworkTracker.teardown();
-
- // No need to call setInterfaceDown(); the IpSecInterface is being fully torn down.
- if (mTunnelIface != null) {
- mTunnelIface.close();
- }
-
sendMessage(
EVENT_DISCONNECT_REQUESTED,
- TOKEN_ANY,
+ TOKEN_ALL,
new EventDisconnectRequestedInfo(DISCONNECT_REASON_TEARDOWN));
quit();
@@ -521,6 +514,16 @@
// is also called asynchronously when a NetworkAgent becomes unwanted
}
+ @Override
+ protected void onQuitting() {
+ // No need to call setInterfaceDown(); the IpSecInterface is being fully torn down.
+ if (mTunnelIface != null) {
+ mTunnelIface.close();
+ }
+
+ mUnderlyingNetworkTracker.teardown();
+ }
+
private class VcnUnderlyingNetworkTrackerCallback implements UnderlyingNetworkTrackerCallback {
@Override
public void onSelectedUnderlyingNetworkChanged(
@@ -530,26 +533,24 @@
if (underlying == null) {
sendMessageDelayed(
EVENT_DISCONNECT_REQUESTED,
- TOKEN_ANY,
+ TOKEN_ALL,
new EventDisconnectRequestedInfo(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST),
TimeUnit.SECONDS.toMillis(NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS));
- return;
- }
+ } else if (getHandler() != null) {
+ // Cancel any existing disconnect due to loss of underlying network
+ // getHandler() can return null if the state machine has already quit. Since this is
+ // called from other classes, this condition must be verified.
- // Cancel any existing disconnect due to loss of underlying network
- // getHandler() can return null if the state machine has already quit. Since this is
- // called
- // from other classes, this condition must be verified.
- if (getHandler() != null) {
getHandler()
.removeEqualMessages(
EVENT_DISCONNECT_REQUESTED,
new EventDisconnectRequestedInfo(
DISCONNECT_REASON_UNDERLYING_NETWORK_LOST));
}
+
sendMessage(
EVENT_UNDERLYING_NETWORK_CHANGED,
- TOKEN_ANY,
+ TOKEN_ALL,
new EventUnderlyingNetworkChangedInfo(underlying));
}
}
@@ -594,10 +595,101 @@
}
private abstract class BaseState extends State {
+ @Override
+ public void enter() {
+ try {
+ enterState();
+ } catch (Exception e) {
+ Slog.wtf(TAG, "Uncaught exception", e);
+ sendMessage(
+ EVENT_DISCONNECT_REQUESTED,
+ TOKEN_ALL,
+ new EventDisconnectRequestedInfo(
+ DISCONNECT_REASON_INTERNAL_ERROR + e.toString()));
+ }
+ }
+
protected void enterState() throws Exception {}
+ /**
+ * Top-level processMessage with safeguards to prevent crashing the System Server on non-eng
+ * builds.
+ */
+ @Override
+ public boolean processMessage(Message msg) {
+ try {
+ processStateMsg(msg);
+ } catch (Exception e) {
+ Slog.wtf(TAG, "Uncaught exception", e);
+ sendMessage(
+ EVENT_DISCONNECT_REQUESTED,
+ TOKEN_ALL,
+ new EventDisconnectRequestedInfo(
+ DISCONNECT_REASON_INTERNAL_ERROR + e.toString()));
+ }
+
+ return HANDLED;
+ }
+
protected abstract void processStateMsg(Message msg) throws Exception;
+
+ protected void logUnhandledMessage(Message msg) {
+ // Log as unexpected all known messages, and log all else as unknown.
+ switch (msg.what) {
+ case EVENT_UNDERLYING_NETWORK_CHANGED: // Fallthrough
+ case EVENT_RETRY_TIMEOUT_EXPIRED: // Fallthrough
+ case EVENT_SESSION_LOST: // Fallthrough
+ case EVENT_SESSION_CLOSED: // Fallthrough
+ case EVENT_TRANSFORM_CREATED: // Fallthrough
+ case EVENT_SETUP_COMPLETED: // Fallthrough
+ case EVENT_DISCONNECT_REQUESTED: // Fallthrough
+ case EVENT_TEARDOWN_TIMEOUT_EXPIRED:
+ logUnexpectedEvent(msg.what);
+ break;
+ default:
+ logWtfUnknownEvent(msg.what);
+ break;
+ }
+ }
+
+ protected void teardownNetwork() {
+ if (mNetworkAgent != null) {
+ mNetworkAgent.sendNetworkInfo(buildNetworkInfo(false /* isConnected */));
+ mNetworkAgent = null;
+ }
+ }
+
+ protected void teardownIke() {
+ if (mIkeSession != null) {
+ mIkeSession.close();
+ }
+ }
+
+ protected void handleDisconnectRequested(String msg) {
+ Slog.v(TAG, "Tearing down. Cause: " + msg);
+ teardownNetwork();
+ teardownIke();
+
+ if (mIkeSession == null) {
+ // Already disconnected, go straight to DisconnectedState
+ transitionTo(mDisconnectedState);
+ } else {
+ // Still need to wait for full closure
+ transitionTo(mDisconnectingState);
+ }
+ }
+
+ protected void logUnexpectedEvent(int what) {
+ Slog.d(TAG, String.format(
+ "Unexpected event code %d in state %s", what, this.getClass().getSimpleName()));
+ }
+
+ protected void logWtfUnknownEvent(int what) {
+ Slog.wtf(TAG, String.format(
+ "Unknown event code %d in state %s", what, this.getClass().getSimpleName()));
+ }
}
+
/**
* State representing the a disconnected VCN tunnel.
*
@@ -608,7 +700,29 @@
protected void processStateMsg(Message msg) {}
}
- private abstract class ActiveBaseState extends BaseState {}
+ private abstract class ActiveBaseState extends BaseState {
+ /**
+ * Handles all incoming messages, discarding messages for previous networks.
+ *
+ * <p>States that handle mobility events may need to override this method to receive
+ * messages for all underlying networks.
+ */
+ @Override
+ public boolean processMessage(Message msg) {
+ final int token = msg.arg1;
+ // Only process if a valid token is presented.
+ if (isValidToken(token)) {
+ return super.processMessage(msg);
+ }
+
+ Slog.v(TAG, "Message called with obsolete token: " + token + "; what: " + msg.what);
+ return HANDLED;
+ }
+
+ protected boolean isValidToken(int token) {
+ return (token == TOKEN_ALL || token == mCurrentToken);
+ }
+ }
/**
* Transitive state representing a VCN that is tearing down an IKE session.
diff --git a/services/core/java/com/android/server/vibrator/VibrationThread.java b/services/core/java/com/android/server/vibrator/VibrationThread.java
index a4d888b..c36375e 100644
--- a/services/core/java/com/android/server/vibrator/VibrationThread.java
+++ b/services/core/java/com/android/server/vibrator/VibrationThread.java
@@ -39,8 +39,6 @@
import java.util.ArrayList;
import java.util.List;
import java.util.PriorityQueue;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
/** Plays a {@link Vibration} in dedicated thread. */
// TODO(b/159207608): Make this package-private once vibrator services are moved to this package
@@ -76,7 +74,6 @@
void onVibrationEnded(long vibrationId, Vibration.Status status);
}
- private final Object mLock = new Object();
private final WorkSource mWorkSource = new WorkSource();
private final PowerManager.WakeLock mWakeLock;
private final IBatteryStats mBatteryStatsService;
@@ -84,7 +81,7 @@
private final VibrationCallbacks mCallbacks;
private final SparseArray<VibratorController> mVibrators;
- @GuardedBy("mLock")
+ @GuardedBy("this")
@Nullable
private VibrateStep mCurrentVibrateStep;
@GuardedBy("this")
@@ -147,7 +144,7 @@
/** Notify current vibration that a step has completed on given vibrator. */
public void vibratorComplete(int vibratorId) {
- synchronized (mLock) {
+ synchronized (this) {
if (mCurrentVibrateStep != null) {
mCurrentVibrateStep.vibratorComplete(vibratorId);
}
@@ -171,7 +168,7 @@
final int stepCount = steps.size();
for (int i = 0; i < stepCount; i++) {
Step step = steps.get(i);
- synchronized (mLock) {
+ synchronized (this) {
if (step instanceof VibrateStep) {
mCurrentVibrateStep = (VibrateStep) step;
} else {
@@ -315,27 +312,6 @@
}
}
- /**
- * Sleeps until given {@link CountDownLatch} has finished or {@code wakeUpTime} was reached.
- *
- * <p>This stops immediately when {@link #cancel()} is called.
- */
- private void awaitUntil(CountDownLatch counter, long wakeUpTime) {
- synchronized (this) {
- long durationRemaining = wakeUpTime - SystemClock.uptimeMillis();
- while (counter.getCount() > 0 && durationRemaining > 0) {
- try {
- counter.await(durationRemaining, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {
- }
- if (mForceStop) {
- break;
- }
- durationRemaining = wakeUpTime - SystemClock.uptimeMillis();
- }
- }
- }
-
private void noteVibratorOn(long duration) {
try {
mBatteryStatsService.noteVibratorOn(mVibration.uid, duration);
@@ -371,12 +347,10 @@
private final class SingleVibrateStep implements VibrateStep {
private final VibratorController mVibrator;
private final VibrationEffect mEffect;
- private final CountDownLatch mCounter;
SingleVibrateStep(VibratorController vibrator, VibrationEffect effect) {
mVibrator = vibrator;
mEffect = effect;
- mCounter = new CountDownLatch(1);
}
@Override
@@ -390,7 +364,9 @@
return;
}
mVibrator.off();
- mCounter.countDown();
+ synchronized (VibrationThread.this) {
+ VibrationThread.this.notify();
+ }
}
@Override
@@ -408,7 +384,11 @@
noteVibratorOn(duration);
// Vibration is playing with no need to control amplitudes, just wait for native
// callback or timeout.
- awaitUntil(mCounter, startTime + duration + CALLBACKS_EXTRA_TIMEOUT);
+ waitUntil(startTime + duration + CALLBACKS_EXTRA_TIMEOUT);
+ if (mForceStop) {
+ mVibrator.off();
+ return Vibration.Status.CANCELLED;
+ }
return Vibration.Status.FINISHED;
}
@@ -499,14 +479,15 @@
/** Represent a synchronized vibration step on multiple vibrators. */
private final class SyncedVibrateStep implements VibrateStep {
private final SparseArray<VibrationEffect> mEffects;
- private final CountDownLatch mActiveVibratorCounter;
-
private final int mRequiredCapabilities;
private final int[] mVibratorIds;
+ @GuardedBy("VibrationThread.this")
+ private int mActiveVibratorCounter;
+
SyncedVibrateStep(SparseArray<VibrationEffect> effects) {
mEffects = effects;
- mActiveVibratorCounter = new CountDownLatch(mEffects.size());
+ mActiveVibratorCounter = mEffects.size();
// TODO(b/159207608): Calculate required capabilities for syncing this step.
mRequiredCapabilities = 0;
mVibratorIds = new int[effects.size()];
@@ -527,7 +508,11 @@
return;
}
mVibrators.get(vibratorId).off();
- mActiveVibratorCounter.countDown();
+ synchronized (VibrationThread.this) {
+ if (--mActiveVibratorCounter <= 0) {
+ VibrationThread.this.notify();
+ }
+ }
}
@Override
@@ -556,7 +541,9 @@
AmplitudeStep nextStep = step.nextStep();
if (nextStep == null) {
// This vibrator has finished playing the effect for this step.
- mActiveVibratorCounter.countDown();
+ synchronized (VibrationThread.this) {
+ mActiveVibratorCounter--;
+ }
} else {
nextSteps.add(nextStep);
}
@@ -564,7 +551,16 @@
// All OneShot and Waveform effects have finished. Just wait for the other effects
// to end via native callbacks before finishing this synced step.
- awaitUntil(mActiveVibratorCounter, startTime + timeout + CALLBACKS_EXTRA_TIMEOUT);
+ synchronized (VibrationThread.this) {
+ if (mActiveVibratorCounter > 0) {
+ waitUntil(startTime + timeout + CALLBACKS_EXTRA_TIMEOUT);
+ }
+ }
+ if (mForceStop) {
+ stopAllVibrators();
+ return Vibration.Status.CANCELLED;
+ }
+
return Vibration.Status.FINISHED;
} finally {
if (timeout > 0) {
@@ -779,7 +775,7 @@
Slog.d(TAG, "DelayStep of " + mDelay + "ms starting...");
}
waitUntil(SystemClock.uptimeMillis() + mDelay);
- return Vibration.Status.FINISHED;
+ return mForceStop ? Vibration.Status.CANCELLED : Vibration.Status.FINISHED;
} finally {
if (DEBUG) {
Slog.d(TAG, "DelayStep done.");
diff --git a/services/core/java/com/android/server/vibrator/VibratorController.java b/services/core/java/com/android/server/vibrator/VibratorController.java
index 53f52e2..9dcf12c 100644
--- a/services/core/java/com/android/server/vibrator/VibratorController.java
+++ b/services/core/java/com/android/server/vibrator/VibratorController.java
@@ -272,12 +272,18 @@
return 0;
}
synchronized (mLock) {
- mNativeWrapper.compose(effect.getPrimitiveEffects().toArray(
- new VibrationEffect.Composition.PrimitiveEffect[0]), vibrationId);
+ VibrationEffect.Composition.PrimitiveEffect[] primitives =
+ effect.getPrimitiveEffects().toArray(
+ new VibrationEffect.Composition.PrimitiveEffect[0]);
+ mNativeWrapper.compose(primitives, vibrationId);
notifyVibratorOnLocked();
// Compose don't actually give us an estimated duration, so we just guess here.
- // TODO(b/177807015): use exposed durations from IVibrator here instead
- return 20 * effect.getPrimitiveEffects().size();
+ long duration = 0;
+ for (VibrationEffect.Composition.PrimitiveEffect primitive : primitives) {
+ // TODO(b/177807015): use exposed durations from IVibrator here instead
+ duration += 20 + primitive.delay;
+ }
+ return duration;
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 0f4bb4c..ba0292df 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2749,8 +2749,7 @@
if (ensureVisibility) {
mDisplayContent.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
- false /* preserveWindows */, true /* notifyClients */,
- mTaskSupervisor.mUserLeaving);
+ false /* preserveWindows */, true /* notifyClients */);
}
}
@@ -4823,7 +4822,7 @@
handleAlreadyVisible();
}
- void makeInvisible(boolean userLeaving) {
+ void makeInvisible() {
if (!mVisibleRequested) {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Already invisible: " + this);
return;
@@ -4864,7 +4863,7 @@
// If the app is capable of entering PIP, we should try pausing it now
// so it can PIP correctly.
if (deferHidingClient) {
- task.startPausingLocked(userLeaving, false /* uiSleeping */,
+ task.startPausingLocked(false /* uiSleeping */,
null /* resuming */, "makeInvisible");
break;
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index e67210e..683bb08 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1588,6 +1588,7 @@
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
startedActivityStack = handleStartResult(r, result);
mService.continueWindowLayout();
+ mSupervisor.mUserLeaving = false;
// Transition housekeeping
if (!ActivityManager.isStartResultSuccessful(result)) {
@@ -2340,6 +2341,7 @@
mDoResume = false;
mAvoidMoveToFront = true;
}
+ mTargetRootTask = Task.fromWindowContainerToken(mOptions.getLaunchRootTask());
}
mNotTop = (mLaunchFlags & FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? sourceRecord : null;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index b332739..efae16b 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1940,7 +1940,7 @@
} else {
stack.setWindowingMode(windowingMode);
stack.mDisplayContent.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS,
- true /* notifyClients */, mTaskSupervisor.mUserLeaving);
+ true /* notifyClients */);
}
return true;
} finally {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index a68f5575..d2ce369 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -1361,53 +1361,58 @@
return;
}
- if ((flags & ActivityManager.MOVE_TASK_NO_USER_ACTION) == 0) {
- mUserLeaving = true;
- }
-
- mService.getTransitionController().requestTransitionIfNeeded(TRANSIT_TO_FRONT,
- 0 /* flags */, task, options != null ? options.getRemoteTransition() : null);
- reason = reason + " findTaskToMoveToFront";
- boolean reparented = false;
- if (task.isResizeable() && canUseActivityOptionsLaunchBounds(options)) {
- final Rect bounds = options.getLaunchBounds();
- task.setBounds(bounds);
-
- Task stack =
- mRootWindowContainer.getLaunchRootTask(null, options, task, ON_TOP);
-
- if (stack != currentStack) {
- moveHomeRootTaskToFrontIfNeeded(flags, stack.getDisplayArea(), reason);
- task.reparent(stack, ON_TOP, REPARENT_KEEP_ROOT_TASK_AT_FRONT, !ANIMATE,
- DEFER_RESUME, reason);
- currentStack = stack;
- reparented = true;
- // task.reparent() should already placed the task on top,
- // still need moveTaskToFrontLocked() below for any transition settings.
+ try {
+ if ((flags & ActivityManager.MOVE_TASK_NO_USER_ACTION) == 0) {
+ mUserLeaving = true;
}
- if (stack.shouldResizeRootTaskWithLaunchBounds()) {
- stack.resize(bounds, !PRESERVE_WINDOWS, !DEFER_RESUME);
- } else {
- // WM resizeTask must be done after the task is moved to the correct stack,
- // because Task's setBounds() also updates dim layer's bounds, but that has
- // dependency on the stack.
- task.resize(false /* relayout */, false /* forced */);
+
+ mService.getTransitionController().requestTransitionIfNeeded(TRANSIT_TO_FRONT,
+ 0 /* flags */, task, options != null ? options.getRemoteTransition() : null);
+ reason = reason + " findTaskToMoveToFront";
+ boolean reparented = false;
+ if (task.isResizeable() && canUseActivityOptionsLaunchBounds(options)) {
+ final Rect bounds = options.getLaunchBounds();
+ task.setBounds(bounds);
+
+ Task stack =
+ mRootWindowContainer.getLaunchRootTask(null, options, task, ON_TOP);
+
+ if (stack != currentStack) {
+ moveHomeRootTaskToFrontIfNeeded(flags, stack.getDisplayArea(), reason);
+ task.reparent(stack, ON_TOP, REPARENT_KEEP_ROOT_TASK_AT_FRONT, !ANIMATE,
+ DEFER_RESUME, reason);
+ currentStack = stack;
+ reparented = true;
+ // task.reparent() should already placed the task on top,
+ // still need moveTaskToFrontLocked() below for any transition settings.
+ }
+ if (stack.shouldResizeRootTaskWithLaunchBounds()) {
+ stack.resize(bounds, !PRESERVE_WINDOWS, !DEFER_RESUME);
+ } else {
+ // WM resizeTask must be done after the task is moved to the correct stack,
+ // because Task's setBounds() also updates dim layer's bounds, but that has
+ // dependency on the stack.
+ task.resize(false /* relayout */, false /* forced */);
+ }
}
+
+ if (!reparented) {
+ moveHomeRootTaskToFrontIfNeeded(flags, currentStack.getDisplayArea(), reason);
+ }
+
+ final ActivityRecord r = task.getTopNonFinishingActivity();
+ currentStack.moveTaskToFront(task, false /* noAnimation */, options,
+ r == null ? null : r.appTimeTracker, reason);
+
+ if (DEBUG_ROOT_TASK) Slog.d(TAG_ROOT_TASK,
+ "findTaskToMoveToFront: moved to front of stack=" + currentStack);
+
+ handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED,
+ mRootWindowContainer.getDefaultTaskDisplayArea(), currentStack,
+ forceNonResizeable);
+ } finally {
+ mUserLeaving = false;
}
-
- if (!reparented) {
- moveHomeRootTaskToFrontIfNeeded(flags, currentStack.getDisplayArea(), reason);
- }
-
- final ActivityRecord r = task.getTopNonFinishingActivity();
- currentStack.moveTaskToFront(task, false /* noAnimation */, options,
- r == null ? null : r.appTimeTracker, reason);
-
- if (DEBUG_ROOT_TASK) Slog.d(TAG_ROOT_TASK,
- "findTaskToMoveToFront: moved to front of stack=" + currentStack);
-
- handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED,
- mRootWindowContainer.getDefaultTaskDisplayArea(), currentStack, forceNonResizeable);
}
private void moveHomeRootTaskToFrontIfNeeded(int flags, TaskDisplayArea taskDisplayArea,
@@ -2209,7 +2214,7 @@
.notifyActivityDismissingDockedStack();
taskDisplayArea.onSplitScreenModeDismissed(task);
taskDisplayArea.mDisplayContent.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS,
- true /* notifyClients */, mUserLeaving);
+ true /* notifyClients */);
}
return;
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 9769244..b7970cd 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1559,6 +1559,13 @@
}
final int rotation = rotationForActivityInDifferentOrientation(r);
if (rotation == ROTATION_UNDEFINED) {
+ // The display rotation won't be changed by current top activity. If there was fixed
+ // rotation activity, its rotated state should be cleared to cancel the adjustments.
+ if (hasTopFixedRotationLaunchingApp()
+ // Avoid breaking recents animation.
+ && !mFixedRotationLaunchingApp.getTask().isAnimatingByRecents()) {
+ clearFixedRotationLaunchingApp();
+ }
return false;
}
if (!r.getParent().matchParentBounds()) {
@@ -5536,7 +5543,7 @@
void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
- boolean preserveWindows, boolean notifyClients, boolean userLeaving) {
+ boolean preserveWindows, boolean notifyClients) {
if (mInEnsureActivitiesVisible) {
// Don't do recursive work.
return;
@@ -5546,7 +5553,7 @@
try {
forAllRootTasks(rootTask -> {
rootTask.ensureActivitiesVisible(starting, configChanges, preserveWindows,
- notifyClients, userLeaving);
+ notifyClients);
});
} finally {
mAtmService.mTaskSupervisor.endActivityVisibilityUpdate();
diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
index 4581024..74264d3 100644
--- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
+++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
@@ -33,7 +33,6 @@
private int mConfigChanges;
private boolean mPreserveWindows;
private boolean mNotifyClients;
- private boolean mUserLeaving;
EnsureActivitiesVisibleHelper(Task container) {
mTask = container;
@@ -50,7 +49,7 @@
* be sent to the clients.
*/
void reset(ActivityRecord starting, int configChanges, boolean preserveWindows,
- boolean notifyClients, boolean userLeaving) {
+ boolean notifyClients) {
mStarting = starting;
mTop = mTask.topRunningActivity();
// If the top activity is not fullscreen, then we need to make sure any activities under it
@@ -61,7 +60,6 @@
mConfigChanges = configChanges;
mPreserveWindows = preserveWindows;
mNotifyClients = notifyClients;
- mUserLeaving = userLeaving;
}
/**
@@ -78,12 +76,10 @@
* @param preserveWindows Flag indicating whether windows should be preserved when updating.
* @param notifyClients Flag indicating whether the configuration and visibility changes shoulc
* be sent to the clients.
- * @param userLeaving Flag indicating whether a userLeaving callback should be issued in the
- * case the activity is being set to invisible.
*/
void process(@Nullable ActivityRecord starting, int configChanges, boolean preserveWindows,
- boolean notifyClients, boolean userLeaving) {
- reset(starting, configChanges, preserveWindows, notifyClients, userLeaving);
+ boolean notifyClients) {
+ reset(starting, configChanges, preserveWindows, notifyClients);
if (DEBUG_VISIBILITY) {
Slog.v(TAG_VISIBILITY, "ensureActivitiesVisible behind " + mTop
@@ -177,7 +173,7 @@
+ " behindFullscreenActivity=" + mBehindFullscreenActivity
+ " mLaunchTaskBehind=" + r.mLaunchTaskBehind);
}
- r.makeInvisible(mUserLeaving);
+ r.makeInvisible();
}
if (!mBehindFullscreenActivity && mTask.isActivityTypeHome() && r.isRootOfTask()) {
diff --git a/services/core/java/com/android/server/wm/ImpressionAttestationController.java b/services/core/java/com/android/server/wm/ImpressionAttestationController.java
index b0afc57..bad6c80 100644
--- a/services/core/java/com/android/server/wm/ImpressionAttestationController.java
+++ b/services/core/java/com/android/server/wm/ImpressionAttestationController.java
@@ -86,7 +86,7 @@
private final Handler mHandler;
- private final String mSalt;
+ private final byte[] mSalt;
private final float[] mTmpFloat9 = new float[9];
private final Matrix mTmpMatrix = new Matrix();
@@ -99,7 +99,7 @@
ImpressionAttestationController(Context context) {
mContext = context;
mHandler = new Handler(Looper.getMainLooper());
- mSalt = UUID.randomUUID().toString();
+ mSalt = UUID.randomUUID().toString().getBytes();
}
String[] getSupportedImpressionAlgorithms() {
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index a20d924..cc77cfa 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -407,7 +407,7 @@
}
mInputFocus = focusToken;
- mInputTransaction.setFocusedWindow(mInputFocus, mDisplayId);
+ mInputTransaction.setFocusedWindow(mInputFocus, focus.getName(), mDisplayId);
EventLog.writeEvent(LOGTAG_INPUT_FOCUS, "Focus request " + focus,
"reason=UpdateInputWindows");
ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Focus requested for window=%s", focus);
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 7d1da5a..c575ca3 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -392,6 +392,7 @@
Slog.e(TAG, "Failed to clean up recents activity", e);
throw e;
} finally {
+ mTaskSupervisor.mUserLeaving = false;
mService.continueWindowLayout();
// Make sure the surfaces are updated with the latest state. Sometimes the
// surface placement may be skipped if display configuration is changed (i.e.
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index d8b1e18..4300aed 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1796,8 +1796,7 @@
// Passing null here for 'starting' param value, so that visibility of actual starting
// activity will be properly updated.
ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
- false /* preserveWindows */, false /* notifyClients */,
- mTaskSupervisor.mUserLeaving);
+ false /* preserveWindows */, false /* notifyClients */);
if (displayId == INVALID_DISPLAY) {
// The caller didn't provide a valid display id, skip updating config.
@@ -1973,15 +1972,14 @@
*/
void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
boolean preserveWindows) {
- ensureActivitiesVisible(starting, configChanges, preserveWindows, true /* notifyClients */,
- mTaskSupervisor.mUserLeaving);
+ ensureActivitiesVisible(starting, configChanges, preserveWindows, true /* notifyClients */);
}
/**
* @see #ensureActivitiesVisible(ActivityRecord, int, boolean)
*/
void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
- boolean preserveWindows, boolean notifyClients, boolean userLeaving) {
+ boolean preserveWindows, boolean notifyClients) {
if (mTaskSupervisor.inActivityVisibilityUpdate()) {
// Don't do recursive work.
return;
@@ -1993,7 +1991,7 @@
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
final DisplayContent display = getChildAt(displayNdx);
display.ensureActivitiesVisible(starting, configChanges, preserveWindows,
- notifyClients, userLeaving);
+ notifyClients);
}
} finally {
mTaskSupervisor.endActivityVisibilityUpdate();
@@ -2858,6 +2856,11 @@
final WindowContainerToken daToken = options.getLaunchTaskDisplayArea();
taskDisplayArea = daToken != null
? (TaskDisplayArea) WindowContainer.fromBinder(daToken.asBinder()) : null;
+
+ final Task rootTask = Task.fromWindowContainerToken(options.getLaunchRootTask());
+ if (rootTask != null) {
+ return rootTask;
+ }
}
// First preference for stack goes to the task Id set in the activity options. Use the stack
@@ -3032,7 +3035,8 @@
final int activityType =
options != null && options.getLaunchActivityType() != ACTIVITY_TYPE_UNDEFINED
? options.getLaunchActivityType() : r.getActivityType();
- return taskDisplayArea.createRootTask(windowingMode, activityType, true /*onTop*/);
+ return taskDisplayArea.createRootTask(
+ windowingMode, activityType, true /*onTop*/, options);
}
return null;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 2295ee3..fb50fa1e 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -209,6 +209,7 @@
import android.window.ITaskOrganizer;
import android.window.StartingWindowInfo;
import android.window.TaskSnapshot;
+import android.window.WindowContainerToken;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -880,6 +881,11 @@
EventLogTags.writeWmTaskCreated(mTaskId, isRootTask() ? INVALID_TASK_ID : getRootTaskId());
}
+ static Task fromWindowContainerToken(WindowContainerToken token) {
+ if (token == null) return null;
+ return fromBinder(token.asBinder()).asTask();
+ }
+
Task reuseAsLeafTask(IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
Intent intent, ActivityInfo info, ActivityRecord activity) {
voiceSession = _voiceSession;
@@ -5600,6 +5606,10 @@
return false;
}
+ final boolean startPausingLocked(boolean uiSleeping, ActivityRecord resuming, String reason) {
+ return startPausingLocked(mTaskSupervisor.mUserLeaving, uiSleeping, resuming, reason);
+ }
+
/**
* Start pausing the currently resumed activity. It is an error to call this if there
* is already an activity being paused or there is no resumed activity.
@@ -5864,8 +5874,7 @@
*/
void ensureActivitiesVisible(@Nullable ActivityRecord starting, int configChanges,
boolean preserveWindows) {
- ensureActivitiesVisible(starting, configChanges, preserveWindows, true /* notifyClients */,
- mTaskSupervisor.mUserLeaving);
+ ensureActivitiesVisible(starting, configChanges, preserveWindows, true /* notifyClients */);
}
/**
@@ -5882,16 +5891,14 @@
* @param configChanges Parts of the configuration that changed for this activity for evaluating
* if the screen should be frozen as part of
* {@link mEnsureActivitiesVisibleHelper}.
- * @param userLeaving Flag indicating whether a userLeaving callback should be issued in the
- * case an activity is being set to invisible.
*/
// TODO: Should be re-worked based on the fact that each task as a stack in most cases.
void ensureActivitiesVisible(@Nullable ActivityRecord starting, int configChanges,
- boolean preserveWindows, boolean notifyClients, boolean userLeaving) {
+ boolean preserveWindows, boolean notifyClients) {
mTaskSupervisor.beginActivityVisibilityUpdate();
try {
forAllLeafTasks(task -> task.mEnsureActivitiesVisibleHelper.process(
- starting, configChanges, preserveWindows, notifyClients, userLeaving),
+ starting, configChanges, preserveWindows, notifyClients),
true /* traverseTopToBottom */);
// Notify WM shell that task visibilities may have changed
@@ -6087,11 +6094,6 @@
mRootWindowContainer.cancelInitializingActivities();
- // Remember how we'll process this pause/resume situation, and ensure
- // that the state is reset however we wind up proceeding.
- boolean userLeaving = mTaskSupervisor.mUserLeaving;
- mTaskSupervisor.mUserLeaving = false;
-
if (!hasRunningActivity) {
// There are no activities left in the stack, let's look somewhere else.
return resumeNextFocusableActivityWhenRootTaskIsEmpty(prev, options);
@@ -6111,7 +6113,7 @@
// a fullscreen window forward to cover another freeform activity.)
if (taskDisplayArea.inMultiWindowMode()) {
taskDisplayArea.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
- false /* preserveWindows */, true /* notifyClients */, userLeaving);
+ false /* preserveWindows */, true /* notifyClients */);
}
ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Top activity "
+ "resumed %s", next);
@@ -6176,19 +6178,12 @@
// doesn't represent the last resumed activity. However, the last focus stack does if
// it isn't null.
lastResumed = lastFocusedRootTask.getResumedActivity();
- if (userLeaving && inMultiWindowMode() && lastFocusedRootTask.shouldBeVisible(next)) {
- // The user isn't leaving if this stack is the multi-window mode and the last
- // focused stack should still be visible.
- if(DEBUG_USER_LEAVING) Slog.i(TAG_USER_LEAVING, "Overriding userLeaving to false"
- + " next=" + next + " lastResumed=" + lastResumed);
- userLeaving = false;
- }
}
- boolean pausing = taskDisplayArea.pauseBackTasks(userLeaving, next);
+ boolean pausing = taskDisplayArea.pauseBackTasks(next);
if (mResumedActivity != null) {
ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Pausing %s", mResumedActivity);
- pausing |= startPausingLocked(userLeaving, false /* uiSleeping */, next,
+ pausing |= startPausingLocked(false /* uiSleeping */, next,
"resumeTopActivityInnerLocked");
}
if (pausing) {
@@ -7380,6 +7375,7 @@
task = new Task.Builder(mAtmService)
.setTaskId(taskId)
.setActivityInfo(info)
+ .setActivityOptions(options)
.setIntent(intent)
.setVoiceSession(voiceSession)
.setVoiceInteractor(voiceInteractor)
@@ -7819,6 +7815,7 @@
private int mMinWidth = INVALID_MIN_SIZE;
private int mMinHeight = INVALID_MIN_SIZE;
private ActivityInfo mActivityInfo;
+ private ActivityOptions mActivityOptions;
private IVoiceInteractionSession mVoiceSession;
private IVoiceInteractor mVoiceInteractor;
private int mActivityType;
@@ -7872,6 +7869,11 @@
return this;
}
+ Builder setActivityOptions(ActivityOptions opts) {
+ mActivityOptions = opts;
+ return this;
+ }
+
Builder setVoiceSession(IVoiceInteractionSession voiceSession) {
mVoiceSession = voiceSession;
return this;
@@ -8078,7 +8080,7 @@
// Task created by organizer are added as root.
final Task launchRootTask = mCreatedByOrganizer
- ? null : tda.getLaunchRootTask(mWindowingMode, mActivityType);
+ ? null : tda.getLaunchRootTask(mWindowingMode, mActivityType, mActivityOptions);
if (launchRootTask != null) {
// Since this task will be put into a root task, its windowingMode will be
// inherited.
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 0136c01..a83f81d 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -48,6 +48,7 @@
import android.util.IntArray;
import android.util.Slog;
import android.view.SurfaceControl;
+import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import com.android.internal.annotations.VisibleForTesting;
@@ -997,11 +998,11 @@
* Returns an existing stack compatible with the windowing mode and activity type or creates one
* if a compatible stack doesn't exist.
*
- * @see #getOrCreateRootTask(int, int, boolean, Intent, Task)
+ * @see #getOrCreateRootTask(int, int, boolean, Intent, Task, ActivityOptions)
*/
Task getOrCreateRootTask(int windowingMode, int activityType, boolean onTop) {
return getOrCreateRootTask(windowingMode, activityType, onTop, null /* intent */,
- null /* candidateTask */);
+ null /* candidateTask */, null /* options */);
}
/**
@@ -1014,7 +1015,7 @@
* @see #createRootTask(int, int, boolean)
*/
Task getOrCreateRootTask(int windowingMode, int activityType, boolean onTop,
- Intent intent, Task candidateTask) {
+ Intent intent, Task candidateTask, ActivityOptions options) {
// Need to pass in a determined windowing mode to see if a new stack should be created,
// so use its parent's windowing mode if it is undefined.
if (!alwaysCreateRootTask(
@@ -1027,7 +1028,7 @@
} else if (candidateTask != null) {
final Task stack = candidateTask;
final int position = onTop ? POSITION_TOP : POSITION_BOTTOM;
- final Task launchRootTask = getLaunchRootTask(windowingMode, activityType);
+ final Task launchRootTask = getLaunchRootTask(windowingMode, activityType, options);
if (launchRootTask != null) {
if (stack.getParent() == null) {
@@ -1054,6 +1055,7 @@
.setOnTop(onTop)
.setParent(this)
.setIntent(intent)
+ .setActivityOptions(options)
.build();
}
@@ -1074,7 +1076,7 @@
// it's display's windowing mode.
windowingMode = validateWindowingMode(windowingMode, r, candidateTask, activityType);
return getOrCreateRootTask(windowingMode, activityType, onTop, null /* intent */,
- candidateTask);
+ candidateTask, options);
}
@VisibleForTesting
@@ -1082,6 +1084,10 @@
return mAtmService.mTaskSupervisor.getNextTaskIdForUser();
}
+ Task createRootTask(int windowingMode, int activityType, boolean onTop) {
+ return createRootTask(windowingMode, activityType, onTop, null /* activityOptions */);
+ }
+
/**
* A convinenit method of creating a root task by providing windowing mode and activity type
* on this display.
@@ -1095,14 +1101,16 @@
* {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
* @param onTop If true the root task will be created at the top of the display,
* else at the bottom.
+ * @param opts The activity options.
* @return The newly created root task.
*/
- Task createRootTask(int windowingMode, int activityType, boolean onTop) {
+ Task createRootTask(int windowingMode, int activityType, boolean onTop, ActivityOptions opts) {
return new Task.Builder(mAtmService)
.setWindowingMode(windowingMode)
.setActivityType(activityType)
.setParent(this)
.setOnTop(onTop)
+ .setActivityOptions(opts)
.build();
}
@@ -1134,7 +1142,16 @@
}
}
- Task getLaunchRootTask(int windowingMode, int activityType) {
+ Task getLaunchRootTask(int windowingMode, int activityType, ActivityOptions options) {
+ // Try to use the launch root task in options if available.
+ if (options != null) {
+ final Task launchRootTask = Task.fromWindowContainerToken(options.getLaunchRootTask());
+ // We only allow this for created by organizer tasks.
+ if (launchRootTask != null && launchRootTask.mCreatedByOrganizer) {
+ return launchRootTask;
+ }
+ }
+
for (int i = mLaunchRootTasks.size() - 1; i >= 0; --i) {
if (mLaunchRootTasks.get(i).contains(windowingMode, activityType)) {
return mLaunchRootTasks.get(i).task;
@@ -1297,11 +1314,10 @@
* pause activities in visible root tasks, so if an activity is launched within the same root
* task, hen we should explicitly pause that root task's top activity.
*
- * @param userLeaving Passed to pauseActivity() to indicate whether to call onUserLeaving().
* @param resuming The resuming activity.
* @return {@code true} if any activity was paused as a result of this call.
*/
- boolean pauseBackTasks(boolean userLeaving, ActivityRecord resuming) {
+ boolean pauseBackTasks(ActivityRecord resuming) {
final int[] someActivityPaused = {0};
forAllLeafTasks((task) -> {
final ActivityRecord resumedActivity = task.getResumedActivity();
@@ -1310,7 +1326,7 @@
|| !task.isTopActivityFocusable())) {
ProtoLog.d(WM_DEBUG_STATES, "pauseBackTasks: task=%s "
+ "mResumedActivity=%s", task, resumedActivity);
- if (task.startPausingLocked(userLeaving, false /* uiSleeping*/,
+ if (task.startPausingLocked(false /* uiSleeping*/,
resuming, "pauseBackTasks")) {
someActivityPaused[0]++;
}
@@ -1816,12 +1832,12 @@
}
void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
- boolean preserveWindows, boolean notifyClients, boolean userLeaving) {
+ boolean preserveWindows, boolean notifyClients) {
mAtmService.mTaskSupervisor.beginActivityVisibilityUpdate();
try {
forAllRootTasks(rootTask -> {
rootTask.ensureActivitiesVisible(starting, configChanges, preserveWindows,
- notifyClients, userLeaving);
+ notifyClients);
});
} finally {
mAtmService.mTaskSupervisor.endActivityVisibilityUpdate();
@@ -1866,7 +1882,7 @@
// Reparent task to corresponding launch root or display area.
final WindowContainer launchRoot = task.supportsSplitScreenWindowingMode()
? toDisplayArea.getLaunchRootTask(
- task.getWindowingMode(), task.getActivityType())
+ task.getWindowingMode(), task.getActivityType(), null /* options */)
: null;
task.reparent(launchRoot == null ? toDisplayArea : launchRoot, POSITION_TOP);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 4156ed6..ad88469 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2339,7 +2339,7 @@
if (shouldRelayout) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: viewVisibility_1");
- result = win.relayoutVisibleWindow(result, attrChanges);
+ result = win.relayoutVisibleWindow(result);
try {
result = createSurfaceControl(outSurfaceControl, result, win, winAnimator);
@@ -8411,10 +8411,10 @@
}
}
- void grantEmbeddedWindowFocus(Session session, IBinder targetInputToken, boolean grantFocus) {
+ void grantEmbeddedWindowFocus(Session session, IBinder inputToken, boolean grantFocus) {
synchronized (mGlobalLock) {
final EmbeddedWindowController.EmbeddedWindow embeddedWindow =
- mEmbeddedWindowController.get(targetInputToken);
+ mEmbeddedWindowController.get(inputToken);
if (embeddedWindow == null) {
Slog.e(TAG, "Embedded window not found");
return;
@@ -8426,7 +8426,7 @@
SurfaceControl.Transaction t = mTransactionFactory.get();
final int displayId = embeddedWindow.mDisplayId;
if (grantFocus) {
- t.setFocusedWindow(targetInputToken, displayId).apply();
+ t.setFocusedWindow(inputToken, embeddedWindow.getName(), displayId).apply();
EventLog.writeEvent(LOGTAG_INPUT_FOCUS,
"Focus request " + embeddedWindow.getName(),
"reason=grantEmbeddedWindowFocus(true)");
@@ -8441,7 +8441,8 @@
embeddedWindow.getName());
return;
}
- t.requestFocusTransfer(newFocusTarget.mInputChannelToken, targetInputToken,
+ t.requestFocusTransfer(newFocusTarget.mInputChannelToken, newFocusTarget.getName(),
+ inputToken, embeddedWindow.getName(),
displayId).apply();
EventLog.writeEvent(LOGTAG_INPUT_FOCUS,
"Transfer focus request " + newFocusTarget,
@@ -8477,13 +8478,17 @@
}
SurfaceControl.Transaction t = mTransactionFactory.get();
if (grantFocus) {
- t.requestFocusTransfer(targetInputToken, hostWindow.mInputChannel.getToken(),
+ t.requestFocusTransfer(targetInputToken, embeddedWindow.getName(),
+ hostWindow.mInputChannel.getToken(),
+ hostWindow.getName(),
hostWindow.getDisplayId()).apply();
EventLog.writeEvent(LOGTAG_INPUT_FOCUS,
"Transfer focus request " + embeddedWindow.getName(),
"reason=grantEmbeddedWindowFocus(true)");
} else {
- t.requestFocusTransfer(hostWindow.mInputChannel.getToken(), targetInputToken,
+ t.requestFocusTransfer(hostWindow.mInputChannel.getToken(), hostWindow.getName(),
+ targetInputToken,
+ embeddedWindow.getName(),
hostWindow.getDisplayId()).apply();
EventLog.writeEvent(LOGTAG_INPUT_FOCUS,
"Transfer focus request " + hostWindow,
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 389f428..5676909 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -519,13 +519,21 @@
}
}
- public boolean areBackgroundActivityStartsAllowed() {
+ /**
+ * Is this WindowProcessController in the state of allowing background FGS start?
+ */
+ public boolean areBackgroundFgsStartsAllowed() {
synchronized (mAtm.mGlobalLock) {
- return areBackgroundActivityStartsAllowed(mAtm.getBalAppSwitchesAllowed());
+ return areBackgroundActivityStartsAllowed(mAtm.getBalAppSwitchesAllowed(), true);
}
}
boolean areBackgroundActivityStartsAllowed(boolean appSwitchAllowed) {
+ return areBackgroundActivityStartsAllowed(appSwitchAllowed, false);
+ }
+
+ boolean areBackgroundActivityStartsAllowed(boolean appSwitchAllowed,
+ boolean isCheckingForFgsStart) {
// If app switching is not allowed, we ignore all the start activity grace period
// exception so apps cannot start itself in onPause() after pressing home button.
if (appSwitchAllowed) {
@@ -579,7 +587,7 @@
return true;
}
// allow if the flag was explicitly set
- if (isBackgroundStartAllowedByToken()) {
+ if (isBackgroundStartAllowedByToken(isCheckingForFgsStart)) {
if (DEBUG_ACTIVITY_STARTS) {
Slog.d(TAG, "[WindowProcessController(" + mPid
+ ")] Activity start allowed: process allowed by token");
@@ -590,13 +598,20 @@
}
/**
- * If there are no tokens, we don't allow *by token*. If there are tokens, we ask the callback
- * if the start is allowed for these tokens, otherwise if there is no callback we allow.
+ * If there are no tokens, we don't allow *by token*. If there are tokens and
+ * isCheckingForFgsStart is false, we ask the callback if the start is allowed for these tokens,
+ * otherwise if there is no callback we allow.
*/
- private boolean isBackgroundStartAllowedByToken() {
+ private boolean isBackgroundStartAllowedByToken(boolean isCheckingForFgsStart) {
if (mBackgroundActivityStartTokens.isEmpty()) {
return false;
}
+
+ if (isCheckingForFgsStart) {
+ /// The checking is for BG-FGS-start.
+ return true;
+ }
+
if (mBackgroundActivityStartCallback == null) {
// We have tokens but no callback to decide => allow
return true;
@@ -843,7 +858,8 @@
if (mPreQTopResumedActivity != null && mPreQTopResumedActivity.isState(RESUMED)) {
final Task task = mPreQTopResumedActivity.getTask();
if (task != null) {
- task.startPausingLocked(false /* userLeaving */, false /* uiSleeping */,
+ boolean userLeaving = task.shouldBeVisible(null);
+ task.startPausingLocked(userLeaving, false /* uiSleeping */,
activity, "top-resumed-changed");
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index b7602fe..621b971 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -55,7 +55,6 @@
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
-import static android.view.WindowManager.LayoutParams.FORMAT_CHANGED;
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
@@ -68,7 +67,6 @@
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
-import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SYSTEM_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
@@ -3049,8 +3047,8 @@
return;
}
- if (mAttrs.type == TYPE_APPLICATION_OVERLAY && mSession.mCanCreateSystemApplicationOverlay
- && (mAttrs.privateFlags & SYSTEM_FLAG_SYSTEM_APPLICATION_OVERLAY) != 0) {
+ if (mAttrs.type == TYPE_APPLICATION_OVERLAY && mAttrs.isSystemApplicationOverlay()
+ && mSession.mCanCreateSystemApplicationOverlay) {
return;
}
@@ -4935,7 +4933,7 @@
return !mLastSurfaceInsets.equals(mAttrs.surfaceInsets);
}
- int relayoutVisibleWindow(int result, int attrChanges) {
+ int relayoutVisibleWindow(int result) {
final boolean wasVisible = isVisible();
result |= (!wasVisible || !isDrawn()) ? RELAYOUT_RES_FIRST_TIME : 0;
@@ -4970,18 +4968,6 @@
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
- if ((attrChanges & FORMAT_CHANGED) != 0) {
- // If the format can't be changed in place, preserve the old surface until the app draws
- // on the new one. This prevents blinking when we change elevation of freeform and
- // pinned windows.
- if (!mWinAnimator.tryChangeFormatInPlaceLocked()) {
- mWinAnimator.preserveSurfaceLocked(getSyncTransaction());
- result |= RELAYOUT_RES_SURFACE_CHANGED
- | RELAYOUT_RES_FIRST_TIME;
- scheduleAnimation();
- }
- }
-
// When we change the Surface size, in scenarios which may require changing
// the surface position in sync with the resize, we use a preserved surface
// so we can freeze it while waiting for the client to report draw on the newly
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 9e0fee39..64e8184 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -647,11 +647,6 @@
state.mIsTransforming = false;
if (applyDisplayRotation != null) {
applyDisplayRotation.run();
- } else {
- // The display will not rotate to the rotation of this container, let's cancel them.
- for (int i = state.mAssociatedTokens.size() - 1; i >= 0; i--) {
- state.mAssociatedTokens.get(i).cancelFixedRotationTransform();
- }
}
// The state is cleared at the end, because it is used to indicate that other windows can
// use seamless rotation when applying rotation to display.
@@ -659,6 +654,10 @@
final WindowToken token = state.mAssociatedTokens.get(i);
token.mFixedRotationTransformState = null;
token.notifyFixedRotationTransform(false /* enabled */);
+ if (applyDisplayRotation == null) {
+ // Notify cancellation because the display does not change rotation.
+ token.cancelFixedRotationTransform();
+ }
}
}
@@ -707,7 +706,6 @@
// The window may be detached or detaching.
return;
}
- notifyFixedRotationTransform(false /* enabled */);
final int originalRotation = getWindowConfiguration().getRotation();
onConfigurationChanged(parent.getConfiguration());
onCancelFixedRotationTransform(originalRotation);
diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd
index 1cb9e57..7d705c1 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -35,6 +35,18 @@
</xs:element>
<xs:element type="highBrightnessMode" name="highBrightnessMode" minOccurs="0" maxOccurs="1"/>
<xs:element type="displayQuirks" name="quirks" minOccurs="0" maxOccurs="1" />
+ <xs:element type="nonNegativeDecimal" name="screenBrightnessRampFastDecrease">
+ <xs:annotation name="final"/>
+ </xs:element>
+ <xs:element type="nonNegativeDecimal" name="screenBrightnessRampFastIncrease">
+ <xs:annotation name="final"/>
+ </xs:element>
+ <xs:element type="nonNegativeDecimal" name="screenBrightnessRampSlowDecrease">
+ <xs:annotation name="final"/>
+ </xs:element>
+ <xs:element type="nonNegativeDecimal" name="screenBrightnessRampSlowIncrease">
+ <xs:annotation name="final"/>
+ </xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index e073ab3..eb3f1b7 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -7,10 +7,18 @@
method public com.android.server.display.config.DisplayQuirks getQuirks();
method @NonNull public final java.math.BigDecimal getScreenBrightnessDefault();
method @NonNull public final com.android.server.display.config.NitsMap getScreenBrightnessMap();
+ method public final java.math.BigDecimal getScreenBrightnessRampFastDecrease();
+ method public final java.math.BigDecimal getScreenBrightnessRampFastIncrease();
+ method public final java.math.BigDecimal getScreenBrightnessRampSlowDecrease();
+ method public final java.math.BigDecimal getScreenBrightnessRampSlowIncrease();
method public void setHighBrightnessMode(com.android.server.display.config.HighBrightnessMode);
method public void setQuirks(com.android.server.display.config.DisplayQuirks);
method public final void setScreenBrightnessDefault(@NonNull java.math.BigDecimal);
method public final void setScreenBrightnessMap(@NonNull com.android.server.display.config.NitsMap);
+ method public final void setScreenBrightnessRampFastDecrease(java.math.BigDecimal);
+ method public final void setScreenBrightnessRampFastIncrease(java.math.BigDecimal);
+ method public final void setScreenBrightnessRampSlowDecrease(java.math.BigDecimal);
+ method public final void setScreenBrightnessRampSlowIncrease(java.math.BigDecimal);
}
public class DisplayQuirks {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 55ba6c9..1194099 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -17,8 +17,11 @@
import android.annotation.NonNull;
import android.app.admin.DevicePolicySafetyChecker;
+import android.app.admin.FullyManagedDeviceProvisioningParams;
import android.app.admin.IDevicePolicyManager;
+import android.app.admin.ManagedProfileProvisioningParams;
import android.content.ComponentName;
+import android.os.UserHandle;
import android.util.Slog;
import com.android.server.SystemService;
@@ -115,4 +118,13 @@
public void setOrganizationIdForUser(
@NonNull String callerPackage, @NonNull String enterpriseId, int userId) {}
+
+ public UserHandle createAndProvisionManagedProfile(
+ @NonNull ManagedProfileProvisioningParams provisioningParams) {
+ return null;
+ }
+
+ public void provisionFullyManagedDevice(
+ FullyManagedDeviceProvisioningParams provisioningParams) {
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 8a9ec08..12b3f40 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -21,8 +21,11 @@
import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY;
import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
+import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE;
import static android.app.admin.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE;
+import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
+import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
import static android.app.admin.DevicePolicyManager.CODE_ACCOUNTS_NOT_EMPTY;
import static android.app.admin.DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE;
@@ -34,6 +37,7 @@
import static android.app.admin.DevicePolicyManager.CODE_NOT_SYSTEM_USER;
import static android.app.admin.DevicePolicyManager.CODE_NOT_SYSTEM_USER_SPLIT;
import static android.app.admin.DevicePolicyManager.CODE_OK;
+import static android.app.admin.DevicePolicyManager.CODE_PROVISIONING_NOT_ALLOWED_FOR_NON_DEVELOPER_USERS;
import static android.app.admin.DevicePolicyManager.CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER;
import static android.app.admin.DevicePolicyManager.CODE_SYSTEM_USER;
import static android.app.admin.DevicePolicyManager.CODE_USER_HAS_PROFILE_OWNER;
@@ -83,16 +87,25 @@
import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_SET_ERROR_FAILURE_SETTING;
import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_SET_NO_ERROR;
import static android.app.admin.DevicePolicyManager.PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
+import static android.app.admin.DevicePolicyManager.PROVISIONING_RESULT_ADMIN_PACKAGE_INSTALLATION_FAILED;
+import static android.app.admin.DevicePolicyManager.PROVISIONING_RESULT_PRE_CONDITION_FAILED;
+import static android.app.admin.DevicePolicyManager.PROVISIONING_RESULT_PROFILE_CREATION_FAILED;
+import static android.app.admin.DevicePolicyManager.PROVISIONING_RESULT_REMOVE_NON_REQUIRED_APPS_FAILED;
+import static android.app.admin.DevicePolicyManager.PROVISIONING_RESULT_SETTING_PROFILE_OWNER_FAILED;
+import static android.app.admin.DevicePolicyManager.PROVISIONING_RESULT_SET_DEVICE_OWNER_FAILED;
+import static android.app.admin.DevicePolicyManager.PROVISIONING_RESULT_STARTING_PROFILE_FAILED;
import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
import static android.app.admin.DevicePolicyManager.WIPE_SILENTLY;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
+import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
import static android.provider.Telephony.Carriers.DPC_URI;
import static android.provider.Telephony.Carriers.ENFORCE_KEY;
import static android.provider.Telephony.Carriers.ENFORCE_MANAGED_URI;
@@ -109,10 +122,14 @@
import static com.android.server.pm.UserManagerInternal.OWNER_TYPE_PROFILE_OWNER;
import static com.android.server.pm.UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE;
+import android.Manifest;
import android.Manifest.permission;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accounts.Account;
import android.accounts.AccountManager;
+import android.accounts.AccountManagerFuture;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -146,6 +163,8 @@
import android.app.admin.DevicePolicySafetyChecker;
import android.app.admin.DeviceStateCache;
import android.app.admin.FactoryResetProtectionPolicy;
+import android.app.admin.FullyManagedDeviceProvisioningParams;
+import android.app.admin.ManagedProfileProvisioningParams;
import android.app.admin.NetworkEvent;
import android.app.admin.PasswordMetrics;
import android.app.admin.PasswordPolicy;
@@ -267,6 +286,7 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.LocalePicker;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.net.NetworkUtilsInternal;
@@ -325,12 +345,14 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Predicate;
+import java.util.stream.Collectors;
/**
* Implementation of the device policy APIs.
@@ -380,6 +402,8 @@
private static final String NULL_STRING_ARRAY = "nullStringArray";
+ private static final String ALLOW_USER_PROVISIONING_KEY = "ro.config.allowuserprovisioning";
+
// Comprehensive list of delegations.
private static final String DELEGATIONS[] = {
DELEGATION_CERT_INSTALL,
@@ -1231,6 +1255,10 @@
return LocalServices.getService(LockSettingsInternal.class);
}
+ CrossProfileApps getCrossProfileApps() {
+ return mContext.getSystemService(CrossProfileApps.class);
+ }
+
boolean hasUserSetupCompleted(DevicePolicyData userData) {
return userData.mUserSetupComplete;
}
@@ -11327,7 +11355,7 @@
private void showLocationSettingsEnabledNotification(UserHandle user) {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ .addFlags(FLAG_ACTIVITY_NEW_TASK);
// Fill the component explicitly to prevent the PendingIntent from being intercepted
// and fired with crafted target. b/155183624
ActivityInfo targetInfo = intent.resolveActivityInfo(
@@ -12188,7 +12216,7 @@
final Intent intent = new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
intent.putExtra(Intent.EXTRA_USER_ID, userId);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, admin);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
return intent;
}
@@ -12666,6 +12694,9 @@
logMissingFeatureAction("Cannot check provisioning for action " + action);
return CODE_DEVICE_ADMIN_NOT_SUPPORTED;
}
+ if (!isProvisioningAllowed()) {
+ return CODE_PROVISIONING_NOT_ALLOWED_FOR_NON_DEVELOPER_USERS;
+ }
final int code = checkProvisioningPreConditionSkipPermissionNoLog(action, packageName);
if (code != CODE_OK) {
Slog.d(LOG_TAG, "checkProvisioningPreCondition(" + action + ", " + packageName
@@ -12675,6 +12706,23 @@
return code;
}
+ /**
+ * Checks if provisioning is allowed during regular usage (non-developer/CTS). This could
+ * return {@code false} if the device has an overlaid config value set to false. If not set,
+ * the default is true.
+ */
+ private boolean isProvisioningAllowed() {
+ boolean isDeveloperMode = isDeveloperMode(mContext);
+ boolean isProvisioningAllowedForNormalUsers = SystemProperties.getBoolean(
+ ALLOW_USER_PROVISIONING_KEY, /* defValue= */ true);
+
+ return isDeveloperMode || isProvisioningAllowedForNormalUsers;
+ }
+
+ private static boolean isDeveloperMode(Context context) {
+ return Global.getInt(context.getContentResolver(), Global.ADB_ENABLED, 0) > 0;
+ }
+
private int checkProvisioningPreConditionSkipPermissionNoLog(String action,
String packageName) {
final int callingUserId = mInjector.userHandleGetCallingUserId();
@@ -12831,14 +12879,11 @@
callingUserHandle, hasDeviceOwner));
return CODE_CANNOT_ADD_MANAGED_PROFILE;
}
- // If there's a restriction on removing the managed profile then we have to take it
- // into account when checking whether more profiles can be added.
- boolean canRemoveProfile =
- !mUserManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
- callingUserHandle);
- if (!mUserManager.canAddMoreManagedProfiles(callingUserId, canRemoveProfile)) {
- Slog.i(LOG_TAG, String.format(
- "Cannot add more profiles: Can remove current? %b", canRemoveProfile));
+
+ // Bail out if we are trying to provision a work profile but one already exists.
+ if (!mUserManager.canAddMoreManagedProfiles(
+ callingUserId, /* allowedToRemoveOne= */ false)) {
+ Slog.i(LOG_TAG, String.format("A work profile already exists."));
return CODE_CANNOT_ADD_MANAGED_PROFILE;
}
} finally {
@@ -13765,7 +13810,7 @@
}
final Uri packageURI = Uri.parse("package:" + packageName);
final Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageURI);
- uninstallIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ uninstallIntent.setFlags(FLAG_ACTIVITY_NEW_TASK);
mContext.startActivityAsUser(uninstallIntent, UserHandle.of(userId));
}
@@ -15957,4 +16002,415 @@
.setBoolean(isManagedProfile(userId))
.write();
}
+
+ @Override
+ public UserHandle createAndProvisionManagedProfile(
+ @NonNull ManagedProfileProvisioningParams provisioningParams) {
+ final ComponentName admin = provisioningParams.getProfileAdminComponentName();
+ Objects.requireNonNull(admin, "admin is null");
+
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(
+ hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
+
+ UserInfo userInfo = null;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ final int result = checkProvisioningPreConditionSkipPermission(
+ ACTION_PROVISION_MANAGED_PROFILE, admin.getPackageName());
+ if (result != CODE_OK) {
+ throw new ServiceSpecificException(
+ PROVISIONING_RESULT_PRE_CONDITION_FAILED,
+ "Provisioning preconditions failed with result: " + result);
+ }
+
+ final Set<String> nonRequiredApps = provisioningParams.isLeaveAllSystemAppsEnabled()
+ ? Collections.emptySet()
+ : mOverlayPackagesProvider.getNonRequiredApps(
+ admin, caller.getUserId(), ACTION_PROVISION_MANAGED_PROFILE);
+ userInfo = mUserManager.createProfileForUserEvenWhenDisallowed(
+ provisioningParams.getProfileName(),
+ UserManager.USER_TYPE_PROFILE_MANAGED,
+ UserInfo.FLAG_DISABLED,
+ caller.getUserId(),
+ nonRequiredApps.toArray(new String[nonRequiredApps.size()]));
+ if (userInfo == null) {
+ throw new ServiceSpecificException(
+ PROVISIONING_RESULT_PROFILE_CREATION_FAILED,
+ "Error creating profile, createProfileForUserEvenWhenDisallowed "
+ + "returned null.");
+ }
+
+ resetInteractAcrossProfilesAppOps();
+ installExistingAdminPackage(userInfo.id, admin.getPackageName());
+ if (!enableAdminAndSetProfileOwner(
+ userInfo.id, caller.getUserId(), admin, provisioningParams.getOwnerName())) {
+ throw new ServiceSpecificException(
+ PROVISIONING_RESULT_SETTING_PROFILE_OWNER_FAILED,
+ "Error setting profile owner.");
+ }
+ setUserSetupComplete(userInfo.id);
+
+ startUser(userInfo.id);
+ maybeMigrateAccount(
+ userInfo.id, caller.getUserId(), provisioningParams.getAccountToMigrate(),
+ provisioningParams.isKeepAccountMigrated());
+
+ if (provisioningParams.isOrganizationOwnedProvisioning()) {
+ markIsProfileOwnerOnOrganizationOwnedDevice(admin, userInfo.id);
+ restrictRemovalOfManagedProfile(admin, userInfo.id);
+ }
+
+ final Intent intent = new Intent(DevicePolicyManager.ACTION_MANAGED_PROFILE_CREATED)
+ .putExtra(Intent.EXTRA_USER_HANDLE, userInfo.id)
+ .putExtra(
+ DevicePolicyManager.EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED,
+ provisioningParams.isLeaveAllSystemAppsEnabled())
+ .setPackage(getManagedProvisioningPackage(mContext))
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
+
+ return userInfo.getUserHandle();
+ } catch (Exception e) {
+ // in case of any errors during provisioning, remove the newly created profile.
+ if (userInfo != null) {
+ mUserManager.removeUserEvenWhenDisallowed(userInfo.id);
+ }
+ throw e;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ private void resetInteractAcrossProfilesAppOps() {
+ mInjector.getCrossProfileApps().clearInteractAcrossProfilesAppOps();
+ pregrantDefaultInteractAcrossProfilesAppOps();
+ }
+
+ private void pregrantDefaultInteractAcrossProfilesAppOps() {
+ final String op =
+ AppOpsManager.permissionToOp(Manifest.permission.INTERACT_ACROSS_PROFILES);
+ for (String packageName : getConfigurableDefaultCrossProfilePackages()) {
+ if (appOpIsChangedFromDefault(op, packageName)) {
+ continue;
+ }
+ mInjector.getCrossProfileApps().setInteractAcrossProfilesAppOp(
+ packageName, MODE_ALLOWED);
+ }
+ }
+
+ private Set<String> getConfigurableDefaultCrossProfilePackages() {
+ List<String> defaultPackages = getDefaultCrossProfilePackages();
+ return defaultPackages.stream().filter(
+ mInjector.getCrossProfileApps()::canConfigureInteractAcrossProfiles).collect(
+ Collectors.toSet());
+ }
+
+ private boolean appOpIsChangedFromDefault(String op, String packageName) {
+ try {
+ final int uid = mContext.getPackageManager().getPackageUid(
+ packageName, /* flags= */ 0);
+ return mInjector.getAppOpsManager().unsafeCheckOpNoThrow(
+ op, uid, packageName)
+ != AppOpsManager.MODE_DEFAULT;
+ } catch (NameNotFoundException e) {
+ return false;
+ }
+ }
+
+ private void installExistingAdminPackage(int userId, String packageName) {
+ try {
+ final int status = mContext.getPackageManager().installExistingPackageAsUser(
+ packageName,
+ userId);
+ if (status != PackageManager.INSTALL_SUCCEEDED) {
+ throw new ServiceSpecificException(
+ PROVISIONING_RESULT_ADMIN_PACKAGE_INSTALLATION_FAILED,
+ String.format("Failed to install existing package %s for user %d with "
+ + "result code %d",
+ packageName, userId, status));
+ }
+ } catch (NameNotFoundException e) {
+ throw new ServiceSpecificException(
+ PROVISIONING_RESULT_ADMIN_PACKAGE_INSTALLATION_FAILED,
+ String.format("Failed to install existing package %s for user %d: %s",
+ packageName, userId, e.getMessage()));
+ }
+ }
+
+ private boolean enableAdminAndSetProfileOwner(
+ @UserIdInt int userId, @UserIdInt int callingUserId, ComponentName adminComponent,
+ String ownerName) {
+ enableAndSetActiveAdmin(userId, callingUserId, adminComponent);
+ return setProfileOwner(adminComponent, ownerName, userId);
+ }
+
+ private void enableAndSetActiveAdmin(
+ @UserIdInt int userId, @UserIdInt int callingUserId, ComponentName adminComponent) {
+ final String adminPackage = adminComponent.getPackageName();
+ enablePackage(adminPackage, callingUserId);
+ setActiveAdmin(adminComponent, /* refreshing= */ true, userId);
+ }
+
+ private void enablePackage(String packageName, @UserIdInt int userId) {
+ try {
+ final int enabledSetting = mIPackageManager.getApplicationEnabledSetting(
+ packageName, userId);
+ if (enabledSetting != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
+ && enabledSetting != PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
+ mIPackageManager.setApplicationEnabledSetting(
+ packageName,
+ PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
+ // Device policy app may have launched ManagedProvisioning, play nice and
+ // don't kill it as a side-effect of this call.
+ PackageManager.DONT_KILL_APP,
+ userId,
+ mContext.getOpPackageName());
+ }
+ } catch (RemoteException e) {
+ // Shouldn't happen.
+ }
+ }
+
+ private void setUserSetupComplete(@UserIdInt int userId) {
+ Settings.Secure.putIntForUser(
+ mContext.getContentResolver(), USER_SETUP_COMPLETE, 1, userId);
+ }
+
+ private void startUser(@UserIdInt int userId) throws IllegalStateException {
+ final UserUnlockedBlockingReceiver unlockedReceiver = new UserUnlockedBlockingReceiver(
+ userId);
+ mContext.registerReceiverAsUser(
+ unlockedReceiver,
+ new UserHandle(userId),
+ new IntentFilter(Intent.ACTION_USER_UNLOCKED),
+ /* broadcastPermission = */ null,
+ /* scheduler= */ null);
+ try {
+ if (!mInjector.getIActivityManager().startUserInBackground(userId)) {
+ throw new ServiceSpecificException(PROVISIONING_RESULT_STARTING_PROFILE_FAILED,
+ String.format("Unable to start user %d in background", userId));
+ }
+
+ if (!unlockedReceiver.waitForUserUnlocked()) {
+ throw new ServiceSpecificException(PROVISIONING_RESULT_STARTING_PROFILE_FAILED,
+ String.format("Timeout whilst waiting for unlock of user %d.", userId));
+ }
+ } catch (RemoteException e) {
+ // Shouldn't happen.
+ } finally {
+ mContext.unregisterReceiver(unlockedReceiver);
+ }
+ }
+
+ void maybeMigrateAccount(
+ @UserIdInt int targetUserId, @UserIdInt int sourceUserId, Account accountToMigrate,
+ boolean keepAccountMigrated) {
+ final UserHandle sourceUser = UserHandle.of(sourceUserId);
+ final UserHandle targetUser = UserHandle.of(targetUserId);
+ if (accountToMigrate == null) {
+ Slog.d(LOG_TAG, "No account to migrate.");
+ return;
+ }
+ if (sourceUser.equals(targetUser)) {
+ Slog.w(LOG_TAG, "sourceUser and targetUser are the same, won't migrate account.");
+ return;
+ }
+ copyAccount(targetUser, sourceUser, accountToMigrate);
+ if (!keepAccountMigrated) {
+ removeAccount(accountToMigrate);
+ }
+ }
+
+ void copyAccount(UserHandle targetUser, UserHandle sourceUser, Account accountToMigrate) {
+ try {
+ final AccountManager accountManager = mContext.getSystemService(AccountManager.class);
+ final boolean copySucceeded = accountManager.copyAccountToUser(
+ accountToMigrate,
+ sourceUser,
+ targetUser,
+ /* callback= */ null, /* handler= */ null)
+ .getResult(60 * 3, TimeUnit.SECONDS);
+ if (!copySucceeded) {
+ Slog.e(LOG_TAG, "Failed to copy account to " + targetUser);
+ }
+ } catch (OperationCanceledException | AuthenticatorException | IOException e) {
+ // Account migration is not considered a critical operation.
+ Slog.e(LOG_TAG, "Exception copying account to " + targetUser, e);
+ }
+ }
+
+ void removeAccount(Account account) {
+ final AccountManager accountManager =
+ mContext.getSystemService(AccountManager.class);
+ final AccountManagerFuture<Bundle> bundle = accountManager.removeAccount(account,
+ null, null /* callback */, null /* handler */);
+ try {
+ final Bundle result = bundle.getResult();
+ if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, /* default */ false)) {
+ Slog.i(LOG_TAG, "Account removed from the primary user.");
+ } else {
+ // TODO(174768447): Revisit start activity logic.
+ final Intent removeIntent = result.getParcelable(AccountManager.KEY_INTENT);
+ removeIntent.addFlags(FLAG_ACTIVITY_NEW_TASK);
+ if (removeIntent != null) {
+ Slog.i(LOG_TAG, "Starting activity to remove account");
+ new Handler(Looper.getMainLooper()).post(() -> {
+ mContext.startActivity(removeIntent);
+ });
+ } else {
+ Slog.e(LOG_TAG, "Could not remove account from the primary user.");
+ }
+ }
+ } catch (OperationCanceledException | AuthenticatorException | IOException e) {
+ Slog.e(LOG_TAG, "Exception removing account from the primary user.", e);
+ }
+ }
+
+ private void markIsProfileOwnerOnOrganizationOwnedDevice(
+ ComponentName admin, @UserIdInt int profileId) {
+ getDpmForProfile(profileId).markProfileOwnerOnOrganizationOwnedDevice(admin);
+ }
+
+ private void restrictRemovalOfManagedProfile(
+ ComponentName admin, @UserIdInt int profileId) {
+ getDpmForProfile(profileId).addUserRestriction(
+ admin, UserManager.DISALLOW_REMOVE_MANAGED_PROFILE);
+ }
+
+ private DevicePolicyManager getDpmForProfile(@UserIdInt int profileId) {
+ final Context profileContext = mContext.createContextAsUser(
+ UserHandle.of(profileId), /* flags= */ 0);
+ return profileContext.getSystemService(DevicePolicyManager.class);
+ }
+
+ @Override
+ public void provisionFullyManagedDevice(
+ FullyManagedDeviceProvisioningParams provisioningParams) {
+ ComponentName deviceAdmin = provisioningParams.getDeviceAdminComponentName();
+
+ Objects.requireNonNull(deviceAdmin, "admin is null.");
+ Objects.requireNonNull(provisioningParams.getOwnerName(), "owner name is null.");
+
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(
+ hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ int result = checkProvisioningPreConditionSkipPermission(
+ ACTION_PROVISION_MANAGED_DEVICE, deviceAdmin.getPackageName());
+ if (result != CODE_OK) {
+ throw new ServiceSpecificException(
+ PROVISIONING_RESULT_PRE_CONDITION_FAILED,
+ "Provisioning preconditions failed with result: " + result);
+ }
+
+ setTimeAndTimezone(provisioningParams.getTimeZone(), provisioningParams.getLocalTime());
+ setLocale(provisioningParams.getLocale());
+
+ if (!removeNonRequiredAppsForManagedDevice(
+ caller.getUserId(),
+ provisioningParams.isLeaveAllSystemAppsEnabled(),
+ deviceAdmin)) {
+ throw new ServiceSpecificException(
+ PROVISIONING_RESULT_REMOVE_NON_REQUIRED_APPS_FAILED,
+ "PackageManager failed to remove non required apps.");
+ }
+
+ if (!setActiveAdminAndDeviceOwner(
+ caller.getUserId(), deviceAdmin, provisioningParams.getOwnerName())) {
+ throw new ServiceSpecificException(
+ PROVISIONING_RESULT_SET_DEVICE_OWNER_FAILED,
+ "Failed to set device owner.");
+ }
+
+ disallowAddUser();
+
+ final Intent intent = new Intent(DevicePolicyManager.ACTION_PROVISIONED_MANAGED_DEVICE)
+ .putExtra(Intent.EXTRA_USER_HANDLE, caller.getUserId())
+ .putExtra(
+ DevicePolicyManager.EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED,
+ provisioningParams.isLeaveAllSystemAppsEnabled())
+ .setPackage(getManagedProvisioningPackage(mContext))
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ private void setTimeAndTimezone(String timeZone, long localTime) {
+ try {
+ final AlarmManager alarmManager = mContext.getSystemService(AlarmManager.class);
+ if (timeZone != null) {
+ alarmManager.setTimeZone(timeZone);
+ }
+ if (localTime > 0) {
+ alarmManager.setTime(localTime);
+ }
+ } catch (Exception e) {
+ // Do not stop provisioning and ignore this error.
+ Slog.e(LOG_TAG, "Alarm manager failed to set the system time/timezone.", e);
+ }
+ }
+
+ private void setLocale(Locale locale) {
+ if (locale == null || locale.equals(Locale.getDefault())) {
+ return;
+ }
+ try {
+ // If locale is different from current locale this results in a configuration change,
+ // which will trigger the restarting of the activity.
+ LocalePicker.updateLocale(locale);
+ } catch (Exception e) {
+ // Do not stop provisioning and ignore this error.
+ Slog.e(LOG_TAG, "Failed to set the system locale.", e);
+ }
+ }
+
+ private boolean removeNonRequiredAppsForManagedDevice(
+ int userId, boolean leaveAllSystemAppsEnabled, ComponentName admin) {
+ Set<String> packagesToDelete = leaveAllSystemAppsEnabled
+ ? Collections.emptySet()
+ : mOverlayPackagesProvider.getNonRequiredApps(
+ admin, userId, ACTION_PROVISION_MANAGED_DEVICE);
+ if (packagesToDelete.isEmpty()) {
+ return true;
+ }
+ NonRequiredPackageDeleteObserver packageDeleteObserver =
+ new NonRequiredPackageDeleteObserver(packagesToDelete.size());
+ for (String packageName : packagesToDelete) {
+ if (isPackageInstalledForUser(packageName, userId)) {
+ Slog.i(LOG_TAG, "Deleting package [" + packageName + "] as user " + userId);
+ mContext.getPackageManager().deletePackageAsUser(
+ packageName,
+ packageDeleteObserver,
+ PackageManager.DELETE_SYSTEM_APP,
+ userId);
+ }
+ }
+ Slog.i(LOG_TAG, "Waiting for non required apps to be deleted");
+ return packageDeleteObserver.awaitPackagesDeletion();
+ }
+
+ private void disallowAddUser() {
+ if (mInjector.userManagerIsHeadlessSystemUserMode()) {
+ Slog.i(LOG_TAG, "Not setting DISALLOW_ADD_USER on headless system user mode.");
+ return;
+ }
+ for (UserInfo userInfo : mUserManager.getUsers()) {
+ UserHandle userHandle = userInfo.getUserHandle();
+ if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER, userHandle)) {
+ mUserManager.setUserRestriction(
+ UserManager.DISALLOW_ADD_USER, /* value= */ true, userHandle);
+ }
+ }
+ }
+
+ private boolean setActiveAdminAndDeviceOwner(
+ @UserIdInt int userId, ComponentName adminComponent, String name) {
+ enableAndSetActiveAdmin(userId, userId, adminComponent);
+ return setDeviceOwner(adminComponent, name, userId);
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NonRequiredPackageDeleteObserver.java b/services/devicepolicy/java/com/android/server/devicepolicy/NonRequiredPackageDeleteObserver.java
new file mode 100644
index 0000000..0e448cd
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/NonRequiredPackageDeleteObserver.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.devicepolicy;
+
+import static com.android.server.devicepolicy.DevicePolicyManagerService.LOG_TAG;
+
+import android.content.pm.IPackageDeleteObserver;
+import android.content.pm.PackageManager;
+import android.util.Log;
+import android.util.Slog;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Awaits the deletion of all the non-required apps.
+ */
+final class NonRequiredPackageDeleteObserver extends IPackageDeleteObserver.Stub {
+ private static final int PACKAGE_DELETE_TIMEOUT_SEC = 30;
+
+ private final AtomicInteger mPackageCount = new AtomicInteger(/* initialValue= */ 0);
+ private final CountDownLatch mLatch;
+ private boolean mSuccess;
+
+ NonRequiredPackageDeleteObserver(int packageCount) {
+ this.mLatch = new CountDownLatch(packageCount);
+ this.mPackageCount.set(packageCount);
+ }
+
+ @Override
+ public void packageDeleted(String packageName, int returnCode) {
+ if (returnCode != PackageManager.DELETE_SUCCEEDED) {
+ Slog.e(LOG_TAG, "Failed to delete package: " + packageName);
+ mLatch.notifyAll();
+ return;
+ }
+ int currentPackageCount = mPackageCount.decrementAndGet();
+ if (currentPackageCount == 0) {
+ mSuccess = true;
+ Slog.i(LOG_TAG, "All non-required system apps with launcher icon, "
+ + "and all disallowed apps have been uninstalled.");
+ }
+ mLatch.countDown();
+ }
+
+ public boolean awaitPackagesDeletion() {
+ try {
+ mLatch.await(PACKAGE_DELETE_TIMEOUT_SEC, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ Log.w(LOG_TAG, "Interrupted while waiting for package deletion", e);
+ Thread.currentThread().interrupt();
+ }
+ return mSuccess;
+ }
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/UserUnlockedBlockingReceiver.java b/services/devicepolicy/java/com/android/server/devicepolicy/UserUnlockedBlockingReceiver.java
new file mode 100644
index 0000000..4ce96b7
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/UserUnlockedBlockingReceiver.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.devicepolicy;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.UserHandle;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * BroadcastReceiver that listens to {@link Intent#ACTION_USER_UNLOCKED} in order to provide
+ * a blocking wait until the managed profile has been started and unlocked.
+ */
+class UserUnlockedBlockingReceiver extends BroadcastReceiver {
+ private static final int WAIT_FOR_USER_UNLOCKED_TIMEOUT_SECONDS = 120;
+
+ private final Semaphore mSemaphore = new Semaphore(0);
+ private final int mUserId;
+
+ UserUnlockedBlockingReceiver(int userId) {
+ mUserId = userId;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
+ return;
+ }
+ if (intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL) == mUserId) {
+ mSemaphore.release();
+ }
+ }
+
+ public boolean waitForUserUnlocked() {
+ try {
+ return mSemaphore.tryAcquire(
+ WAIT_FOR_USER_UNLOCKED_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ } catch (InterruptedException ie) {
+ return false;
+ }
+ }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 57b3e8d..c613dfb 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -323,6 +323,8 @@
"com.android.server.timezonedetector.TimeZoneDetectorService$Lifecycle";
private static final String LOCATION_TIME_ZONE_MANAGER_SERVICE_CLASS =
"com.android.server.location.timezone.LocationTimeZoneManagerService$Lifecycle";
+ private static final String GNSS_TIME_UPDATE_SERVICE_CLASS =
+ "com.android.server.timedetector.GnssTimeUpdateService$Lifecycle";
private static final String ACCESSIBILITY_MANAGER_SERVICE_CLASS =
"com.android.server.accessibility.AccessibilityManagerService$Lifecycle";
private static final String ADB_SERVICE_CLASS =
@@ -1874,6 +1876,16 @@
}
t.traceEnd();
+ if (context.getResources().getBoolean(R.bool.config_enableGnssTimeUpdateService)) {
+ t.traceBegin("StartGnssTimeUpdateService");
+ try {
+ mSystemServiceManager.startService(GNSS_TIME_UPDATE_SERVICE_CLASS);
+ } catch (Throwable e) {
+ reportWtf("starting GnssTimeUpdateService service", e);
+ }
+ t.traceEnd();
+ }
+
if (!isWatch) {
t.traceBegin("StartSearchManagerService");
try {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
index c038a0f..28a6ff7 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
@@ -124,7 +124,7 @@
private Context mContext;
FullScreenMagnificationController mFullScreenMagnificationController;
@Mock
- MagnificationGestureHandler.ScaleChangedListener mMockScaleChangedListener;
+ MagnificationGestureHandler.Callback mMockCallback;
@Mock
MagnificationRequestObserver mMagnificationRequestObserver;
@Mock
@@ -179,7 +179,7 @@
private FullScreenMagnificationGestureHandler newInstance(boolean detectTripleTap,
boolean detectShortcutTrigger) {
FullScreenMagnificationGestureHandler h = new FullScreenMagnificationGestureHandler(
- mContext, mFullScreenMagnificationController, mMockScaleChangedListener,
+ mContext, mFullScreenMagnificationController, mMockCallback,
detectTripleTap, detectShortcutTrigger,
mWindowMagnificationPromptController, DISPLAY_0);
mHandler = new TestHandler(h.mDetectingState, mClock) {
@@ -451,6 +451,14 @@
verify(mWindowMagnificationPromptController).showNotificationIfNeeded();
}
+ @Test
+ public void testZoomedWithTripleTap_callsOnTripleTapped() {
+ goFromStateIdleTo(STATE_ZOOMED_2TAPS);
+
+ verify(mMockCallback).onTripleTapped(DISPLAY_0,
+ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+ }
+
private void assertActionsInOrder(List<MotionEvent> actualEvents,
List<Integer> expectedActions) {
assertTrue(actualEvents.size() == expectedActions.size());
@@ -554,8 +562,6 @@
check(mMgh.mCurrentState == mMgh.mPanningScalingState,
state);
check(mMgh.mPanningScalingState.mScaling, state);
- verify(mMockScaleChangedListener).onMagnificationScaleChanged(DISPLAY_0,
- Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
} break;
default: throw new IllegalArgumentException("Illegal state: " + state);
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
index cba618b..0c3640c 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
@@ -109,6 +109,8 @@
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
mMagnificationController = spy(new MagnificationController(mService, new Object(), mContext,
mScreenMagnificationController, mWindowMagnificationManager));
+ mMagnificationController.setMagnificationCapabilities(
+ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL);
}
@After
@@ -278,34 +280,128 @@
verify(mWindowMagnificationManager).setScale(eq(TEST_DISPLAY), eq(newScale));
verify(mWindowMagnificationManager).persistScale(eq(TEST_DISPLAY));
- verify(mMagnificationController).onMagnificationScaleChanged(eq(TEST_DISPLAY),
- eq(MODE_WINDOW));
}
@Test
- public void onMagnificationScaleChanged_capabilitiesAllMode_showMagnificationButton()
+ public void onTouchInteractionStart_fullScreenAndCapabilitiesAll_showMagnificationButton()
throws RemoteException {
- mMagnificationController.setMagnificationCapabilities(
- Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL);
+ setMagnificationEnabled(MODE_FULLSCREEN);
- mMagnificationController.onMagnificationScaleChanged(TEST_DISPLAY, MODE_WINDOW);
+ mMagnificationController.onTouchInteractionStart(TEST_DISPLAY, MODE_FULLSCREEN);
+
+ verify(mWindowMagnificationManager).showMagnificationButton(eq(TEST_DISPLAY),
+ eq(MODE_FULLSCREEN));
+ }
+
+ @Test
+ public void onTouchInteractionEnd_fullScreenAndCapabilitiesAll_showMagnificationButton()
+ throws RemoteException {
+ setMagnificationEnabled(MODE_FULLSCREEN);
+
+ mMagnificationController.onTouchInteractionEnd(TEST_DISPLAY, MODE_FULLSCREEN);
+
+ verify(mWindowMagnificationManager).showMagnificationButton(eq(TEST_DISPLAY),
+ eq(MODE_FULLSCREEN));
+ }
+
+ @Test
+ public void onTouchInteractionStart_windowModeAndCapabilitiesAll_showMagnificationButton()
+ throws RemoteException {
+ setMagnificationEnabled(MODE_WINDOW);
+
+ mMagnificationController.onTouchInteractionStart(TEST_DISPLAY, MODE_WINDOW);
verify(mWindowMagnificationManager).showMagnificationButton(eq(TEST_DISPLAY),
eq(MODE_WINDOW));
}
@Test
- public void onMagnificationScaleChanged_capabilitiesNotAllMode_notShowMagnificationButton()
+ public void onTouchInteractionEnd_windowModeAndCapabilitiesAll_showMagnificationButton()
+ throws RemoteException {
+ setMagnificationEnabled(MODE_WINDOW);
+
+ mMagnificationController.onTouchInteractionEnd(TEST_DISPLAY, MODE_WINDOW);
+
+ verify(mWindowMagnificationManager).showMagnificationButton(eq(TEST_DISPLAY),
+ eq(MODE_WINDOW));
+ }
+
+ @Test
+ public void onTouchInteractionChanged_notCapabilitiesAll_notShowMagnificationButton()
throws RemoteException {
mMagnificationController.setMagnificationCapabilities(
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+ setMagnificationEnabled(MODE_FULLSCREEN);
- mMagnificationController.onMagnificationScaleChanged(TEST_DISPLAY, MODE_WINDOW);
+ mMagnificationController.onTouchInteractionStart(TEST_DISPLAY, MODE_FULLSCREEN);
+ mMagnificationController.onTouchInteractionEnd(TEST_DISPLAY, MODE_FULLSCREEN);
verify(mWindowMagnificationManager, never()).showMagnificationButton(eq(TEST_DISPLAY),
+ eq(MODE_FULLSCREEN));
+ }
+
+ @Test
+ public void onShortcutTriggered_windowModeEnabledAndCapabilitiesAll_showMagnificationButton()
+ throws RemoteException {
+ setMagnificationEnabled(MODE_WINDOW);
+
+ mMagnificationController.onShortcutTriggered(TEST_DISPLAY, MODE_WINDOW);
+
+ verify(mWindowMagnificationManager).showMagnificationButton(eq(TEST_DISPLAY),
eq(MODE_WINDOW));
}
+ @Test
+ public void onShortcutTriggered_fullscreenEnabledAndCapabilitiesAll_showMagnificationButton()
+ throws RemoteException {
+ setMagnificationEnabled(MODE_FULLSCREEN);
+
+ mMagnificationController.onShortcutTriggered(TEST_DISPLAY, MODE_FULLSCREEN);
+
+ verify(mWindowMagnificationManager).showMagnificationButton(eq(TEST_DISPLAY),
+ eq(MODE_FULLSCREEN));
+ }
+
+ @Test
+ public void onShortcutTriggered_windowModeDisabled_removeMagnificationButton()
+ throws RemoteException {
+
+ mMagnificationController.onShortcutTriggered(TEST_DISPLAY, MODE_WINDOW);
+
+ verify(mWindowMagnificationManager).removeMagnificationButton(eq(TEST_DISPLAY));
+ }
+
+ @Test
+ public void onTripleTap_windowModeEnabledAndCapabilitiesAll_showMagnificationButton()
+ throws RemoteException {
+ setMagnificationEnabled(MODE_WINDOW);
+
+ mMagnificationController.onTripleTapped(TEST_DISPLAY, MODE_WINDOW);
+
+ verify(mWindowMagnificationManager).showMagnificationButton(eq(TEST_DISPLAY),
+ eq(MODE_WINDOW));
+ }
+
+ @Test
+ public void onTripleTap_fullscreenEnabledAndCapabilitiesAll_showMagnificationButton()
+ throws RemoteException {
+ setMagnificationEnabled(MODE_FULLSCREEN);
+
+ mMagnificationController.onTripleTapped(TEST_DISPLAY, MODE_FULLSCREEN);
+
+ verify(mWindowMagnificationManager).showMagnificationButton(eq(TEST_DISPLAY),
+ eq(MODE_FULLSCREEN));
+ }
+
+ @Test
+ public void onTripleTap_windowModeDisabled_removeMagnificationButton()
+ throws RemoteException {
+
+ mMagnificationController.onTripleTapped(TEST_DISPLAY, MODE_WINDOW);
+
+ verify(mWindowMagnificationManager).removeMagnificationButton(eq(TEST_DISPLAY));
+ }
+
private void setMagnificationEnabled(int mode) throws RemoteException {
setMagnificationEnabled(mode, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationGestureHandlerTest.java
new file mode 100644
index 0000000..514d16a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationGestureHandlerTest.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.accessibility.magnification;
+
+import static android.view.MotionEvent.ACTION_CANCEL;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_UP;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.testng.AssertJUnit.assertTrue;
+
+import android.annotation.NonNull;
+import android.provider.Settings;
+import android.view.InputDevice;
+import android.view.MotionEvent;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for {@link MagnificationGestureHandler}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class MagnificationGestureHandlerTest {
+
+ private TestMagnificationGestureHandler mMgh;
+ private static final int DISPLAY_0 = 0;
+ private static final int FULLSCREEN_MODE =
+ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
+
+ @Mock
+ MagnificationGestureHandler.Callback mCallback;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mMgh = new TestMagnificationGestureHandler(DISPLAY_0,
+ /* detectTripleTap= */true,
+ /* detectShortcutTrigger= */true,
+ mCallback);
+ }
+
+ @Test
+ public void onMotionEvent_isFromScreen_onMotionEventInternal() {
+ final MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
+ downEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN);
+
+ mMgh.onMotionEvent(downEvent, downEvent, /* policyFlags= */ 0);
+
+ try {
+ assertTrue(mMgh.mIsInternalMethodCalled);
+ } finally {
+ downEvent.recycle();
+ }
+ }
+
+ @Test
+ public void onMotionEvent_downEvent_handleInteractionStart() {
+ final MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
+ downEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN);
+
+ mMgh.onMotionEvent(downEvent, downEvent, /* policyFlags= */ 0);
+
+ try {
+ verify(mCallback).onTouchInteractionStart(eq(DISPLAY_0), eq(mMgh.getMode()));
+ } finally {
+ downEvent.recycle();
+ }
+ }
+
+ @Test
+ public void onMotionEvent_upEvent_handleInteractionEnd() {
+ final MotionEvent upEvent = MotionEvent.obtain(0, 0, ACTION_UP, 0, 0, 0);
+ upEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN);
+
+ mMgh.onMotionEvent(upEvent, upEvent, /* policyFlags= */ 0);
+
+ try {
+ verify(mCallback).onTouchInteractionEnd(eq(DISPLAY_0), eq(mMgh.getMode()));
+ } finally {
+ upEvent.recycle();
+ }
+ }
+
+ @Test
+ public void onMotionEvent_cancelEvent_handleInteractionEnd() {
+ final MotionEvent cancelEvent = MotionEvent.obtain(0, 0, ACTION_CANCEL, 0, 0, 0);
+ cancelEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN);
+
+ mMgh.onMotionEvent(cancelEvent, cancelEvent, /* policyFlags= */ 0);
+
+ try {
+ verify(mCallback).onTouchInteractionEnd(eq(DISPLAY_0), eq(mMgh.getMode()));
+ } finally {
+ cancelEvent.recycle();
+ }
+ }
+
+
+ @Test
+ public void notifyShortcutTriggered_callsOnShortcutTriggered() {
+ mMgh.notifyShortcutTriggered();
+
+ verify(mCallback).onShortcutTriggered(eq(DISPLAY_0), eq(mMgh.getMode()));
+ }
+
+ private static class TestMagnificationGestureHandler extends MagnificationGestureHandler {
+
+ boolean mIsInternalMethodCalled = false;
+
+ TestMagnificationGestureHandler(int displayId, boolean detectTripleTap,
+ boolean detectShortcutTrigger, @NonNull Callback callback) {
+ super(displayId, detectTripleTap, detectShortcutTrigger, callback);
+ }
+
+ @Override
+ void onMotionEventInternal(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ mIsInternalMethodCalled = true;
+ }
+
+ @Override
+ public void notifyShortcutTriggered() {
+ super.notifyShortcutTriggered();
+ }
+
+ @Override
+ public void handleShortcutTriggered() {
+ }
+
+ @Override
+ public int getMode() {
+ return FULLSCREEN_MODE;
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
index 9f930da..4b7ebbc 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
@@ -19,7 +19,9 @@
import static com.android.server.testutils.TestUtils.strictMock;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import android.content.Context;
import android.graphics.Rect;
@@ -38,6 +40,8 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.util.function.IntConsumer;
@@ -48,7 +52,7 @@
public class WindowMagnificationGestureHandlerTest {
public static final int STATE_IDLE = 1;
- public static final int STATE_SHOW_MAGNIFIER = 2;
+ public static final int STATE_SHOW_MAGNIFIER_SHORTCUT = 2;
public static final int STATE_TWO_FINGERS_DOWN = 3;
public static final int STATE_SHOW_MAGNIFIER_TRIPLE_TAP = 4;
//TODO: Test it after can injecting Handler to GestureMatcher is available.
@@ -65,16 +69,18 @@
private WindowMagnificationManager mWindowMagnificationManager;
private MockWindowMagnificationConnection mMockConnection;
private WindowMagnificationGestureHandler mWindowMagnificationGestureHandler;
+ @Mock
+ MagnificationGestureHandler.Callback mMockCallback;
@Before
public void setUp() throws RemoteException {
+ MockitoAnnotations.initMocks(this);
mContext = InstrumentationRegistry.getContext();
mWindowMagnificationManager = new WindowMagnificationManager(mContext, 0,
mock(WindowMagnificationManager.Callback.class));
mMockConnection = new MockWindowMagnificationConnection();
mWindowMagnificationGestureHandler = new WindowMagnificationGestureHandler(
- mContext, mWindowMagnificationManager, mock(
- MagnificationGestureHandler.ScaleChangedListener.class),
+ mContext, mWindowMagnificationManager, mMockCallback,
/** detectTripleTap= */true, /** detectShortcutTrigger= */true, DISPLAY_0);
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
mWindowMagnificationGestureHandler.setNext(strictMock(EventStreamTransformation.class));
@@ -140,6 +146,14 @@
});
}
+ @Test
+ public void onTripleTap_callsOnTripleTapped() {
+ goFromStateIdleTo(STATE_SHOW_MAGNIFIER_TRIPLE_TAP);
+
+ verify(mMockCallback).onTripleTapped(eq(DISPLAY_0),
+ eq(mWindowMagnificationGestureHandler.getMode()));
+ }
+
private void forEachState(IntConsumer action) {
for (int state = FIRST_STATE; state <= LAST_STATE; state++) {
action.accept(state);
@@ -159,7 +173,7 @@
== mWindowMagnificationGestureHandler.mDetectingState, state);
}
break;
- case STATE_SHOW_MAGNIFIER:
+ case STATE_SHOW_MAGNIFIER_SHORTCUT:
case STATE_SHOW_MAGNIFIER_TRIPLE_TAP: {
check(isWindowMagnifierEnabled(DISPLAY_0), state);
check(mWindowMagnificationGestureHandler.mCurrentState
@@ -188,12 +202,12 @@
// no op
}
break;
- case STATE_SHOW_MAGNIFIER: {
+ case STATE_SHOW_MAGNIFIER_SHORTCUT: {
triggerShortcut();
}
break;
case STATE_TWO_FINGERS_DOWN: {
- goFromStateIdleTo(STATE_SHOW_MAGNIFIER);
+ goFromStateIdleTo(STATE_SHOW_MAGNIFIER_SHORTCUT);
final Rect frame = mMockConnection.getMirrorWindowFrame();
send(downEvent(frame.centerX(), frame.centerY()));
//Second finger is outside the window.
@@ -225,14 +239,14 @@
// no op
}
break;
- case STATE_SHOW_MAGNIFIER: {
+ case STATE_SHOW_MAGNIFIER_SHORTCUT: {
mWindowMagnificationManager.disableWindowMagnification(DISPLAY_0, false);
}
break;
case STATE_TWO_FINGERS_DOWN: {
final Rect frame = mMockConnection.getMirrorWindowFrame();
send(upEvent(frame.centerX(), frame.centerY()));
- returnToNormalFrom(STATE_SHOW_MAGNIFIER);
+ returnToNormalFrom(STATE_SHOW_MAGNIFIER_SHORTCUT);
}
break;
case STATE_SHOW_MAGNIFIER_TRIPLE_TAP: {
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java b/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java
new file mode 100644
index 0000000..b5f4912
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java
@@ -0,0 +1,426 @@
+/*
+ * 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.
+ */
+
+// TODO(b/169883602): This is purposely a different package from the path so that it can access
+// AppSearchImpl's methods without having to make them public. This should be replaced by proper
+// global query integration tests that can test AppSearchImpl-VisibilityStore integration logic.
+package com.android.server.appsearch.external.localstorage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.appsearch.AppSearchSchema;
+import android.app.appsearch.GenericDocument;
+import android.app.appsearch.PackageIdentifier;
+import android.app.appsearch.SearchResultPage;
+import android.app.appsearch.SearchSpec;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.pm.PackageManager;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.util.Collections;
+import java.util.List;
+
+/** This tests AppSearchImpl when it's running with a platform-backed VisibilityStore. */
+public class AppSearchImplPlatformTest {
+ @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+ private MockPackageManager mMockPackageManager = new MockPackageManager();
+ private Context mContext;
+ private AppSearchImpl mAppSearchImpl;
+ private int mGlobalQuerierUid;
+
+ @Before
+ public void setUp() throws Exception {
+ Context context = ApplicationProvider.getApplicationContext();
+ mContext =
+ new ContextWrapper(context) {
+ @Override
+ public PackageManager getPackageManager() {
+ return mMockPackageManager.getMockPackageManager();
+ }
+ };
+
+ // Give ourselves global query permissions
+ mAppSearchImpl =
+ AppSearchImpl.create(
+ mTemporaryFolder.newFolder(),
+ mContext,
+ mContext.getUserId(),
+ mContext.getPackageName());
+ mGlobalQuerierUid =
+ mContext.getPackageManager().getPackageUid(mContext.getPackageName(), /*flags=*/ 0);
+ }
+ /**
+ * TODO(b/169883602): This should be an integration test at the cts-level. This is a short-term
+ * test until we have official support for multiple-apps indexing at once.
+ */
+ @Test
+ public void testGlobalQueryWithMultiplePackages_noPackageFilters() throws Exception {
+ // Insert package1 schema
+ List<AppSearchSchema> schema1 =
+ ImmutableList.of(new AppSearchSchema.Builder("schema1").build());
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database1",
+ schema1,
+ /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+ /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false);
+
+ // Insert package2 schema
+ List<AppSearchSchema> schema2 =
+ ImmutableList.of(new AppSearchSchema.Builder("schema2").build());
+ mAppSearchImpl.setSchema(
+ "package2",
+ "database2",
+ schema2,
+ /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+ /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false);
+
+ // Insert package1 document
+ GenericDocument document1 =
+ new GenericDocument.Builder<>("uri", "schema1").setNamespace("namespace").build();
+ mAppSearchImpl.putDocument("package1", "database1", document1);
+
+ // Insert package2 document
+ GenericDocument document2 =
+ new GenericDocument.Builder<>("uri", "schema2").setNamespace("namespace").build();
+ mAppSearchImpl.putDocument("package2", "database2", document2);
+
+ // No query filters specified, global query can retrieve all documents.
+ SearchSpec searchSpec =
+ new SearchSpec.Builder().setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY).build();
+ SearchResultPage searchResultPage =
+ mAppSearchImpl.globalQuery(
+ "", searchSpec, mContext.getPackageName(), mGlobalQuerierUid);
+ assertThat(searchResultPage.getResults()).hasSize(2);
+
+ // Document2 will be first since it got indexed later and has a "better", aka more recent
+ // score.
+ assertThat(searchResultPage.getResults().get(0).getDocument()).isEqualTo(document2);
+ assertThat(searchResultPage.getResults().get(1).getDocument()).isEqualTo(document1);
+ }
+
+ /**
+ * TODO(b/169883602): This should be an integration test at the cts-level. This is a short-term
+ * test until we have official support for multiple-apps indexing at once.
+ */
+ @Test
+ public void testGlobalQueryWithMultiplePackages_withPackageFilters() throws Exception {
+ // Insert package1 schema
+ List<AppSearchSchema> schema1 =
+ ImmutableList.of(new AppSearchSchema.Builder("schema1").build());
+ mAppSearchImpl.setSchema(
+ "package1",
+ "database1",
+ schema1,
+ /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+ /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false);
+
+ // Insert package2 schema
+ List<AppSearchSchema> schema2 =
+ ImmutableList.of(new AppSearchSchema.Builder("schema2").build());
+ mAppSearchImpl.setSchema(
+ "package2",
+ "database2",
+ schema2,
+ /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+ /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false);
+
+ // Insert package1 document
+ GenericDocument document1 =
+ new GenericDocument.Builder<>("uri", "schema1").setNamespace("namespace").build();
+ mAppSearchImpl.putDocument("package1", "database1", document1);
+
+ // Insert package2 document
+ GenericDocument document2 =
+ new GenericDocument.Builder<>("uri", "schema2").setNamespace("namespace").build();
+ mAppSearchImpl.putDocument("package2", "database2", document2);
+
+ // "package1" filter specified
+ SearchSpec searchSpec =
+ new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
+ .addFilterPackageNames("package1")
+ .build();
+ SearchResultPage searchResultPage =
+ mAppSearchImpl.globalQuery(
+ "", searchSpec, mContext.getPackageName(), mGlobalQuerierUid);
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getDocument()).isEqualTo(document1);
+
+ // "package2" filter specified
+ searchSpec =
+ new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
+ .addFilterPackageNames("package2")
+ .build();
+ searchResultPage =
+ mAppSearchImpl.globalQuery(
+ "", searchSpec, mContext.getPackageName(), mGlobalQuerierUid);
+ assertThat(searchResultPage.getResults()).hasSize(1);
+ assertThat(searchResultPage.getResults().get(0).getDocument()).isEqualTo(document2);
+ }
+
+ @Test
+ public void testSetSchema_existingSchemaRetainsVisibilitySetting() throws Exception {
+ // Values for a "foo" client
+ String packageNameFoo = "packageFoo";
+ byte[] sha256CertFoo = new byte[] {10};
+ int uidFoo = 1;
+
+ // Make sure foo package will pass package manager checks.
+ mMockPackageManager.mockGetPackageUidAsUser(packageNameFoo, mContext.getUserId(), uidFoo);
+ mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
+
+ // Set schema1
+ String prefix = AppSearchImpl.createPrefix("package", "database");
+ mAppSearchImpl.setSchema(
+ "package",
+ "database",
+ Collections.singletonList(new AppSearchSchema.Builder("schema1").build()),
+ /*schemasNotPlatformSurfaceable=*/ Collections.singletonList("schema1"),
+ /*schemasPackageAccessible=*/ ImmutableMap.of(
+ "schema1",
+ ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))),
+ /*forceOverride=*/ false);
+
+ // "schema1" is platform hidden now and package visible to package1
+ assertThat(
+ mAppSearchImpl
+ .getVisibilityStoreLocked()
+ .isSchemaSearchableByCaller(
+ prefix, prefix + "schema1", mGlobalQuerierUid))
+ .isFalse();
+ assertThat(
+ mAppSearchImpl
+ .getVisibilityStoreLocked()
+ .isSchemaSearchableByCaller(prefix, prefix + "schema1", uidFoo))
+ .isTrue();
+
+ // Add a new schema, and include the already-existing "schema1"
+ mAppSearchImpl.setSchema(
+ "package",
+ "database",
+ ImmutableList.of(
+ new AppSearchSchema.Builder("schema1").build(),
+ new AppSearchSchema.Builder("schema2").build()),
+ /*schemasNotPlatformSurfaceable=*/ Collections.singletonList("schema1"),
+ /*schemasPackageAccessible=*/ ImmutableMap.of(
+ "schema1",
+ ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))),
+ /*forceOverride=*/ false);
+
+ // Check that "schema1" still has the same visibility settings
+ assertThat(
+ mAppSearchImpl
+ .getVisibilityStoreLocked()
+ .isSchemaSearchableByCaller(
+ prefix, prefix + "schema1", mGlobalQuerierUid))
+ .isFalse();
+ assertThat(
+ mAppSearchImpl
+ .getVisibilityStoreLocked()
+ .isSchemaSearchableByCaller(prefix, prefix + "schema1", uidFoo))
+ .isTrue();
+
+ // "schema2" has default visibility settings
+ assertThat(
+ mAppSearchImpl
+ .getVisibilityStoreLocked()
+ .isSchemaSearchableByCaller(
+ prefix, prefix + "schema2", mGlobalQuerierUid))
+ .isTrue();
+ assertThat(
+ mAppSearchImpl
+ .getVisibilityStoreLocked()
+ .isSchemaSearchableByCaller(prefix, prefix + "schema2", uidFoo))
+ .isFalse();
+ }
+
+ @Test
+ public void testRemoveSchema_removedFromVisibilityStore() throws Exception {
+ // Values for a "foo" client
+ String packageNameFoo = "packageFoo";
+ byte[] sha256CertFoo = new byte[] {10};
+ int uidFoo = 1;
+
+ // Make sure foo package will pass package manager checks.
+ mMockPackageManager.mockGetPackageUidAsUser(packageNameFoo, mContext.getUserId(), uidFoo);
+ mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
+
+ String prefix = AppSearchImpl.createPrefix("package", "database");
+ mAppSearchImpl.setSchema(
+ "package",
+ "database",
+ Collections.singletonList(new AppSearchSchema.Builder("schema1").build()),
+ /*schemasNotPlatformSurfaceable=*/ Collections.singletonList("schema1"),
+ /*schemasPackageAccessible=*/ ImmutableMap.of(
+ "schema1",
+ ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))),
+ /*forceOverride=*/ false);
+
+ // "schema1" is platform hidden now and package accessible
+ assertThat(
+ mAppSearchImpl
+ .getVisibilityStoreLocked()
+ .isSchemaSearchableByCaller(
+ prefix, prefix + "schema1", mGlobalQuerierUid))
+ .isFalse();
+ assertThat(
+ mAppSearchImpl
+ .getVisibilityStoreLocked()
+ .isSchemaSearchableByCaller(prefix, prefix + "schema1", uidFoo))
+ .isTrue();
+
+ // Remove "schema1" by force overriding
+ mAppSearchImpl.setSchema(
+ "package",
+ "database",
+ /*schemas=*/ Collections.emptyList(),
+ /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+ /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*forceOverride=*/ true);
+
+ // Check that "schema1" is no longer considered platform hidden or package accessible
+ assertThat(
+ mAppSearchImpl
+ .getVisibilityStoreLocked()
+ .isSchemaSearchableByCaller(
+ prefix, prefix + "schema1", mGlobalQuerierUid))
+ .isTrue();
+ assertThat(
+ mAppSearchImpl
+ .getVisibilityStoreLocked()
+ .isSchemaSearchableByCaller(prefix, prefix + "schema1", uidFoo))
+ .isFalse();
+
+ // Add "schema1" back, it gets default visibility settings which means it's not platform
+ // hidden and not package accessible
+ mAppSearchImpl.setSchema(
+ "package",
+ "database",
+ Collections.singletonList(new AppSearchSchema.Builder("schema1").build()),
+ /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+ /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false);
+ assertThat(
+ mAppSearchImpl
+ .getVisibilityStoreLocked()
+ .isSchemaSearchableByCaller(
+ prefix, prefix + "schema1", mGlobalQuerierUid))
+ .isTrue();
+ assertThat(
+ mAppSearchImpl
+ .getVisibilityStoreLocked()
+ .isSchemaSearchableByCaller(prefix, prefix + "schema1", uidFoo))
+ .isFalse();
+ }
+
+ @Test
+ public void testSetSchema_defaultPlatformVisible() throws Exception {
+ String prefix = AppSearchImpl.createPrefix("package", "database");
+ mAppSearchImpl.setSchema(
+ "package",
+ "database",
+ Collections.singletonList(new AppSearchSchema.Builder("Schema").build()),
+ /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+ /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false);
+ assertThat(
+ mAppSearchImpl
+ .getVisibilityStoreLocked()
+ .isSchemaSearchableByCaller(
+ prefix, prefix + "Schema", mGlobalQuerierUid))
+ .isTrue();
+ }
+
+ @Test
+ public void testSetSchema_platformHidden() throws Exception {
+ String prefix = AppSearchImpl.createPrefix("package", "database");
+ mAppSearchImpl.setSchema(
+ "package",
+ "database",
+ Collections.singletonList(new AppSearchSchema.Builder("Schema").build()),
+ /*schemasNotPlatformSurfaceable=*/ Collections.singletonList("Schema"),
+ /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false);
+ assertThat(
+ mAppSearchImpl
+ .getVisibilityStoreLocked()
+ .isSchemaSearchableByCaller(
+ prefix, prefix + "Schema", mGlobalQuerierUid))
+ .isFalse();
+ }
+
+ @Test
+ public void testSetSchema_defaultNotPackageAccessible() throws Exception {
+ String prefix = AppSearchImpl.createPrefix("package", "database");
+ mAppSearchImpl.setSchema(
+ "package",
+ "database",
+ Collections.singletonList(new AppSearchSchema.Builder("Schema").build()),
+ /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+ /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false);
+ assertThat(
+ mAppSearchImpl
+ .getVisibilityStoreLocked()
+ .isSchemaSearchableByCaller(
+ prefix, prefix + "Schema", /*callerUid=*/ 42))
+ .isFalse();
+ }
+
+ @Test
+ public void testSetSchema_packageAccessible() throws Exception {
+ // Values for a "foo" client
+ String packageNameFoo = "packageFoo";
+ byte[] sha256CertFoo = new byte[] {10};
+ int uidFoo = 1;
+
+ // Make sure foo package will pass package manager checks.
+ mMockPackageManager.mockGetPackageUidAsUser(packageNameFoo, mContext.getUserId(), uidFoo);
+ mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
+
+ String prefix = AppSearchImpl.createPrefix("package", "database");
+ mAppSearchImpl.setSchema(
+ "package",
+ "database",
+ Collections.singletonList(new AppSearchSchema.Builder("Schema").build()),
+ /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+ /*schemasPackageAccessible=*/ ImmutableMap.of(
+ "Schema",
+ ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))),
+ /*forceOverride=*/ false);
+ assertThat(
+ mAppSearchImpl
+ .getVisibilityStoreLocked()
+ .isSchemaSearchableByCaller(prefix, prefix + "Schema", uidFoo))
+ .isTrue();
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/MockPackageManager.java b/services/tests/servicestests/src/com/android/server/appsearch/MockPackageManager.java
new file mode 100644
index 0000000..459fc53
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/appsearch/MockPackageManager.java
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+// TODO(b/169883602): This is purposely a different package from the path so that AppSearchImplTest
+// can use it without an extra import. This should be moved into a proper package once
+// AppSearchImpl-VisibilityStore's dependencies are refactored.
+package com.android.server.appsearch.external.localstorage;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.content.pm.PackageManager;
+
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/** Mock to help test package name, UID, and certificate verification. */
+public class MockPackageManager {
+
+ @Mock private PackageManager mMockPackageManager;
+
+ public MockPackageManager() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @NonNull
+ public PackageManager getMockPackageManager() {
+ return mMockPackageManager;
+ }
+
+ /** Mock a NameNotFoundException if the package name isn't installed. */
+ public void mockThrowsNameNotFoundException(String packageName) {
+ try {
+ when(mMockPackageManager.getPackageUidAsUser(eq(packageName), /*userId=*/ anyInt()))
+ .thenThrow(new PackageManager.NameNotFoundException());
+ when(mMockPackageManager.getPackageUidAsUser(
+ eq(packageName), /*flags=*/ anyInt(), /*userId=*/ anyInt()))
+ .thenThrow(new PackageManager.NameNotFoundException());
+ } catch (PackageManager.NameNotFoundException e) {
+ // Shouldn't ever happen since we're mocking the exception
+ e.printStackTrace();
+ }
+ }
+
+ /** Mocks that {@code uid} contains the {@code packageName} */
+ public void mockGetPackageUidAsUser(String packageName, @UserIdInt int callerUserId, int uid) {
+ try {
+ when(mMockPackageManager.getPackageUidAsUser(eq(packageName), eq(callerUserId)))
+ .thenReturn(uid);
+ when(mMockPackageManager.getPackageUidAsUser(
+ eq(packageName), /*flags=*/ anyInt(), eq(callerUserId)))
+ .thenReturn(uid);
+ } catch (PackageManager.NameNotFoundException e) {
+ // Shouldn't ever happen since we're mocking the method.
+ e.printStackTrace();
+ }
+ }
+
+ /** Mocks that {@code packageName} has been signed with {@code sha256Cert}. */
+ public void mockAddSigningCertificate(String packageName, byte[] sha256Cert) {
+ when(mMockPackageManager.hasSigningCertificate(
+ packageName, sha256Cert, PackageManager.CERT_INPUT_SHA256))
+ .thenReturn(true);
+ }
+
+ /** Mocks that {@code packageName} has NOT been signed with {@code sha256Cert}. */
+ public void mockRemoveSigningCertificate(String packageName, byte[] sha256Cert) {
+ when(mMockPackageManager.hasSigningCertificate(
+ packageName, sha256Cert, PackageManager.CERT_INPUT_SHA256))
+ .thenReturn(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
new file mode 100644
index 0000000..8d35ebe
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java
@@ -0,0 +1,324 @@
+/*
+ * 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.
+ */
+
+// TODO(b/169883602): This is purposely a different package from the path so that it can access
+// AppSearchImpl and VisibilityStore methods without having to make methods public. This should be
+// moved into a proper package once AppSearchImpl-VisibilityStore's dependencies are refactored.
+package com.android.server.appsearch.external.localstorage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.appsearch.PackageIdentifier;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.pm.PackageManager;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.util.Collections;
+
+public class VisibilityStoreTest {
+
+ @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+ private MockPackageManager mMockPackageManager = new MockPackageManager();
+ private Context mContext;
+ private AppSearchImpl mAppSearchImpl;
+ private VisibilityStore mVisibilityStore;
+ private int mGlobalQuerierUid;
+
+ @Before
+ public void setUp() throws Exception {
+ Context context = ApplicationProvider.getApplicationContext();
+ mContext =
+ new ContextWrapper(context) {
+ @Override
+ public PackageManager getPackageManager() {
+ return mMockPackageManager.getMockPackageManager();
+ }
+ };
+
+ // Give ourselves global query permissions
+ mAppSearchImpl =
+ AppSearchImpl.create(
+ mTemporaryFolder.newFolder(),
+ mContext,
+ mContext.getUserId(),
+ /*globalQuerierPackage=*/ mContext.getPackageName());
+ mGlobalQuerierUid =
+ mContext.getPackageManager().getPackageUid(mContext.getPackageName(), /*flags=*/ 0);
+
+ mVisibilityStore = mAppSearchImpl.getVisibilityStoreLocked();
+ }
+
+ /**
+ * Make sure that we don't conflict with any special characters that AppSearchImpl has reserved.
+ */
+ @Test
+ public void testValidPackageName() {
+ assertThat(VisibilityStore.PACKAGE_NAME)
+ .doesNotContain(
+ "" + AppSearchImpl.PACKAGE_DELIMITER); // Convert the chars to CharSequences
+ assertThat(VisibilityStore.PACKAGE_NAME)
+ .doesNotContain(
+ ""
+ + AppSearchImpl
+ .DATABASE_DELIMITER); // Convert the chars to CharSequences
+ }
+
+ /**
+ * Make sure that we don't conflict with any special characters that AppSearchImpl has reserved.
+ */
+ @Test
+ public void testValidDatabaseName() {
+ assertThat(VisibilityStore.DATABASE_NAME)
+ .doesNotContain(
+ "" + AppSearchImpl.PACKAGE_DELIMITER); // Convert the chars to CharSequences
+ assertThat(VisibilityStore.DATABASE_NAME)
+ .doesNotContain(
+ ""
+ + AppSearchImpl
+ .DATABASE_DELIMITER); // Convert the chars to CharSequences
+ }
+
+ @Test
+ public void testSetVisibility_platformSurfaceable() throws Exception {
+ mVisibilityStore.setVisibility(
+ "prefix",
+ /*schemasNotPlatformSurfaceable=*/ ImmutableSet.of(
+ "prefix/schema1", "prefix/schema2"),
+ /*schemasPackageAccessible=*/ Collections.emptyMap());
+ assertThat(
+ mVisibilityStore.isSchemaSearchableByCaller(
+ "prefix", "prefix/schema1", mGlobalQuerierUid))
+ .isFalse();
+ assertThat(
+ mVisibilityStore.isSchemaSearchableByCaller(
+ "prefix", "prefix/schema2", mGlobalQuerierUid))
+ .isFalse();
+
+ // New .setVisibility() call completely overrides previous visibility settings. So
+ // "schema2" isn't preserved.
+ mVisibilityStore.setVisibility(
+ "prefix",
+ /*schemasNotPlatformSurfaceable=*/ ImmutableSet.of(
+ "prefix/schema1", "prefix/schema3"),
+ /*schemasPackageAccessible=*/ Collections.emptyMap());
+ assertThat(
+ mVisibilityStore.isSchemaSearchableByCaller(
+ "prefix", "prefix/schema1", mGlobalQuerierUid))
+ .isFalse();
+ assertThat(
+ mVisibilityStore.isSchemaSearchableByCaller(
+ "prefix", "prefix/schema2", mGlobalQuerierUid))
+ .isTrue();
+ assertThat(
+ mVisibilityStore.isSchemaSearchableByCaller(
+ "prefix", "prefix/schema3", mGlobalQuerierUid))
+ .isFalse();
+
+ // Everything defaults to visible again.
+ mVisibilityStore.setVisibility(
+ "prefix",
+ /*schemasNotPlatformSurfaceable=*/ Collections.emptySet(),
+ /*schemasPackageAccessible=*/ Collections.emptyMap());
+ assertThat(
+ mVisibilityStore.isSchemaSearchableByCaller(
+ "prefix", "prefix/schema1", mGlobalQuerierUid))
+ .isTrue();
+ assertThat(
+ mVisibilityStore.isSchemaSearchableByCaller(
+ "prefix", "prefix/schema2", mGlobalQuerierUid))
+ .isTrue();
+ assertThat(
+ mVisibilityStore.isSchemaSearchableByCaller(
+ "prefix", "prefix/schema3", mGlobalQuerierUid))
+ .isTrue();
+ }
+
+ @Test
+ public void testIsSchemaSearchableByCaller_platformQuerierHandlesNameNotFoundException()
+ throws Exception {
+ // Initialized the VisibilityStore with this context's package name as the global querier.
+ mMockPackageManager.mockThrowsNameNotFoundException(mContext.getPackageName());
+
+ // Create a new VisibilityStore instance since we look up the UID on initialization
+ AppSearchImpl appSearchImpl =
+ AppSearchImpl.create(
+ mTemporaryFolder.newFolder(),
+ mContext,
+ mContext.getUserId(),
+ /*globalQuerierPackage=*/ mContext.getPackageName());
+ VisibilityStore visibilityStore = appSearchImpl.getVisibilityStoreLocked();
+
+ // Use some arbitrary callerUid. If we can't find the global querier's uid though,
+ // nothing should be platform surfaceable.
+ assertThat(
+ visibilityStore.isSchemaSearchableByCaller(
+ "prefix", "prefix/schemaFoo", /*callerUid=*/ 0))
+ .isFalse();
+ }
+
+ @Test
+ public void testSetVisibility_packageAccessible() throws Exception {
+ // Values for a "foo" client
+ String packageNameFoo = "packageFoo";
+ byte[] sha256CertFoo = new byte[] {10};
+ int uidFoo = 1;
+
+ // Values for a "bar" client
+ String packageNameBar = "packageBar";
+ byte[] sha256CertBar = new byte[] {100};
+ int uidBar = 2;
+
+ // Can't be the same value as uidFoo nor uidBar
+ int uidNotFooOrBar = 3;
+
+ // By default, a schema isn't package accessible.
+ assertThat(
+ mVisibilityStore.isSchemaSearchableByCaller(
+ "prefix", "prefix/schemaFoo", uidFoo))
+ .isFalse();
+ assertThat(
+ mVisibilityStore.isSchemaSearchableByCaller(
+ "prefix", "prefix/schemaBar", uidBar))
+ .isFalse();
+
+ // Grant package access
+ mVisibilityStore.setVisibility(
+ "prefix",
+ /*schemasNotPlatformSurfaceable=*/ Collections.emptySet(),
+ /*schemasPackageAccessible=*/ ImmutableMap.of(
+ "prefix/schemaFoo",
+ ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo)),
+ "prefix/schemaBar",
+ ImmutableList.of(new PackageIdentifier(packageNameBar, sha256CertBar))));
+
+ // Should fail if PackageManager doesn't see that it has the proper certificate
+ mMockPackageManager.mockGetPackageUidAsUser(packageNameFoo, mContext.getUserId(), uidFoo);
+ mMockPackageManager.mockRemoveSigningCertificate(packageNameFoo, sha256CertFoo);
+ assertThat(
+ mVisibilityStore.isSchemaSearchableByCaller(
+ "prefix", "prefix/schemaFoo", uidFoo))
+ .isFalse();
+
+ // Should fail if PackageManager doesn't think the package belongs to the uid
+ mMockPackageManager.mockGetPackageUidAsUser(
+ packageNameFoo, mContext.getUserId(), uidNotFooOrBar);
+ mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
+ assertThat(
+ mVisibilityStore.isSchemaSearchableByCaller(
+ "prefix", "prefix/schemaFoo", uidFoo))
+ .isFalse();
+
+ // But if uid and certificate match, then we should have access
+ mMockPackageManager.mockGetPackageUidAsUser(packageNameFoo, mContext.getUserId(), uidFoo);
+ mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
+ assertThat(
+ mVisibilityStore.isSchemaSearchableByCaller(
+ "prefix", "prefix/schemaFoo", uidFoo))
+ .isTrue();
+
+ mMockPackageManager.mockGetPackageUidAsUser(packageNameBar, mContext.getUserId(), uidBar);
+ mMockPackageManager.mockAddSigningCertificate(packageNameBar, sha256CertBar);
+ assertThat(
+ mVisibilityStore.isSchemaSearchableByCaller(
+ "prefix", "prefix/schemaBar", uidBar))
+ .isTrue();
+
+ // New .setVisibility() call completely overrides previous visibility settings. So
+ // "schemaBar" settings aren't preserved.
+ mVisibilityStore.setVisibility(
+ "prefix",
+ /*schemasNotPlatformSurfaceable=*/ Collections.emptySet(),
+ /*schemasPackageAccessible=*/ ImmutableMap.of(
+ "prefix/schemaFoo",
+ ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))));
+
+ mMockPackageManager.mockGetPackageUidAsUser(packageNameFoo, mContext.getUserId(), uidFoo);
+ mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
+ assertThat(
+ mVisibilityStore.isSchemaSearchableByCaller(
+ "prefix", "prefix/schemaFoo", uidFoo))
+ .isTrue();
+
+ mMockPackageManager.mockGetPackageUidAsUser(packageNameBar, mContext.getUserId(), uidBar);
+ mMockPackageManager.mockAddSigningCertificate(packageNameBar, sha256CertBar);
+ assertThat(
+ mVisibilityStore.isSchemaSearchableByCaller(
+ "prefix", "prefix/schemaBar", uidBar))
+ .isFalse();
+ }
+
+ @Test
+ public void testIsSchemaSearchableByCaller_packageAccessibilityHandlesNameNotFoundException()
+ throws Exception {
+ // Values for a "foo" client
+ String packageNameFoo = "packageFoo";
+ byte[] sha256CertFoo = new byte[] {10};
+ int uidFoo = 1;
+
+ // Pretend we can't find the Foo package.
+ mMockPackageManager.mockThrowsNameNotFoundException(packageNameFoo);
+
+ // Grant package access
+ mVisibilityStore.setVisibility(
+ "prefix",
+ /*schemasNotPlatformSurfaceable=*/ Collections.emptySet(),
+ /*schemasPackageAccessible=*/ ImmutableMap.of(
+ "prefix/schemaFoo",
+ ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))));
+
+ // If we can't verify the Foo package that has access, assume it doesn't have access.
+ assertThat(
+ mVisibilityStore.isSchemaSearchableByCaller(
+ "prefix", "prefix/schemaFoo", uidFoo))
+ .isFalse();
+ }
+
+ @Test
+ public void testEmptyPrefix() throws Exception {
+ // Values for a "foo" client
+ String packageNameFoo = "packageFoo";
+ byte[] sha256CertFoo = new byte[] {10};
+ int uidFoo = 1;
+
+ mVisibilityStore.setVisibility(
+ /*prefix=*/ "",
+ /*schemasNotPlatformSurfaceable=*/ Collections.emptySet(),
+ /*schemasPackageAccessible=*/ ImmutableMap.of(
+ "schema",
+ ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))));
+
+ assertThat(
+ mVisibilityStore.isSchemaSearchableByCaller(
+ /*prefix=*/ "", "schema", mGlobalQuerierUid))
+ .isTrue();
+
+ mMockPackageManager.mockGetPackageUidAsUser(packageNameFoo, mContext.getUserId(), uidFoo);
+ mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
+ assertThat(mVisibilityStore.isSchemaSearchableByCaller(/*prefix=*/ "", "schema", uidFoo))
+ .isTrue();
+ }
+}
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 6366155..8d744c4 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
@@ -16,17 +16,23 @@
package com.android.server.appsearch.external.localstorage;
+import static android.app.appsearch.AppSearchResult.RESULT_OK;
+
import static com.google.common.truth.Truth.assertThat;
import static org.testng.Assert.expectThrows;
import android.app.appsearch.AppSearchSchema;
import android.app.appsearch.GenericDocument;
-import android.app.appsearch.PackageIdentifier;
import android.app.appsearch.SearchResult;
import android.app.appsearch.SearchResultPage;
import android.app.appsearch.SearchSpec;
+import android.app.appsearch.SetSchemaResult;
import android.app.appsearch.exceptions.AppSearchException;
+import android.content.Context;
+import android.util.ArraySet;
+
+import androidx.test.core.app.ApplicationProvider;
import com.android.server.appsearch.external.localstorage.converter.GenericDocumentToProtoConverter;
import com.android.server.appsearch.proto.DocumentProto;
@@ -41,7 +47,6 @@
import com.android.server.appsearch.proto.TermMatchType;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import org.junit.Before;
@@ -52,6 +57,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Set;
public class AppSearchImplTest {
@Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
@@ -59,7 +65,15 @@
@Before
public void setUp() throws Exception {
- mAppSearchImpl = AppSearchImpl.create(mTemporaryFolder.newFolder());
+ Context context = ApplicationProvider.getApplicationContext();
+ // Give ourselves global query permissions
+ mAppSearchImpl =
+ AppSearchImpl.create(
+ mTemporaryFolder.newFolder(),
+ context,
+ VisibilityStore.NO_OP_USER_ID,
+ /*globalQuerierPackage
+ =*/ context.getPackageName());
}
// TODO(b/175430168) add test to verify reset is working properly.
@@ -460,7 +474,8 @@
// Rewrite SearchSpec
mAppSearchImpl.rewriteSearchSpecForPrefixesLocked(
searchSpecProto,
- Collections.singleton(AppSearchImpl.createPrefix("package", "database")));
+ Collections.singleton(AppSearchImpl.createPrefix("package", "database")),
+ ImmutableSet.of("package$database/type"));
assertThat(searchSpecProto.getSchemaTypeFiltersList())
.containsExactly("package$database/type");
assertThat(searchSpecProto.getNamespaceFiltersList())
@@ -505,7 +520,10 @@
searchSpecProto,
ImmutableSet.of(
AppSearchImpl.createPrefix("package", "database1"),
- AppSearchImpl.createPrefix("package", "database2")));
+ AppSearchImpl.createPrefix("package", "database2")),
+ ImmutableSet.of(
+ "package$database1/typeA", "package$database1/typeB",
+ "package$database2/typeA", "package$database2/typeB"));
assertThat(searchSpecProto.getSchemaTypeFiltersList())
.containsExactly(
"package$database1/typeA",
@@ -517,6 +535,38 @@
}
@Test
+ public void testRewriteSearchSpec_ignoresSearchSpecSchemaFilters() throws Exception {
+ SearchSpecProto.Builder searchSpecProto =
+ SearchSpecProto.newBuilder().setQuery("").addSchemaTypeFilters("type");
+
+ // Insert schema
+ List<AppSearchSchema> schemas =
+ Collections.singletonList(new AppSearchSchema.Builder("type").build());
+ mAppSearchImpl.setSchema(
+ "package",
+ "database",
+ schemas,
+ /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+ /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false);
+
+ // Insert document
+ GenericDocument document =
+ new GenericDocument.Builder<>("uri", "type").setNamespace("namespace").build();
+ mAppSearchImpl.putDocument("package", "database", document);
+
+ // If 'allowedPrefixedSchemas' is empty, this returns false since there's nothing to
+ // search over. Despite the searchSpecProto having schema type filters.
+ assertThat(
+ mAppSearchImpl.rewriteSearchSpecForPrefixesLocked(
+ searchSpecProto,
+ Collections.singleton(
+ AppSearchImpl.createPrefix("package", "database")),
+ /*allowedPrefixedSchemas=*/ Collections.emptySet()))
+ .isFalse();
+ }
+
+ @Test
public void testQueryEmptyDatabase() throws Exception {
SearchSpec searchSpec =
new SearchSpec.Builder().setTermMatch(TermMatchType.Code.PREFIX_VALUE).build();
@@ -640,119 +690,12 @@
public void testGlobalQueryEmptyDatabase() throws Exception {
SearchSpec searchSpec =
new SearchSpec.Builder().setTermMatch(TermMatchType.Code.PREFIX_VALUE).build();
- SearchResultPage searchResultPage = mAppSearchImpl.globalQuery("", searchSpec);
+ SearchResultPage searchResultPage =
+ mAppSearchImpl.globalQuery(
+ "", searchSpec, /*callerPackageName=*/ "", /*callerUid=*/ 0);
assertThat(searchResultPage.getResults()).isEmpty();
}
- /**
- * TODO(b/169883602): This should be an integration test at the cts-level. This is a short-term
- * test until we have official support for multiple-apps indexing at once.
- */
- @Test
- public void testGlobalQueryWithMultiplePackages_noPackageFilters() throws Exception {
- // Insert package1 schema
- List<AppSearchSchema> schema1 =
- ImmutableList.of(new AppSearchSchema.Builder("schema1").build());
- mAppSearchImpl.setSchema(
- "package1",
- "database1",
- schema1,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
- /*forceOverride=*/ false);
-
- // Insert package2 schema
- List<AppSearchSchema> schema2 =
- ImmutableList.of(new AppSearchSchema.Builder("schema2").build());
- mAppSearchImpl.setSchema(
- "package2",
- "database2",
- schema2,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
- /*forceOverride=*/ false);
-
- // Insert package1 document
- GenericDocument document1 =
- new GenericDocument.Builder<>("uri", "schema1").setNamespace("namespace").build();
- mAppSearchImpl.putDocument("package1", "database1", document1);
-
- // Insert package2 document
- GenericDocument document2 =
- new GenericDocument.Builder<>("uri", "schema2").setNamespace("namespace").build();
- mAppSearchImpl.putDocument("package2", "database2", document2);
-
- // No query filters specified, global query can retrieve all documents.
- SearchSpec searchSpec =
- new SearchSpec.Builder().setTermMatch(TermMatchType.Code.PREFIX_VALUE).build();
- SearchResultPage searchResultPage = mAppSearchImpl.globalQuery("", searchSpec);
- assertThat(searchResultPage.getResults()).hasSize(2);
-
- // Document2 will be first since it got indexed later and has a "better", aka more recent
- // score.
- assertThat(searchResultPage.getResults().get(0).getDocument()).isEqualTo(document2);
- assertThat(searchResultPage.getResults().get(1).getDocument()).isEqualTo(document1);
- }
-
- /**
- * TODO(b/169883602): This should be an integration test at the cts-level. This is a short-term
- * test until we have official support for multiple-apps indexing at once.
- */
- @Test
- public void testGlobalQueryWithMultiplePackages_withPackageFilters() throws Exception {
- // Insert package1 schema
- List<AppSearchSchema> schema1 =
- ImmutableList.of(new AppSearchSchema.Builder("schema1").build());
- mAppSearchImpl.setSchema(
- "package1",
- "database1",
- schema1,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
- /*forceOverride=*/ false);
-
- // Insert package2 schema
- List<AppSearchSchema> schema2 =
- ImmutableList.of(new AppSearchSchema.Builder("schema2").build());
- mAppSearchImpl.setSchema(
- "package2",
- "database2",
- schema2,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
- /*forceOverride=*/ false);
-
- // Insert package1 document
- GenericDocument document1 =
- new GenericDocument.Builder<>("uri", "schema1").setNamespace("namespace").build();
- mAppSearchImpl.putDocument("package1", "database1", document1);
-
- // Insert package2 document
- GenericDocument document2 =
- new GenericDocument.Builder<>("uri", "schema2").setNamespace("namespace").build();
- mAppSearchImpl.putDocument("package2", "database2", document2);
-
- // "package1" filter specified
- SearchSpec searchSpec =
- new SearchSpec.Builder()
- .setTermMatch(TermMatchType.Code.PREFIX_VALUE)
- .addFilterPackageNames("package1")
- .build();
- SearchResultPage searchResultPage = mAppSearchImpl.globalQuery("", searchSpec);
- assertThat(searchResultPage.getResults()).hasSize(1);
- assertThat(searchResultPage.getResults().get(0).getDocument()).isEqualTo(document1);
-
- // "package2" filter specified
- searchSpec =
- new SearchSpec.Builder()
- .setTermMatch(TermMatchType.Code.PREFIX_VALUE)
- .addFilterPackageNames("package2")
- .build();
- searchResultPage = mAppSearchImpl.globalQuery("", searchSpec);
- assertThat(searchResultPage.getResults()).hasSize(1);
- assertThat(searchResultPage.getResults().get(0).getDocument()).isEqualTo(document2);
- }
-
@Test
public void testRemoveEmptyDatabase_noExceptionThrown() throws Exception {
SearchSpec searchSpec =
@@ -794,7 +737,8 @@
SchemaProto.newBuilder()
.addTypes(
SchemaTypeConfigProto.newBuilder()
- .setSchemaType("package$database1/Email"))
+ .setSchemaType("package$database1/Email")
+ .setVersion(0))
.build();
List<SchemaTypeConfigProto> expectedTypes = new ArrayList<>();
@@ -805,67 +749,51 @@
}
@Test
- public void testSetSchema_existingSchemaRetainsVisibilitySetting() throws Exception {
- PackageIdentifier package1 =
- new PackageIdentifier("package1", /*sha256Certificate=*/ new byte[] {100});
+ public void testSetSchema_incompatible() throws Exception {
+ List<SchemaTypeConfigProto> existingSchemas =
+ mAppSearchImpl.getSchemaProtoLocked().getTypesList();
- String prefix = AppSearchImpl.createPrefix("package", "database");
+ List<AppSearchSchema> oldSchemas = new ArrayList<>();
+ oldSchemas.add(
+ new AppSearchSchema.Builder("Email")
+ .addProperty(
+ new AppSearchSchema.StringPropertyConfig.Builder("foo")
+ .setCardinality(
+ AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .setTokenizerType(
+ AppSearchSchema.StringPropertyConfig
+ .TOKENIZER_TYPE_PLAIN)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig
+ .INDEXING_TYPE_PREFIXES)
+ .build())
+ .build());
+ oldSchemas.add(new AppSearchSchema.Builder("Text").build());
+ // Set schema Email to AppSearch database1
mAppSearchImpl.setSchema(
"package",
- "database",
- Collections.singletonList(new AppSearchSchema.Builder("schema1").build()),
- /*schemasNotPlatformSurfaceable=*/ Collections.singletonList("schema1"),
- /*schemasPackageAccessible=*/ ImmutableMap.of(
- "schema1", ImmutableList.of(package1)),
+ "database1",
+ oldSchemas,
+ /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+ /*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false);
- // "schema1" is platform hidden now and package visible to package1
- assertThat(
- mAppSearchImpl
- .getVisibilityStoreLocked()
- .isSchemaPlatformSurfaceable(prefix, prefix + "schema1"))
- .isFalse();
- assertThat(
- mAppSearchImpl
- .getVisibilityStoreLocked()
- .isSchemaPackageAccessible(prefix, prefix + "schema1", package1))
- .isTrue();
+ // Create incompatible schema
+ List<AppSearchSchema> newSchemas =
+ Collections.singletonList(new AppSearchSchema.Builder("Email").build());
- // Add a new schema, and include the already-existing "schema1"
- mAppSearchImpl.setSchema(
- "package",
- "database",
- ImmutableList.of(
- new AppSearchSchema.Builder("schema1").build(),
- new AppSearchSchema.Builder("schema2").build()),
- /*schemasNotPlatformSurfaceable=*/ Collections.singletonList("schema1"),
- /*schemasPackageAccessible=*/ ImmutableMap.of(
- "schema1", ImmutableList.of(package1)),
- /*forceOverride=*/ false);
-
- // Check that "schema1" still has the same visibility settings
- assertThat(
- mAppSearchImpl
- .getVisibilityStoreLocked()
- .isSchemaPlatformSurfaceable(prefix, prefix + "schema1"))
- .isFalse();
- assertThat(
- mAppSearchImpl
- .getVisibilityStoreLocked()
- .isSchemaPackageAccessible(prefix, prefix + "schema1", package1))
- .isTrue();
-
- // "schema2" has default visibility settings
- assertThat(
- mAppSearchImpl
- .getVisibilityStoreLocked()
- .isSchemaPlatformSurfaceable(prefix, prefix + "schema2"))
- .isTrue();
- assertThat(
- mAppSearchImpl
- .getVisibilityStoreLocked()
- .isSchemaPackageAccessible(prefix, prefix + "schema2", package1))
- .isFalse();
+ // set email incompatible and delete text
+ SetSchemaResult setSchemaResult =
+ mAppSearchImpl.setSchema(
+ "package",
+ "database1",
+ newSchemas,
+ /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+ /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*forceOverride=*/ true);
+ assertThat(setSchemaResult.getDeletedSchemaTypes()).containsExactly("Text");
+ assertThat(setSchemaResult.getIncompatibleSchemaTypes()).containsExactly("Email");
+ assertThat(setSchemaResult.getResultCode()).isEqualTo(RESULT_OK);
}
@Test
@@ -891,10 +819,12 @@
SchemaProto.newBuilder()
.addTypes(
SchemaTypeConfigProto.newBuilder()
- .setSchemaType("package$database1/Email"))
+ .setSchemaType("package$database1/Email")
+ .setVersion(0))
.addTypes(
SchemaTypeConfigProto.newBuilder()
- .setSchemaType("package$database1/Document"))
+ .setSchemaType("package$database1/Document")
+ .setVersion(0))
.build();
// Check both schema Email and Document saved correctly.
@@ -906,20 +836,17 @@
final List<AppSearchSchema> finalSchemas =
Collections.singletonList(new AppSearchSchema.Builder("Email").build());
- // Check the incompatible error has been thrown.
- AppSearchException e =
- expectThrows(
- AppSearchException.class,
- () ->
- mAppSearchImpl.setSchema(
- "package",
- "database1",
- finalSchemas,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
- /*forceOverride=*/ false));
- assertThat(e).hasMessageThat().contains("Schema is incompatible");
- assertThat(e).hasMessageThat().contains("Deleted types: [package$database1/Document]");
+ SetSchemaResult setSchemaResult =
+ mAppSearchImpl.setSchema(
+ "package",
+ "database1",
+ finalSchemas,
+ /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+ /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false);
+
+ // Check the Document type has been deleted.
+ assertThat(setSchemaResult.getDeletedSchemaTypes()).containsExactly("Document");
// ForceOverride to delete.
mAppSearchImpl.setSchema(
@@ -935,7 +862,8 @@
SchemaProto.newBuilder()
.addTypes(
SchemaTypeConfigProto.newBuilder()
- .setSchemaType("package$database1/Email"))
+ .setSchemaType("package$database1/Email")
+ .setVersion(0))
.build();
expectedTypes = new ArrayList<>();
@@ -977,16 +905,20 @@
SchemaProto.newBuilder()
.addTypes(
SchemaTypeConfigProto.newBuilder()
- .setSchemaType("package$database1/Email"))
+ .setSchemaType("package$database1/Email")
+ .setVersion(0))
.addTypes(
SchemaTypeConfigProto.newBuilder()
- .setSchemaType("package$database1/Document"))
+ .setSchemaType("package$database1/Document")
+ .setVersion(0))
.addTypes(
SchemaTypeConfigProto.newBuilder()
- .setSchemaType("package$database2/Email"))
+ .setSchemaType("package$database2/Email")
+ .setVersion(0))
.addTypes(
SchemaTypeConfigProto.newBuilder()
- .setSchemaType("package$database2/Document"))
+ .setSchemaType("package$database2/Document")
+ .setVersion(0))
.build();
// Check Email and Document is saved in database 1 and 2 correctly.
@@ -1012,13 +944,16 @@
SchemaProto.newBuilder()
.addTypes(
SchemaTypeConfigProto.newBuilder()
- .setSchemaType("package$database1/Email"))
+ .setSchemaType("package$database1/Email")
+ .setVersion(0))
.addTypes(
SchemaTypeConfigProto.newBuilder()
- .setSchemaType("package$database2/Email"))
+ .setSchemaType("package$database2/Email")
+ .setVersion(0))
.addTypes(
SchemaTypeConfigProto.newBuilder()
- .setSchemaType("package$database2/Document"))
+ .setSchemaType("package$database2/Document")
+ .setVersion(0))
.build();
// Check nothing changed in database2.
@@ -1030,149 +965,6 @@
}
@Test
- public void testRemoveSchema_removedFromVisibilityStore() throws Exception {
- PackageIdentifier package1 =
- new PackageIdentifier("package1", /*sha256Certificate=*/ new byte[] {100});
-
- String prefix = AppSearchImpl.createPrefix("package", "database");
- mAppSearchImpl.setSchema(
- "package",
- "database",
- Collections.singletonList(new AppSearchSchema.Builder("schema1").build()),
- /*schemasNotPlatformSurfaceable=*/ Collections.singletonList("schema1"),
- /*schemasPackageAccessible=*/ ImmutableMap.of(
- "schema1", ImmutableList.of(package1)),
- /*forceOverride=*/ false);
-
- // "schema1" is platform hidden now and package accessible
- assertThat(
- mAppSearchImpl
- .getVisibilityStoreLocked()
- .isSchemaPlatformSurfaceable(prefix, prefix + "schema1"))
- .isFalse();
- assertThat(
- mAppSearchImpl
- .getVisibilityStoreLocked()
- .isSchemaPackageAccessible(prefix, prefix + "schema1", package1))
- .isTrue();
-
- // Remove "schema1" by force overriding
- mAppSearchImpl.setSchema(
- "package",
- "database",
- /*schemas=*/ Collections.emptyList(),
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
- /*forceOverride=*/ true);
-
- // Check that "schema1" is no longer considered platform hidden or package accessible
- assertThat(
- mAppSearchImpl
- .getVisibilityStoreLocked()
- .isSchemaPlatformSurfaceable(prefix, prefix + "schema1"))
- .isTrue();
- assertThat(
- mAppSearchImpl
- .getVisibilityStoreLocked()
- .isSchemaPackageAccessible(prefix, prefix + "schema1", package1))
- .isFalse();
-
- // Add "schema1" back, it gets default visibility settings which means it's not platform
- // hidden and not package accessible
- mAppSearchImpl.setSchema(
- "package",
- "database",
- Collections.singletonList(new AppSearchSchema.Builder("schema1").build()),
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
- /*forceOverride=*/ false);
- assertThat(
- mAppSearchImpl
- .getVisibilityStoreLocked()
- .isSchemaPlatformSurfaceable(prefix, prefix + "schema1"))
- .isTrue();
- assertThat(
- mAppSearchImpl
- .getVisibilityStoreLocked()
- .isSchemaPackageAccessible(prefix, prefix + "schema1", package1))
- .isFalse();
- }
-
- @Test
- public void testSetSchema_defaultPlatformVisible() throws Exception {
- String prefix = AppSearchImpl.createPrefix("package", "database");
- mAppSearchImpl.setSchema(
- "package",
- "database",
- Collections.singletonList(new AppSearchSchema.Builder("Schema").build()),
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
- /*forceOverride=*/ false);
- assertThat(
- mAppSearchImpl
- .getVisibilityStoreLocked()
- .isSchemaPlatformSurfaceable(prefix, prefix + "Schema"))
- .isTrue();
- }
-
- @Test
- public void testSetSchema_platformHidden() throws Exception {
- String prefix = AppSearchImpl.createPrefix("package", "database");
- mAppSearchImpl.setSchema(
- "package",
- "database",
- Collections.singletonList(new AppSearchSchema.Builder("Schema").build()),
- /*schemasNotPlatformSurfaceable=*/ Collections.singletonList("Schema"),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
- /*forceOverride=*/ false);
- assertThat(
- mAppSearchImpl
- .getVisibilityStoreLocked()
- .isSchemaPlatformSurfaceable(prefix, prefix + "Schema"))
- .isFalse();
- }
-
- @Test
- public void testSetSchema_defaultNotPackageAccessible() throws Exception {
- PackageIdentifier package1 =
- new PackageIdentifier("package1", /*sha256Certificate=*/ new byte[] {100});
-
- String prefix = AppSearchImpl.createPrefix("package", "database");
- mAppSearchImpl.setSchema(
- "package",
- "database",
- Collections.singletonList(new AppSearchSchema.Builder("Schema").build()),
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
- /*forceOverride=*/ false);
- assertThat(
- mAppSearchImpl
- .getVisibilityStoreLocked()
- .isSchemaPackageAccessible(prefix, prefix + "Schema", package1))
- .isFalse();
- }
-
- @Test
- public void testSetSchema_packageAccessible() throws Exception {
- PackageIdentifier package1 =
- new PackageIdentifier("package1", /*sha256Certificate=*/ new byte[] {100});
-
- String prefix = AppSearchImpl.createPrefix("package", "database");
- mAppSearchImpl.setSchema(
- "package",
- "database",
- Collections.singletonList(new AppSearchSchema.Builder("Schema").build()),
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ ImmutableMap.of("Schema", ImmutableList.of(package1)),
- /*forceOverride=*/ false);
- assertThat(
- mAppSearchImpl
- .getVisibilityStoreLocked()
- .isSchemaPackageAccessible(prefix, prefix + "Schema", package1))
- .isTrue();
- }
-
- @Test
public void testHasSchemaType() throws Exception {
// Nothing exists yet
assertThat(mAppSearchImpl.hasSchemaTypeLocked("package", "database", "Schema")).isFalse();
@@ -1191,14 +983,12 @@
}
@Test
- public void testGetDatabases() throws Exception {
- // No client databases exist yet, but the VisibilityStore's does
- assertThat(mAppSearchImpl.getPrefixesLocked())
- .containsExactly(
- AppSearchImpl.createPrefix(
- VisibilityStore.PACKAGE_NAME, VisibilityStore.DATABASE_NAME));
+ public void testGetPrefixes() throws Exception {
+ Set<String> existingPrefixes = mAppSearchImpl.getPrefixesLocked();
// Has database1
+ Set<String> expectedPrefixes = new ArraySet<>(existingPrefixes);
+ expectedPrefixes.add(AppSearchImpl.createPrefix("package", "database1"));
mAppSearchImpl.setSchema(
"package",
"database1",
@@ -1206,13 +996,10 @@
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false);
- assertThat(mAppSearchImpl.getPrefixesLocked())
- .containsExactly(
- AppSearchImpl.createPrefix(
- VisibilityStore.PACKAGE_NAME, VisibilityStore.DATABASE_NAME),
- AppSearchImpl.createPrefix("package", "database1"));
+ assertThat(mAppSearchImpl.getPrefixesLocked()).containsExactlyElementsIn(expectedPrefixes);
// Has both databases
+ expectedPrefixes.add(AppSearchImpl.createPrefix("package", "database2"));
mAppSearchImpl.setSchema(
"package",
"database2",
@@ -1220,12 +1007,7 @@
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
/*forceOverride=*/ false);
- assertThat(mAppSearchImpl.getPrefixesLocked())
- .containsExactly(
- AppSearchImpl.createPrefix(
- VisibilityStore.PACKAGE_NAME, VisibilityStore.DATABASE_NAME),
- AppSearchImpl.createPrefix("package", "database1"),
- AppSearchImpl.createPrefix("package", "database2"));
+ assertThat(mAppSearchImpl.getPrefixesLocked()).containsExactlyElementsIn(expectedPrefixes);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/VisibilityStoreTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/VisibilityStoreTest.java
deleted file mode 100644
index e491ac3..0000000
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/VisibilityStoreTest.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.appsearch.external.localstorage;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.app.appsearch.PackageIdentifier;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-
-import java.util.Collections;
-
-public class VisibilityStoreTest {
-
- @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
- private AppSearchImpl mAppSearchImpl;
- private VisibilityStore mVisibilityStore;
-
- @Before
- public void setUp() throws Exception {
- mAppSearchImpl = AppSearchImpl.create(mTemporaryFolder.newFolder());
- mVisibilityStore = mAppSearchImpl.getVisibilityStoreLocked();
- }
-
- /**
- * Make sure that we don't conflict with any special characters that AppSearchImpl has reserved.
- */
- @Test
- public void testValidPackageName() {
- assertThat(VisibilityStore.PACKAGE_NAME)
- .doesNotContain(
- "" + AppSearchImpl.PACKAGE_DELIMITER); // Convert the chars to CharSequences
- assertThat(VisibilityStore.PACKAGE_NAME)
- .doesNotContain(
- ""
- + AppSearchImpl
- .DATABASE_DELIMITER); // Convert the chars to CharSequences
- }
-
- /**
- * Make sure that we don't conflict with any special characters that AppSearchImpl has reserved.
- */
- @Test
- public void testValidDatabaseName() {
- assertThat(VisibilityStore.DATABASE_NAME)
- .doesNotContain(
- "" + AppSearchImpl.PACKAGE_DELIMITER); // Convert the chars to CharSequences
- assertThat(VisibilityStore.DATABASE_NAME)
- .doesNotContain(
- ""
- + AppSearchImpl
- .DATABASE_DELIMITER); // Convert the chars to CharSequences
- }
-
- @Test
- public void testSetVisibility_platformSurfaceable() throws Exception {
- mVisibilityStore.setVisibility(
- "prefix",
- /*schemasNotPlatformSurfaceable=*/ ImmutableSet.of(
- "prefix/schema1", "prefix/schema2"),
- /*schemasPackageAccessible=*/ Collections.emptyMap());
- assertThat(mVisibilityStore.isSchemaPlatformSurfaceable("prefix", "prefix/schema1"))
- .isFalse();
- assertThat(mVisibilityStore.isSchemaPlatformSurfaceable("prefix", "prefix/schema2"))
- .isFalse();
-
- // New .setVisibility() call completely overrides previous visibility settings. So
- // "schema2" isn't preserved.
- mVisibilityStore.setVisibility(
- "prefix",
- /*schemasNotPlatformSurfaceable=*/ ImmutableSet.of(
- "prefix/schema1", "prefix/schema3"),
- /*schemasPackageAccessible=*/ Collections.emptyMap());
- assertThat(mVisibilityStore.isSchemaPlatformSurfaceable("prefix", "prefix/schema1"))
- .isFalse();
- assertThat(mVisibilityStore.isSchemaPlatformSurfaceable("prefix", "prefix/schema2"))
- .isTrue();
- assertThat(mVisibilityStore.isSchemaPlatformSurfaceable("prefix", "prefix/schema3"))
- .isFalse();
-
- mVisibilityStore.setVisibility(
- "prefix",
- /*schemasNotPlatformSurfaceable=*/ Collections.emptySet(),
- /*schemasPackageAccessible=*/ Collections.emptyMap());
- assertThat(mVisibilityStore.isSchemaPlatformSurfaceable("prefix", "prefix/schema1"))
- .isTrue();
- assertThat(mVisibilityStore.isSchemaPlatformSurfaceable("prefix", "prefix/schema2"))
- .isTrue();
- assertThat(mVisibilityStore.isSchemaPlatformSurfaceable("prefix", "prefix/schema3"))
- .isTrue();
- }
-
- @Test
- public void testSetVisibility_packageAccessible() throws Exception {
- PackageIdentifier package1 =
- new PackageIdentifier("package1", /*sha256Certificate=*/ new byte[] {100});
- PackageIdentifier package2 =
- new PackageIdentifier("package2", /*sha256Certificate=*/ new byte[] {100});
- PackageIdentifier package3 =
- new PackageIdentifier("package3", /*sha256Certificate=*/ new byte[] {100});
-
- mVisibilityStore.setVisibility(
- "prefix",
- /*schemasNotPlatformSurfaceable=*/ Collections.emptySet(),
- /*schemasPackageAccessible=*/ ImmutableMap.of(
- "prefix/schema1", ImmutableList.of(package1),
- "prefix/schema2", ImmutableList.of(package2)));
- assertThat(mVisibilityStore.isSchemaPackageAccessible("prefix", "prefix/schema1", package1))
- .isTrue();
- assertThat(mVisibilityStore.isSchemaPackageAccessible("prefix", "prefix/schema2", package2))
- .isTrue();
-
- // New .setVisibility() call completely overrides previous visibility settings. So
- // "schema2" isn't preserved.
- mVisibilityStore.setVisibility(
- "prefix",
- /*schemasNotPlatformSurfaceable=*/ Collections.emptySet(),
- /*schemasPackageAccessible=*/ ImmutableMap.of(
- "prefix/schema1", ImmutableList.of(package1),
- "prefix/schema3", ImmutableList.of(package3)));
- assertThat(mVisibilityStore.isSchemaPackageAccessible("prefix", "prefix/schema1", package1))
- .isTrue();
- assertThat(mVisibilityStore.isSchemaPackageAccessible("prefix", "prefix/schema2", package2))
- .isFalse();
- assertThat(mVisibilityStore.isSchemaPackageAccessible("prefix", "prefix/schema3", package3))
- .isTrue();
-
- mVisibilityStore.setVisibility(
- "prefix",
- /*schemasNotPlatformSurfaceable=*/ Collections.emptySet(),
- /*schemasPackageAccessible=*/ Collections.emptyMap());
- assertThat(mVisibilityStore.isSchemaPackageAccessible("prefix", "prefix/schema1", package1))
- .isFalse();
- assertThat(mVisibilityStore.isSchemaPackageAccessible("prefix", "prefix/schema2", package2))
- .isFalse();
- assertThat(mVisibilityStore.isSchemaPackageAccessible("prefix", "prefix/schema3", package3))
- .isFalse();
- }
-
- @Test
- public void testEmptyPrefix() throws Exception {
- PackageIdentifier package1 =
- new PackageIdentifier("package1", /*sha256Certificate=*/ new byte[] {100});
- PackageIdentifier package2 =
- new PackageIdentifier("package2", /*sha256Certificate=*/ new byte[] {100});
-
- mVisibilityStore.setVisibility(
- /*prefix=*/ "",
- /*schemasNotPlatformSurfaceable=*/ ImmutableSet.of("schema1", "schema2"),
- /*schemasPackageAccessible=*/ ImmutableMap.of(
- "schema1", ImmutableList.of(package1),
- "schema2", ImmutableList.of(package2)));
- assertThat(mVisibilityStore.isSchemaPlatformSurfaceable(/*prefix=*/ "", "schema1"))
- .isFalse();
- assertThat(mVisibilityStore.isSchemaPlatformSurfaceable(/*prefix=*/ "", "schema2"))
- .isFalse();
- assertThat(mVisibilityStore.isSchemaPackageAccessible(/*prefix=*/ "", "schema1", package1))
- .isTrue();
- assertThat(mVisibilityStore.isSchemaPackageAccessible(/*prefix=*/ "", "schema2", package2))
- .isTrue();
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverterTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverterTest.java
index 88edcb8..dc225f1 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverterTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverterTest.java
@@ -32,35 +32,35 @@
public void testGetProto_Email() {
AppSearchSchema emailSchema =
new AppSearchSchema.Builder("Email")
+ .setVersion(12345)
.addProperty(
- new AppSearchSchema.PropertyConfig.Builder("subject")
- .setDataType(
- AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ new AppSearchSchema.StringPropertyConfig.Builder("subject")
.setCardinality(
AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setIndexingType(
- AppSearchSchema.PropertyConfig
+ AppSearchSchema.StringPropertyConfig
.INDEXING_TYPE_PREFIXES)
.setTokenizerType(
- AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ AppSearchSchema.StringPropertyConfig
+ .TOKENIZER_TYPE_PLAIN)
.build())
.addProperty(
- new AppSearchSchema.PropertyConfig.Builder("body")
- .setDataType(
- AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ new AppSearchSchema.StringPropertyConfig.Builder("body")
.setCardinality(
AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setIndexingType(
- AppSearchSchema.PropertyConfig
+ AppSearchSchema.StringPropertyConfig
.INDEXING_TYPE_PREFIXES)
.setTokenizerType(
- AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ AppSearchSchema.StringPropertyConfig
+ .TOKENIZER_TYPE_PLAIN)
.build())
.build();
SchemaTypeConfigProto expectedEmailProto =
SchemaTypeConfigProto.newBuilder()
.setSchemaType("Email")
+ .setVersion(12345)
.addProperties(
PropertyConfigProto.newBuilder()
.setPropertyName("subject")
@@ -100,32 +100,27 @@
AppSearchSchema musicRecordingSchema =
new AppSearchSchema.Builder("MusicRecording")
.addProperty(
- new AppSearchSchema.PropertyConfig.Builder("artist")
- .setDataType(
- AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ new AppSearchSchema.StringPropertyConfig.Builder("artist")
.setCardinality(
AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
.setIndexingType(
- AppSearchSchema.PropertyConfig
+ AppSearchSchema.StringPropertyConfig
.INDEXING_TYPE_PREFIXES)
.setTokenizerType(
- AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ AppSearchSchema.StringPropertyConfig
+ .TOKENIZER_TYPE_PLAIN)
.build())
.addProperty(
- new AppSearchSchema.PropertyConfig.Builder("pubDate")
- .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ new AppSearchSchema.Int64PropertyConfig.Builder("pubDate")
.setCardinality(
AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(
- AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
- .setTokenizerType(
- AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
.build())
.build();
SchemaTypeConfigProto expectedMusicRecordingProto =
SchemaTypeConfigProto.newBuilder()
.setSchemaType("MusicRecording")
+ .setVersion(0)
.addProperties(
PropertyConfigProto.newBuilder()
.setPropertyName("artist")
@@ -144,14 +139,7 @@
.setPropertyName("pubDate")
.setDataType(PropertyConfigProto.DataType.Code.INT64)
.setCardinality(
- PropertyConfigProto.Cardinality.Code.OPTIONAL)
- .setStringIndexingConfig(
- StringIndexingConfig.newBuilder()
- .setTokenizerType(
- StringIndexingConfig.TokenizerType
- .Code.NONE)
- .setTermMatchType(
- TermMatchType.Code.UNKNOWN)))
+ PropertyConfigProto.Cardinality.Code.OPTIONAL))
.build();
assertThat(SchemaToProtoConverter.toSchemaTypeConfigProto(musicRecordingSchema))
diff --git a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
index 4ecaac5..79a5ed6 100644
--- a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
@@ -17,6 +17,7 @@
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@@ -27,6 +28,7 @@
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
+import android.content.Intent;
import android.media.AudioManager;
import android.media.AudioSystem;
import android.util.Log;
@@ -58,7 +60,7 @@
@Mock private AudioService mMockAudioService;
@Spy private AudioDeviceInventory mSpyDevInventory;
@Spy private AudioSystemAdapter mSpyAudioSystem;
- private SystemServerAdapter mSystemServer;
+ @Spy private SystemServerAdapter mSpySystemServer;
private BluetoothDevice mFakeBtDevice;
@@ -69,9 +71,9 @@
mMockAudioService = mock(AudioService.class);
mSpyAudioSystem = spy(new NoOpAudioSystemAdapter());
mSpyDevInventory = spy(new AudioDeviceInventory(mSpyAudioSystem));
- mSystemServer = new NoOpSystemServerAdapter();
+ mSpySystemServer = spy(new NoOpSystemServerAdapter());
mAudioDeviceBroker = new AudioDeviceBroker(mContext, mMockAudioService, mSpyDevInventory,
- mSystemServer);
+ mSpySystemServer);
mSpyDevInventory.setDeviceBroker(mAudioDeviceBroker);
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
@@ -172,6 +174,30 @@
true);
}
+ /**
+ * Test that device wired state intents are broadcasted on connection state change
+ * @throws Exception
+ */
+ @Test
+ public void testSetWiredDeviceConnectionState() throws Exception {
+ Log.i(TAG, "starting postSetWiredDeviceConnectionState");
+
+ final String address = "testAddress";
+ final String name = "testName";
+ final String caller = "testCaller";
+
+ doNothing().when(mSpySystemServer).broadcastStickyIntentToCurrentProfileGroup(
+ any(Intent.class));
+
+ mSpyDevInventory.setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET,
+ AudioService.CONNECTION_STATE_CONNECTED, address, name, caller);
+ Thread.sleep(MAX_MESSAGE_HANDLING_DELAY_MS);
+
+ // Verify that the sticky intent is broadcasted
+ verify(mSpySystemServer, times(1)).broadcastStickyIntentToCurrentProfileGroup(
+ any(Intent.class));
+ }
+
private void doTestConnectionDisconnectionReconnection(int delayAfterDisconnection,
boolean mockMediaPlayback, boolean guaranteeSingleConnection) throws Exception {
when(mMockAudioService.getDeviceForStream(AudioManager.STREAM_MUSIC))
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index cc4541b..832f918 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -34,11 +34,14 @@
import android.os.Binder;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
+import android.util.proto.ProtoOutputStream;
import androidx.annotation.NonNull;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
+import com.android.server.biometrics.nano.BiometricSchedulerProto;
+import com.android.server.biometrics.nano.BiometricsProto;
import com.android.server.biometrics.sensors.BiometricScheduler.Operation;
import org.junit.Before;
@@ -52,6 +55,7 @@
private static final String TAG = "BiometricSchedulerTest";
private static final int TEST_SENSOR_ID = 1;
+ private static final int LOG_NUM_RECENT_OPERATIONS = 2;
private BiometricScheduler mScheduler;
private IBinder mToken;
@@ -66,7 +70,7 @@
MockitoAnnotations.initMocks(this);
mToken = new Binder();
mScheduler = new BiometricScheduler(TAG, null /* gestureAvailabilityTracker */,
- mBiometricService);
+ mBiometricService, LOG_NUM_RECENT_OPERATIONS);
}
@Test
@@ -186,6 +190,88 @@
assertNull(mScheduler.mCurrentOperation);
}
+ @Test
+ public void testProtoDump_singleCurrentOperation() throws Exception {
+ // Nothing so far
+ BiometricSchedulerProto bsp = getDump(true /* clearSchedulerBuffer */);
+ assertEquals(BiometricsProto.CM_NONE, bsp.currentOperation);
+ assertEquals(0, bsp.totalOperations);
+ assertEquals(0, bsp.recentOperations.length);
+
+ // Pretend the scheduler is busy enrolling, and check the proto dump again.
+ final TestClientMonitor2 client = new TestClientMonitor2(mContext, mToken,
+ () -> mock(Object.class), BiometricsProto.CM_ENROLL);
+ mScheduler.scheduleClientMonitor(client);
+ waitForIdle();
+ bsp = getDump(true /* clearSchedulerBuffer */);
+ assertEquals(BiometricsProto.CM_ENROLL, bsp.currentOperation);
+ // No operations have completed yet
+ assertEquals(0, bsp.totalOperations);
+ assertEquals(0, bsp.recentOperations.length);
+ // Finish this operation, so the next scheduled one can start
+ client.getCallback().onClientFinished(client, true);
+ }
+
+ @Test
+ public void testProtoDump_fifo() throws Exception {
+ // Add the first operation
+ final TestClientMonitor2 client = new TestClientMonitor2(mContext, mToken,
+ () -> mock(Object.class), BiometricsProto.CM_ENROLL);
+ mScheduler.scheduleClientMonitor(client);
+ waitForIdle();
+ BiometricSchedulerProto bsp = getDump(false /* clearSchedulerBuffer */);
+ assertEquals(BiometricsProto.CM_ENROLL, bsp.currentOperation);
+ // No operations have completed yet
+ assertEquals(0, bsp.totalOperations);
+ assertEquals(0, bsp.recentOperations.length);
+ // Finish this operation, so the next scheduled one can start
+ client.getCallback().onClientFinished(client, true);
+
+ // Add another operation
+ final TestClientMonitor2 client2 = new TestClientMonitor2(mContext, mToken,
+ () -> mock(Object.class), BiometricsProto.CM_REMOVE);
+ mScheduler.scheduleClientMonitor(client2);
+ waitForIdle();
+ bsp = getDump(false /* clearSchedulerBuffer */);
+ assertEquals(BiometricsProto.CM_REMOVE, bsp.currentOperation);
+ assertEquals(1, bsp.totalOperations); // Enroll finished
+ assertEquals(1, bsp.recentOperations.length);
+ assertEquals(BiometricsProto.CM_ENROLL, bsp.recentOperations[0]);
+ client2.getCallback().onClientFinished(client2, true);
+
+ // And another operation
+ final TestClientMonitor2 client3 = new TestClientMonitor2(mContext, mToken,
+ () -> mock(Object.class), BiometricsProto.CM_AUTHENTICATE);
+ mScheduler.scheduleClientMonitor(client3);
+ waitForIdle();
+ bsp = getDump(false /* clearSchedulerBuffer */);
+ assertEquals(BiometricsProto.CM_AUTHENTICATE, bsp.currentOperation);
+ assertEquals(2, bsp.totalOperations);
+ assertEquals(2, bsp.recentOperations.length);
+ assertEquals(BiometricsProto.CM_ENROLL, bsp.recentOperations[0]);
+ assertEquals(BiometricsProto.CM_REMOVE, bsp.recentOperations[1]);
+
+ // Finish the last operation, and check that the first operation is removed from the FIFO.
+ // The test initializes the scheduler with "LOG_NUM_RECENT_OPERATIONS = 2" :)
+ client3.getCallback().onClientFinished(client3, true);
+ waitForIdle();
+ bsp = getDump(true /* clearSchedulerBuffer */);
+ assertEquals(3, bsp.totalOperations);
+ assertEquals(2, bsp.recentOperations.length);
+ assertEquals(BiometricsProto.CM_REMOVE, bsp.recentOperations[0]);
+ assertEquals(BiometricsProto.CM_AUTHENTICATE, bsp.recentOperations[1]);
+ // Nothing is currently running anymore
+ assertEquals(BiometricsProto.CM_NONE, bsp.currentOperation);
+
+ // RecentOperations queue is cleared (by the previous dump)
+ bsp = getDump(true /* clearSchedulerBuffer */);
+ assertEquals(0, bsp.recentOperations.length);
+ }
+
+ private BiometricSchedulerProto getDump(boolean clearSchedulerBuffer) throws Exception {
+ return BiometricSchedulerProto.parseFrom(mScheduler.dumpProtoState(clearSchedulerBuffer));
+ }
+
private static class BiometricPromptClientMonitor extends AuthenticationClient<Object> {
public BiometricPromptClientMonitor(@NonNull Context context, @NonNull IBinder token,
@@ -207,6 +293,21 @@
}
}
+ private static class TestClientMonitor2 extends TestClientMonitor {
+ private final int mProtoEnum;
+
+ public TestClientMonitor2(@NonNull Context context, @NonNull IBinder token,
+ @NonNull LazyDaemon<Object> lazyDaemon, int protoEnum) {
+ super(context, token, lazyDaemon);
+ mProtoEnum = protoEnum;
+ }
+
+ @Override
+ public int getProtoEnum() {
+ return mProtoEnum;
+ }
+ }
+
private static class TestClientMonitor extends HalClientMonitor<Object> {
private boolean mUnableToStart;
private boolean mStarted;
@@ -230,6 +331,13 @@
}
@Override
+ public int getProtoEnum() {
+ // Anything other than CM_NONE, which is used to represent "idle". Tests that need
+ // real proto enums should use TestClientMonitor2
+ return BiometricsProto.CM_UPDATE_ACTIVE_USER;
+ }
+
+ @Override
public void start(@NonNull Callback callback) {
super.start(callback);
assertFalse(mStarted);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 065a2f3..2e97a8d 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -31,6 +31,7 @@
import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
import static android.app.admin.PasswordMetrics.computeForPassword;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
+import static android.net.InetAddresses.parseNumericAddress;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback;
@@ -66,6 +67,8 @@
import static org.mockito.hamcrest.MockitoHamcrest.argThat;
import static org.testng.Assert.assertThrows;
+import static java.util.Collections.emptyList;
+
import android.Manifest.permission;
import android.app.Activity;
import android.app.AppOpsManager;
@@ -126,6 +129,8 @@
import org.mockito.stubbing.Answer;
import java.io.File;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -2360,6 +2365,49 @@
}
@Test
+ public void testGetProxyParameters() throws Exception {
+ assertThat(dpm.getProxyParameters(inetAddrProxy("192.0.2.1", 1234), emptyList()))
+ .isEqualTo(new Pair<>("192.0.2.1:1234", ""));
+ assertThat(dpm.getProxyParameters(inetAddrProxy("192.0.2.1", 1234),
+ listOf("one.example.com ", " two.example.com ")))
+ .isEqualTo(new Pair<>("192.0.2.1:1234", "one.example.com,two.example.com"));
+ assertThat(dpm.getProxyParameters(hostnameProxy("proxy.example.com", 1234), emptyList()))
+ .isEqualTo(new Pair<>("proxy.example.com:1234", ""));
+ assertThat(dpm.getProxyParameters(hostnameProxy("proxy.example.com", 1234),
+ listOf("excluded.example.com")))
+ .isEqualTo(new Pair<>("proxy.example.com:1234", "excluded.example.com"));
+
+ assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
+ inetAddrProxy("192.0.2.1", 0), emptyList()));
+ assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
+ hostnameProxy("", 1234), emptyList()));
+ assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
+ hostnameProxy("", 0), emptyList()));
+ assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
+ hostnameProxy("invalid! hostname", 1234), emptyList()));
+ assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
+ hostnameProxy("proxy.example.com", 1234), listOf("invalid exclusion")));
+ assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
+ hostnameProxy("proxy.example.com", -1), emptyList()));
+ assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
+ hostnameProxy("proxy.example.com", 0xFFFF + 1), emptyList()));
+ }
+
+ private static Proxy inetAddrProxy(String inetAddr, int port) {
+ return new Proxy(
+ Proxy.Type.HTTP, new InetSocketAddress(parseNumericAddress(inetAddr), port));
+ }
+
+ private static Proxy hostnameProxy(String hostname, int port) {
+ return new Proxy(
+ Proxy.Type.HTTP, InetSocketAddress.createUnresolved(hostname, port));
+ }
+
+ private static List<String> listOf(String... args) {
+ return Arrays.asList(args);
+ }
+
+ @Test
public void testSetKeyguardDisabledFeaturesWithDO() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -3289,7 +3337,7 @@
.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)).thenReturn(false);
initializeDpms();
when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(false);
- when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+ when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, false))
.thenReturn(true);
setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
@@ -3331,7 +3379,7 @@
.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)).thenReturn(false);
initializeDpms();
when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(false);
- when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+ when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, false))
.thenReturn(true);
setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
@@ -3395,7 +3443,7 @@
when(getServices().ipackageManager
.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)).thenReturn(true);
when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(false);
- when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+ when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, false))
.thenReturn(true);
setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
when(getServices().userManager.getProfileParent(UserHandle.USER_SYSTEM)).thenReturn(null);
@@ -3439,7 +3487,7 @@
when(getServices().ipackageManager
.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)).thenReturn(true);
when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(false);
- when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+ when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, false))
.thenReturn(true);
setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM);
when(getServices().userManager.getProfileParent(UserHandle.USER_SYSTEM)).thenReturn(null);
@@ -3459,8 +3507,6 @@
final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 1308);
when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM,
false /* we can't remove a managed profile */)).thenReturn(false);
- when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM,
- true)).thenReturn(true);
}
@Test
@@ -3620,7 +3666,7 @@
when(getServices().ipackageManager
.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)).thenReturn(true);
when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(true);
- when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+ when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, false))
.thenReturn(false);
setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
@@ -3664,7 +3710,7 @@
when(getServices().ipackageManager
.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)).thenReturn(true);
when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(true);
- when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+ when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, false))
.thenReturn(false);
setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM);
@@ -3711,7 +3757,7 @@
.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)).thenReturn(true);
when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(true);
when(getServices().userManager.canAddMoreManagedProfiles(CALLER_USER_HANDLE,
- true)).thenReturn(true);
+ false)).thenReturn(true);
setUserSetupCompleteForUser(false, CALLER_USER_HANDLE);
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
@@ -3753,7 +3799,7 @@
.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)).thenReturn(true);
when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(true);
when(getServices().userManager.canAddMoreManagedProfiles(CALLER_USER_HANDLE,
- true)).thenReturn(true);
+ false)).thenReturn(true);
setUserSetupCompleteForUser(true, CALLER_USER_HANDLE);
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
@@ -3800,7 +3846,7 @@
when(getServices().ipackageManager
.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)).thenReturn(true);
when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(true);
- when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
+ when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, false))
.thenReturn(false);
setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM);
@@ -3835,7 +3881,7 @@
when(getServices().userManager.getProfileParent(CALLER_USER_HANDLE))
.thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
when(getServices().userManager.canAddMoreManagedProfiles(CALLER_USER_HANDLE,
- true)).thenReturn(true);
+ false)).thenReturn(true);
setUserSetupCompleteForUser(false, CALLER_USER_HANDLE);
mContext.binder.callingUid = DpmMockContext.ANOTHER_UID;
@@ -3861,7 +3907,7 @@
DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE);
}
- private void setup_provisionManagedProfileCantRemoveUser_primaryUser() throws Exception {
+ private void setup_provisionManagedProfileOneAlreadyExist_primaryUser() throws Exception {
setDeviceOwner();
when(getServices().ipackageManager
@@ -3873,26 +3919,24 @@
.thenReturn(true);
when(getServices().userManager.canAddMoreManagedProfiles(CALLER_USER_HANDLE,
false /* we can't remove a managed profile */)).thenReturn(false);
- when(getServices().userManager.canAddMoreManagedProfiles(CALLER_USER_HANDLE,
- true)).thenReturn(true);
setUserSetupCompleteForUser(false, CALLER_USER_HANDLE);
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
}
@Test
- public void testIsProvisioningAllowed_provisionManagedProfileCantRemoveUser_primaryUser()
+ public void testIsProvisioningAllowed_provisionManagedProfile_oneAlreadyExists_primaryUser()
throws Exception {
- setup_provisionManagedProfileCantRemoveUser_primaryUser();
+ setup_provisionManagedProfileOneAlreadyExist_primaryUser();
mContext.packageName = admin1.getPackageName();
setUpPackageManagerForAdmin(admin1, mContext.binder.callingUid);
assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
}
@Test
- public void testCheckProvisioningPreCondition_provisionManagedProfileCantRemoveUser_primaryUser()
+ public void testCheckProvisioningPreCondition_provisionManagedProfile_oneAlreadyExists_primaryUser()
throws Exception {
- setup_provisionManagedProfileCantRemoveUser_primaryUser();
+ setup_provisionManagedProfileOneAlreadyExist_primaryUser();
mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
assertCheckProvisioningPreCondition(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE,
DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE);
@@ -5494,7 +5538,7 @@
// Attempt to set to empty list (which means no listener is allowlisted)
mContext.binder.callingUid = adminUid;
assertThat(dpms.setPermittedCrossProfileNotificationListeners(
- admin1, Collections.emptyList())).isFalse();
+ admin1, emptyList())).isFalse();
assertThat(dpms.getPermittedCrossProfileNotificationListeners(admin1)).isNull();
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
@@ -5588,7 +5632,7 @@
// Setting an empty allowlist - only system listeners allowed
mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
assertThat(dpms.setPermittedCrossProfileNotificationListeners(
- admin1, Collections.emptyList())).isTrue();
+ admin1, emptyList())).isTrue();
assertThat(dpms.getPermittedCrossProfileNotificationListeners(admin1).size()).isEqualTo(0);
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
@@ -5653,7 +5697,7 @@
// all allowed in primary profile
mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
assertThat(dpms.setPermittedCrossProfileNotificationListeners(
- admin1, Collections.emptyList())).isTrue();
+ admin1, emptyList())).isTrue();
assertThat(dpms.getPermittedCrossProfileNotificationListeners(admin1).size()).isEqualTo(0);
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
diff --git a/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java b/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
index 0cf0af3..75bf1e6 100644
--- a/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
+++ b/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
@@ -19,6 +19,8 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
+import static org.junit.Assert.fail;
+
import android.content.Context;
import android.os.FileUtils;
import android.platform.test.annotations.Presubmit;
@@ -35,7 +37,12 @@
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
import java.util.Map;
+import java.util.Set;
@Presubmit
@SmallTest
@@ -44,17 +51,63 @@
/**
* A {@link UpdatableFontDir.FontFileParser} for testing. Instead of using real font files,
- * this test uses fake font files. A fake font file has its version as its file content.
+ * this test uses fake font files. A fake font file has its PostScript naem and revision as the
+ * file content.
*/
private static class FakeFontFileParser implements UpdatableFontDir.FontFileParser {
@Override
- public long getVersion(File file) throws IOException {
- return Long.parseLong(FileUtils.readTextFile(file, 100, ""));
+ public String getPostScriptName(File file) throws IOException {
+ String content = FileUtils.readTextFile(file, 100, "");
+ return content.split(",")[0];
+ }
+
+ @Override
+ public long getRevision(File file) throws IOException {
+ String content = FileUtils.readTextFile(file, 100, "");
+ return Long.parseLong(content.split(",")[1]);
+ }
+ }
+
+ // FakeFsverityUtil will successfully set up fake fs-verity if the signature is GOOD_SIGNATURE.
+ private static final String GOOD_SIGNATURE = "Good signature";
+
+ /** A fake FsverityUtil to keep fake verity bit in memory. */
+ private static class FakeFsverityUtil implements UpdatableFontDir.FsverityUtil {
+ private final Set<String> mHasFsverityPaths = new HashSet<>();
+
+ public void remove(String name) {
+ mHasFsverityPaths.remove(name);
+ }
+
+ @Override
+ public boolean hasFsverity(String path) {
+ return mHasFsverityPaths.contains(path);
+ }
+
+ @Override
+ public void setUpFsverity(String path, byte[] pkcs7Signature) throws IOException {
+ String fakeSignature = new String(pkcs7Signature, StandardCharsets.UTF_8);
+ if (GOOD_SIGNATURE.equals(fakeSignature)) {
+ mHasFsverityPaths.add(path);
+ } else {
+ throw new IOException("Failed to set up fake fs-verity");
+ }
+ }
+
+ @Override
+ public boolean rename(File src, File dest) {
+ if (src.renameTo(dest)) {
+ mHasFsverityPaths.remove(src.getAbsolutePath());
+ mHasFsverityPaths.add(dest.getAbsolutePath());
+ return true;
+ }
+ return false;
}
}
private File mCacheDir;
private File mUpdatableFontFilesDir;
+ private List<File> mPreinstalledFontDirs;
@SuppressWarnings("ResultOfMethodCallIgnored")
@Before
@@ -65,6 +118,12 @@
mCacheDir.mkdirs();
mUpdatableFontFilesDir = new File(mCacheDir, "updatable_fonts");
mUpdatableFontFilesDir.mkdir();
+ mPreinstalledFontDirs = new ArrayList<>();
+ mPreinstalledFontDirs.add(new File(mCacheDir, "system_fonts"));
+ mPreinstalledFontDirs.add(new File(mCacheDir, "product_fonts"));
+ for (File dir : mPreinstalledFontDirs) {
+ dir.mkdir();
+ }
}
@After
@@ -75,19 +134,22 @@
@Test
public void construct() throws Exception {
FakeFontFileParser parser = new FakeFontFileParser();
- UpdatableFontDir dirForPreparation = new UpdatableFontDir(mUpdatableFontFilesDir, parser);
- installFontFile(dirForPreparation, "foo.ttf", "1");
- installFontFile(dirForPreparation, "bar.ttf", "2");
- installFontFile(dirForPreparation, "foo.ttf", "3");
- installFontFile(dirForPreparation, "bar.ttf", "4");
+ FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
+ UpdatableFontDir dirForPreparation = new UpdatableFontDir(
+ mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil);
+ installFontFile(dirForPreparation, "foo,1", GOOD_SIGNATURE);
+ installFontFile(dirForPreparation, "bar,2", GOOD_SIGNATURE);
+ installFontFile(dirForPreparation, "foo,3", GOOD_SIGNATURE);
+ installFontFile(dirForPreparation, "bar,4", GOOD_SIGNATURE);
// Four font dirs are created.
assertThat(mUpdatableFontFilesDir.list()).hasLength(4);
- UpdatableFontDir dir = new UpdatableFontDir(mUpdatableFontFilesDir, parser);
+ UpdatableFontDir dir = new UpdatableFontDir(
+ mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil);
assertThat(dir.getFontFileMap()).containsKey("foo.ttf");
- assertThat(parser.getVersion(dir.getFontFileMap().get("foo.ttf"))).isEqualTo(3);
+ assertThat(parser.getRevision(dir.getFontFileMap().get("foo.ttf"))).isEqualTo(3);
assertThat(dir.getFontFileMap()).containsKey("bar.ttf");
- assertThat(parser.getVersion(dir.getFontFileMap().get("bar.ttf"))).isEqualTo(4);
+ assertThat(parser.getRevision(dir.getFontFileMap().get("bar.ttf"))).isEqualTo(4);
// Outdated font dir should be deleted.
assertThat(mUpdatableFontFilesDir.list()).hasLength(2);
}
@@ -95,66 +157,189 @@
@Test
public void construct_empty() {
FakeFontFileParser parser = new FakeFontFileParser();
- UpdatableFontDir dir = new UpdatableFontDir(mUpdatableFontFilesDir, parser);
+ FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
+ UpdatableFontDir dir = new UpdatableFontDir(
+ mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil);
assertThat(dir.getFontFileMap()).isEmpty();
}
@Test
+ public void construct_missingFsverity() throws Exception {
+ FakeFontFileParser parser = new FakeFontFileParser();
+ FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
+ UpdatableFontDir dirForPreparation = new UpdatableFontDir(
+ mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil);
+ installFontFile(dirForPreparation, "foo,1", GOOD_SIGNATURE);
+ installFontFile(dirForPreparation, "bar,2", GOOD_SIGNATURE);
+ installFontFile(dirForPreparation, "foo,3", GOOD_SIGNATURE);
+ installFontFile(dirForPreparation, "bar,4", GOOD_SIGNATURE);
+ // Four font dirs are created.
+ assertThat(mUpdatableFontFilesDir.list()).hasLength(4);
+
+ fakeFsverityUtil.remove(
+ dirForPreparation.getFontFileMap().get("foo.ttf").getAbsolutePath());
+ UpdatableFontDir dir = new UpdatableFontDir(
+ mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil);
+ assertThat(dir.getFontFileMap()).isEmpty();
+ // All font dirs (including dir for "bar.ttf") should be deleted.
+ assertThat(mUpdatableFontFilesDir.list()).hasLength(0);
+ }
+
+ @Test
+ public void construct_fontNameMismatch() throws Exception {
+ FakeFontFileParser parser = new FakeFontFileParser();
+ FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
+ UpdatableFontDir dirForPreparation = new UpdatableFontDir(
+ mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil);
+ installFontFile(dirForPreparation, "foo,1", GOOD_SIGNATURE);
+ installFontFile(dirForPreparation, "bar,2", GOOD_SIGNATURE);
+ installFontFile(dirForPreparation, "foo,3", GOOD_SIGNATURE);
+ installFontFile(dirForPreparation, "bar,4", GOOD_SIGNATURE);
+ // Four font dirs are created.
+ assertThat(mUpdatableFontFilesDir.list()).hasLength(4);
+
+ // Overwrite "foo.ttf" with wrong contents.
+ FileUtils.stringToFile(dirForPreparation.getFontFileMap().get("foo.ttf"), "bar,4");
+
+ UpdatableFontDir dir = new UpdatableFontDir(
+ mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil);
+ assertThat(dir.getFontFileMap()).isEmpty();
+ // All font dirs (including dir for "bar.ttf") should be deleted.
+ assertThat(mUpdatableFontFilesDir.list()).hasLength(0);
+ }
+
+ @Test
+ public void construct_olderThanPreinstalledFont() throws Exception {
+ FakeFontFileParser parser = new FakeFontFileParser();
+ FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
+ UpdatableFontDir dirForPreparation = new UpdatableFontDir(
+ mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil);
+ installFontFile(dirForPreparation, "foo,1", GOOD_SIGNATURE);
+ installFontFile(dirForPreparation, "bar,2", GOOD_SIGNATURE);
+ installFontFile(dirForPreparation, "foo,3", GOOD_SIGNATURE);
+ installFontFile(dirForPreparation, "bar,4", GOOD_SIGNATURE);
+ // Four font dirs are created.
+ assertThat(mUpdatableFontFilesDir.list()).hasLength(4);
+
+ // Add preinstalled fonts.
+ FileUtils.stringToFile(new File(mPreinstalledFontDirs.get(0), "foo.ttf"), "foo,5");
+ FileUtils.stringToFile(new File(mPreinstalledFontDirs.get(0), "bar.ttf"), "bar,1");
+ FileUtils.stringToFile(new File(mPreinstalledFontDirs.get(1), "bar.ttf"), "bar,2");
+ UpdatableFontDir dir = new UpdatableFontDir(
+ mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil);
+ // For foo.ttf, preinstalled font (revision 5) should be used.
+ assertThat(dir.getFontFileMap()).doesNotContainKey("foo.ttf");
+ // For bar.ttf, updated font (revision 4) should be used.
+ assertThat(dir.getFontFileMap()).containsKey("bar.ttf");
+ assertThat(parser.getRevision(dir.getFontFileMap().get("bar.ttf"))).isEqualTo(4);
+ // Outdated font dir should be deleted.
+ // We don't delete bar.ttf in this case, because it's normal that OTA updates preinstalled
+ // fonts.
+ assertThat(mUpdatableFontFilesDir.list()).hasLength(1);
+ }
+
+ @Test
public void installFontFile() throws Exception {
FakeFontFileParser parser = new FakeFontFileParser();
- UpdatableFontDir dir = new UpdatableFontDir(mUpdatableFontFilesDir, parser);
+ FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
+ UpdatableFontDir dir = new UpdatableFontDir(
+ mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil);
- installFontFile(dir, "test.ttf", "1");
+ installFontFile(dir, "test,1", GOOD_SIGNATURE);
assertThat(dir.getFontFileMap()).containsKey("test.ttf");
- assertThat(parser.getVersion(dir.getFontFileMap().get("test.ttf"))).isEqualTo(1);
+ assertThat(parser.getRevision(dir.getFontFileMap().get("test.ttf"))).isEqualTo(1);
}
@Test
public void installFontFile_upgrade() throws Exception {
FakeFontFileParser parser = new FakeFontFileParser();
- UpdatableFontDir dir = new UpdatableFontDir(mUpdatableFontFilesDir, parser);
+ FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
+ UpdatableFontDir dir = new UpdatableFontDir(
+ mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil);
- installFontFile(dir, "test.ttf", "1");
+ installFontFile(dir, "test,1", GOOD_SIGNATURE);
Map<String, File> mapBeforeUpgrade = dir.getFontFileMap();
- installFontFile(dir, "test.ttf", "2");
+ installFontFile(dir, "test,2", GOOD_SIGNATURE);
assertThat(dir.getFontFileMap()).containsKey("test.ttf");
- assertThat(parser.getVersion(dir.getFontFileMap().get("test.ttf"))).isEqualTo(2);
+ assertThat(parser.getRevision(dir.getFontFileMap().get("test.ttf"))).isEqualTo(2);
assertThat(mapBeforeUpgrade).containsKey("test.ttf");
assertWithMessage("Older fonts should not be deleted until next loadFontFileMap")
- .that(parser.getVersion(mapBeforeUpgrade.get("test.ttf"))).isEqualTo(1);
+ .that(parser.getRevision(mapBeforeUpgrade.get("test.ttf"))).isEqualTo(1);
}
@Test
public void installFontFile_downgrade() throws Exception {
FakeFontFileParser parser = new FakeFontFileParser();
- UpdatableFontDir dir = new UpdatableFontDir(mUpdatableFontFilesDir, parser);
+ FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
+ UpdatableFontDir dir = new UpdatableFontDir(
+ mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil);
- installFontFile(dir, "test.ttf", "2");
- installFontFile(dir, "test.ttf", "1");
+ installFontFile(dir, "test,2", GOOD_SIGNATURE);
+ try {
+ installFontFile(dir, "test,1", GOOD_SIGNATURE);
+ fail("Expect IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // Expect
+ }
assertThat(dir.getFontFileMap()).containsKey("test.ttf");
- assertWithMessage("Font should not be downgraded to an older version")
- .that(parser.getVersion(dir.getFontFileMap().get("test.ttf"))).isEqualTo(2);
+ assertWithMessage("Font should not be downgraded to an older revision")
+ .that(parser.getRevision(dir.getFontFileMap().get("test.ttf"))).isEqualTo(2);
}
@Test
public void installFontFile_multiple() throws Exception {
FakeFontFileParser parser = new FakeFontFileParser();
- UpdatableFontDir dir = new UpdatableFontDir(mUpdatableFontFilesDir, parser);
+ FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
+ UpdatableFontDir dir = new UpdatableFontDir(
+ mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil);
- installFontFile(dir, "foo.ttf", "1");
- installFontFile(dir, "bar.ttf", "2");
+ installFontFile(dir, "foo,1", GOOD_SIGNATURE);
+ installFontFile(dir, "bar,2", GOOD_SIGNATURE);
assertThat(dir.getFontFileMap()).containsKey("foo.ttf");
- assertThat(parser.getVersion(dir.getFontFileMap().get("foo.ttf"))).isEqualTo(1);
+ assertThat(parser.getRevision(dir.getFontFileMap().get("foo.ttf"))).isEqualTo(1);
assertThat(dir.getFontFileMap()).containsKey("bar.ttf");
- assertThat(parser.getVersion(dir.getFontFileMap().get("bar.ttf"))).isEqualTo(2);
+ assertThat(parser.getRevision(dir.getFontFileMap().get("bar.ttf"))).isEqualTo(2);
}
- private void installFontFile(UpdatableFontDir dir, String name, String content)
+ @Test
+ public void installFontFile_invalidSignature() {
+ FakeFontFileParser parser = new FakeFontFileParser();
+ FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
+ UpdatableFontDir dir = new UpdatableFontDir(
+ mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil);
+
+ try {
+ installFontFile(dir, "test,1", "Invalid signature");
+ fail("Expect IOException");
+ } catch (IOException e) {
+ // Expect
+ }
+ assertThat(dir.getFontFileMap()).isEmpty();
+ }
+
+ @Test
+ public void installFontFile_olderThanPreinstalledFont() throws Exception {
+ FakeFontFileParser parser = new FakeFontFileParser();
+ FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
+ FileUtils.stringToFile(new File(mPreinstalledFontDirs.get(0), "test.ttf"), "test,1");
+ UpdatableFontDir dir = new UpdatableFontDir(
+ mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil);
+
+ try {
+ installFontFile(dir, "test,1", GOOD_SIGNATURE);
+ fail("Expect IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // Expect
+ }
+ assertThat(dir.getFontFileMap()).isEmpty();
+ }
+
+ private void installFontFile(UpdatableFontDir dir, String content, String signature)
throws IOException {
- File file = File.createTempFile(name, "", mCacheDir);
+ File file = File.createTempFile("font", "ttf", mCacheDir);
FileUtils.stringToFile(file, content);
try (FileInputStream in = new FileInputStream(file)) {
- dir.installFontFile(name, in.getFD());
+ dir.installFontFile(in.getFD(), signature.getBytes());
}
}
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/ResumeOnRebootServiceProviderTests.java b/services/tests/servicestests/src/com/android/server/locksettings/ResumeOnRebootServiceProviderTests.java
new file mode 100644
index 0000000..b9af82b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/locksettings/ResumeOnRebootServiceProviderTests.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.locksettings;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.Manifest;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.service.resumeonreboot.ResumeOnRebootService;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+
+@SmallTest
+@RunWith(JUnit4.class)
+public class ResumeOnRebootServiceProviderTests {
+
+ @Mock
+ Context mMockContext;
+ @Mock
+ PackageManager mMockPackageManager;
+ @Mock
+ ResolveInfo mMockResolvedInfo;
+ @Mock
+ ServiceInfo mMockServiceInfo;
+ @Mock
+ ComponentName mMockComponentName;
+ @Captor
+ ArgumentCaptor<Intent> mIntentArgumentCaptor;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mMockContext.getUserId()).thenReturn(0);
+ when(mMockResolvedInfo.serviceInfo).thenReturn(mMockServiceInfo);
+ when(mMockServiceInfo.getComponentName()).thenReturn(mMockComponentName);
+ }
+
+ @Test
+ public void noServiceFound() throws Exception {
+ when(mMockPackageManager.queryIntentServices(any(),
+ eq(PackageManager.MATCH_SYSTEM_ONLY))).thenReturn(
+ null);
+ assertThat(new ResumeOnRebootServiceProvider(mMockContext,
+ mMockPackageManager).getServiceConnection()).isNull();
+ }
+
+ @Test
+ public void serviceNotGuardedWithPermission() throws Exception {
+ ArrayList<ResolveInfo> resultList = new ArrayList<>();
+ when(mMockServiceInfo.permission).thenReturn("");
+ resultList.add(mMockResolvedInfo);
+ when(mMockPackageManager.queryIntentServices(any(), any())).thenReturn(
+ resultList);
+ assertThat(new ResumeOnRebootServiceProvider(mMockContext,
+ mMockPackageManager).getServiceConnection()).isNull();
+ }
+
+ @Test
+ public void serviceResolved() throws Exception {
+ ArrayList<ResolveInfo> resultList = new ArrayList<>();
+ resultList.add(mMockResolvedInfo);
+ when(mMockServiceInfo.permission).thenReturn(
+ Manifest.permission.BIND_RESUME_ON_REBOOT_SERVICE);
+ when(mMockPackageManager.queryIntentServices(any(),
+ eq(PackageManager.MATCH_SYSTEM_ONLY))).thenReturn(
+ resultList);
+
+ assertThat(new ResumeOnRebootServiceProvider(mMockContext,
+ mMockPackageManager).getServiceConnection()).isNotNull();
+
+ verify(mMockPackageManager).queryIntentServices(mIntentArgumentCaptor.capture(),
+ eq(PackageManager.MATCH_SYSTEM_ONLY));
+ assertThat(mIntentArgumentCaptor.getValue().getAction()).isEqualTo(
+ ResumeOnRebootService.SERVICE_INTERFACE);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java
index 391611b..5468fba 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java
@@ -78,7 +78,7 @@
}
@Test
- public void testImmutableEnabledChange() {
+ public void testImmutableEnabledChange() throws Exception {
final OverlayManagerServiceImpl impl = getImpl();
installNewPackage(target(TARGET), USER);
installNewPackage(overlay(OVERLAY, TARGET), USER);
@@ -106,7 +106,7 @@
}
@Test
- public void testMutableEnabledChangeHasNoEffect() {
+ public void testMutableEnabledChangeHasNoEffect() throws Exception {
final OverlayManagerServiceImpl impl = getImpl();
installNewPackage(target(TARGET), USER);
installNewPackage(overlay(OVERLAY, TARGET), USER);
@@ -134,7 +134,7 @@
}
@Test
- public void testMutableEnabledToImmutableEnabled() {
+ public void testMutableEnabledToImmutableEnabled() throws Exception {
final OverlayManagerServiceImpl impl = getImpl();
installNewPackage(target(TARGET), USER);
installNewPackage(overlay(OVERLAY, TARGET), USER);
@@ -178,7 +178,7 @@
}
@Test
- public void testMutablePriorityChange() {
+ public void testMutablePriorityChange() throws Exception {
final OverlayManagerServiceImpl impl = getImpl();
installNewPackage(target(TARGET), USER);
installNewPackage(overlay(OVERLAY, TARGET), USER);
@@ -218,7 +218,7 @@
}
@Test
- public void testImmutablePriorityChange() {
+ public void testImmutablePriorityChange() throws Exception {
final OverlayManagerServiceImpl impl = getImpl();
installNewPackage(target(TARGET), USER);
installNewPackage(overlay(OVERLAY, TARGET), USER);
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
index 4f882ce..33dbcc0 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
@@ -22,11 +22,14 @@
import static android.os.OverlayablePolicy.CONFIG_SIGNATURE;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.testng.Assert.assertThrows;
import android.content.om.OverlayInfo;
+import android.util.Pair;
import androidx.test.runner.AndroidJUnit4;
@@ -35,6 +38,7 @@
import java.util.List;
import java.util.Map;
+import java.util.Optional;
@RunWith(AndroidJUnit4.class)
public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTestsBase {
@@ -55,7 +59,7 @@
private static final String CERT_CONFIG_NOK = "config_certificate_nok";
@Test
- public void testGetOverlayInfo() {
+ public void testGetOverlayInfo() throws Exception {
installNewPackage(overlay(OVERLAY, TARGET), USER);
final OverlayManagerServiceImpl impl = getImpl();
@@ -67,7 +71,7 @@
}
@Test
- public void testGetOverlayInfosForTarget() {
+ public void testGetOverlayInfosForTarget() throws Exception {
installNewPackage(overlay(OVERLAY, TARGET), USER);
installNewPackage(overlay(OVERLAY2, TARGET), USER);
installNewPackage(overlay(OVERLAY3, TARGET), USER2);
@@ -92,7 +96,7 @@
}
@Test
- public void testGetOverlayInfosForUser() {
+ public void testGetOverlayInfosForUser() throws Exception {
installNewPackage(target(TARGET), USER);
installNewPackage(overlay(OVERLAY, TARGET), USER);
installNewPackage(overlay(OVERLAY2, TARGET), USER);
@@ -119,7 +123,7 @@
}
@Test
- public void testPriority() {
+ public void testPriority() throws Exception {
installNewPackage(overlay(OVERLAY, TARGET), USER);
installNewPackage(overlay(OVERLAY2, TARGET), USER);
installNewPackage(overlay(OVERLAY3, TARGET), USER);
@@ -131,18 +135,21 @@
assertOverlayInfoForTarget(TARGET, USER, o1, o2, o3);
- assertTrue(impl.setLowestPriority(OVERLAY3, USER));
+ assertEquals(impl.setLowestPriority(OVERLAY3, USER),
+ Optional.of(new PackageAndUser(TARGET, USER)));
assertOverlayInfoForTarget(TARGET, USER, o3, o1, o2);
- assertTrue(impl.setHighestPriority(OVERLAY3, USER));
+ assertEquals(impl.setHighestPriority(OVERLAY3, USER),
+ Optional.of(new PackageAndUser(TARGET, USER)));
assertOverlayInfoForTarget(TARGET, USER, o1, o2, o3);
- assertTrue(impl.setPriority(OVERLAY, OVERLAY2, USER));
+ assertEquals(impl.setPriority(OVERLAY, OVERLAY2, USER),
+ Optional.of(new PackageAndUser(TARGET, USER)));
assertOverlayInfoForTarget(TARGET, USER, o2, o1, o3);
}
@Test
- public void testOverlayInfoStateTransitions() {
+ public void testOverlayInfoStateTransitions() throws Exception {
final OverlayManagerServiceImpl impl = getImpl();
assertNull(impl.getOverlayInfo(OVERLAY, USER));
@@ -153,7 +160,8 @@
installNewPackage(target, USER);
assertState(STATE_DISABLED, OVERLAY, USER);
- impl.setEnabled(OVERLAY, true, USER);
+ assertEquals(impl.setEnabled(OVERLAY, true, USER),
+ Optional.of(new PackageAndUser(TARGET, USER)));
assertState(STATE_ENABLED, OVERLAY, USER);
// target upgrades do not change the state of the overlay
@@ -168,50 +176,40 @@
}
@Test
- public void testOnOverlayPackageUpgraded() {
- final FakeListener listener = getListener();
+ public void testOnOverlayPackageUpgraded() throws Exception {
final FakeDeviceState.PackageBuilder target = target(TARGET);
final FakeDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET);
installNewPackage(target, USER);
installNewPackage(overlay, USER);
- listener.count = 0;
upgradePackage(overlay, USER);
- assertEquals(2, listener.count);
// upgrade to a version where the overlay has changed its target
- // expect once for the old target package, once for the new target package
- listener.count = 0;
final FakeDeviceState.PackageBuilder overlay2 = overlay(OVERLAY, "some.other.target");
- upgradePackage(overlay2, USER);
- assertEquals(3, listener.count);
-
- listener.count = 0;
- upgradePackage(overlay2, USER);
- assertEquals(2, listener.count);
+ final Pair<Optional<PackageAndUser>, Optional<PackageAndUser>> pair =
+ upgradePackage(overlay2, USER);
+ assertEquals(pair.first, Optional.of(new PackageAndUser(TARGET, USER)));
+ assertEquals(pair.second, Optional.of(new PackageAndUser("some.other.target", USER)));
}
@Test
- public void testListener() {
+ public void testSetEnabledAtVariousConditions() throws Exception {
final OverlayManagerServiceImpl impl = getImpl();
- final FakeListener listener = getListener();
- installNewPackage(overlay(OVERLAY, TARGET), USER);
- assertEquals(1, listener.count);
- listener.count = 0;
+ assertThrows(OverlayManagerServiceImpl.OperationFailedException.class,
+ () -> impl.setEnabled(OVERLAY, true, USER));
+ // request succeeded, and there was a change that needs to be
+ // propagated to the rest of the system
installNewPackage(target(TARGET), USER);
- assertEquals(1, listener.count);
- listener.count = 0;
+ installNewPackage(overlay(OVERLAY, TARGET), USER);
+ assertEquals(impl.setEnabled(OVERLAY, true, USER),
+ Optional.of(new PackageAndUser(TARGET, USER)));
- impl.setEnabled(OVERLAY, true, USER);
- assertEquals(1, listener.count);
- listener.count = 0;
-
- impl.setEnabled(OVERLAY, true, USER);
- assertEquals(0, listener.count);
+ // request succeeded, but nothing changed
+ assertFalse(impl.setEnabled(OVERLAY, true, USER).isPresent());
}
@Test
- public void testConfigSignaturePolicyOk() {
+ public void testConfigSignaturePolicyOk() throws Exception {
setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG);
reinitializeImpl();
@@ -229,7 +227,7 @@
}
@Test
- public void testConfigSignaturePolicyCertNok() {
+ public void testConfigSignaturePolicyCertNok() throws Exception {
setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG);
reinitializeImpl();
@@ -247,7 +245,7 @@
}
@Test
- public void testConfigSignaturePolicyNoConfig() {
+ public void testConfigSignaturePolicyNoConfig() throws Exception {
addPackage(target(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER);
installNewPackage(target(TARGET), USER);
installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER);
@@ -262,7 +260,7 @@
}
@Test
- public void testConfigSignaturePolicyNoRefPkg() {
+ public void testConfigSignaturePolicyNoRefPkg() throws Exception {
installNewPackage(target(TARGET), USER);
installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER);
@@ -276,7 +274,7 @@
}
@Test
- public void testConfigSignaturePolicyRefPkgNotSystem() {
+ public void testConfigSignaturePolicyRefPkgNotSystem() throws Exception {
setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG);
reinitializeImpl();
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
index 006dda0..2c477c8 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
@@ -16,6 +16,8 @@
package com.android.server.om;
+import static com.android.server.om.OverlayManagerServiceImpl.OperationFailedException;
+
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
@@ -30,6 +32,7 @@
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Pair;
import androidx.annotation.Nullable;
@@ -43,13 +46,13 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.stream.Collectors;
/** Base class for creating {@link OverlayManagerServiceImplTests} tests. */
class OverlayManagerServiceImplTestsBase {
private OverlayManagerServiceImpl mImpl;
private FakeDeviceState mState;
- private FakeListener mListener;
private FakePackageManagerHelper mPackageManager;
private FakeIdmapDaemon mIdmapDaemon;
private OverlayConfig mOverlayConfig;
@@ -58,7 +61,6 @@
@Before
public void setUp() {
mState = new FakeDeviceState();
- mListener = new FakeListener();
mPackageManager = new FakePackageManagerHelper(mState);
mIdmapDaemon = new FakeIdmapDaemon(mState);
mOverlayConfig = mock(OverlayConfig.class);
@@ -73,18 +75,13 @@
new IdmapManager(mIdmapDaemon, mPackageManager),
new OverlayManagerSettings(),
mOverlayConfig,
- new String[0],
- mListener);
+ new String[0]);
}
OverlayManagerServiceImpl getImpl() {
return mImpl;
}
- FakeListener getListener() {
- return mListener;
- }
-
FakeIdmapDaemon getIdmapd() {
return mIdmapDaemon;
}
@@ -155,7 +152,8 @@
*
* @throws IllegalStateException if the package is currently installed
*/
- void installNewPackage(FakeDeviceState.PackageBuilder pkg, int userId) {
+ void installNewPackage(FakeDeviceState.PackageBuilder pkg, int userId)
+ throws OperationFailedException {
if (mState.select(pkg.packageName, userId) != null) {
throw new IllegalStateException("package " + pkg.packageName + " already installed");
}
@@ -176,23 +174,30 @@
* {@link android.content.Intent#ACTION_PACKAGE_ADDED} broadcast with the
* {@link android.content.Intent#EXTRA_REPLACING} extra.
*
+ * @return the two Optional<PackageAndUser> objects from starting and finishing the upgrade
+ *
* @throws IllegalStateException if the package is not currently installed
*/
- void upgradePackage(FakeDeviceState.PackageBuilder pkg, int userId) {
+ Pair<Optional<PackageAndUser>, Optional<PackageAndUser>> upgradePackage(
+ FakeDeviceState.PackageBuilder pkg, int userId) throws OperationFailedException {
final FakeDeviceState.Package replacedPackage = mState.select(pkg.packageName, userId);
if (replacedPackage == null) {
throw new IllegalStateException("package " + pkg.packageName + " not installed");
}
+ Optional<PackageAndUser> opt1 = Optional.empty();
if (replacedPackage.targetPackageName != null) {
- mImpl.onOverlayPackageReplacing(pkg.packageName, userId);
+ opt1 = mImpl.onOverlayPackageReplacing(pkg.packageName, userId);
}
mState.add(pkg, userId);
+ Optional<PackageAndUser> opt2;
if (pkg.targetPackage == null) {
- mImpl.onTargetPackageReplaced(pkg.packageName, userId);
+ opt2 = mImpl.onTargetPackageReplaced(pkg.packageName, userId);
} else {
- mImpl.onOverlayPackageReplaced(pkg.packageName, userId);
+ opt2 = mImpl.onOverlayPackageReplaced(pkg.packageName, userId);
}
+
+ return Pair.create(opt1, opt2);
}
/**
@@ -203,7 +208,7 @@
*
* @throws IllegalStateException if the package is not currently installed
*/
- void uninstallPackage(String packageName, int userId) {
+ void uninstallPackage(String packageName, int userId) throws OperationFailedException {
final FakeDeviceState.Package pkg = mState.select(packageName, userId);
if (pkg == null) {
throw new IllegalStateException("package " + packageName+ " not installed");
@@ -485,12 +490,4 @@
}
}
}
-
- static class FakeListener implements OverlayManagerServiceImpl.OverlayChangeListener {
- public int count;
-
- public void onOverlaysChanged(@NonNull String targetPackage, int userId) {
- count++;
- }
- }
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index b190339..395b643 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -219,8 +219,8 @@
mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_USER, /* value= */ true,
asHandle(currentUser));
try {
- assertThat(mUserManager.removeUserOrSetEphemeral(user1.id)).isEqualTo(
- UserManager.REMOVE_RESULT_ERROR);
+ assertThat(mUserManager.removeUserOrSetEphemeral(user1.id,
+ /* evenWhenDisallowed= */ false)).isEqualTo(UserManager.REMOVE_RESULT_ERROR);
} finally {
mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_USER, /* value= */ false,
asHandle(currentUser));
@@ -232,9 +232,32 @@
@MediumTest
@Test
+ public void testRemoveUserOrSetEphemeral_evenWhenRestricted() throws Exception {
+ final int currentUser = ActivityManager.getCurrentUser();
+ final UserInfo user1 = createUser("User 1", /* flags= */ 0);
+ mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_USER, /* value= */ true,
+ asHandle(currentUser));
+ try {
+ synchronized (mUserRemoveLock) {
+ assertThat(mUserManager.removeUserOrSetEphemeral(user1.id,
+ /* evenWhenDisallowed= */ true))
+ .isEqualTo(UserManager.REMOVE_RESULT_REMOVED);
+ waitForUserRemovalLocked(user1.id);
+ }
+
+ } finally {
+ mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_USER, /* value= */ false,
+ asHandle(currentUser));
+ }
+
+ assertThat(hasUser(user1.id)).isFalse();
+ }
+
+ @MediumTest
+ @Test
public void testRemoveUserOrSetEphemeral_systemUserReturnsError() throws Exception {
- assertThat(mUserManager.removeUserOrSetEphemeral(UserHandle.USER_SYSTEM)).isEqualTo(
- UserManager.REMOVE_RESULT_ERROR);
+ assertThat(mUserManager.removeUserOrSetEphemeral(UserHandle.USER_SYSTEM,
+ /* evenWhenDisallowed= */ false)).isEqualTo(UserManager.REMOVE_RESULT_ERROR);
assertThat(hasUser(UserHandle.USER_SYSTEM)).isTrue();
}
@@ -243,8 +266,8 @@
@Test
public void testRemoveUserOrSetEphemeral_invalidUserReturnsError() throws Exception {
assertThat(hasUser(Integer.MAX_VALUE)).isFalse();
- assertThat(mUserManager.removeUserOrSetEphemeral(Integer.MAX_VALUE)).isEqualTo(
- UserManager.REMOVE_RESULT_ERROR);
+ assertThat(mUserManager.removeUserOrSetEphemeral(Integer.MAX_VALUE,
+ /* evenWhenDisallowed= */ false)).isEqualTo(UserManager.REMOVE_RESULT_ERROR);
}
@MediumTest
@@ -255,8 +278,8 @@
// Switch to the user just created.
switchUser(user1.id, null, /* ignoreHandle= */ true);
- assertThat(mUserManager.removeUserOrSetEphemeral(user1.id)).isEqualTo(
- UserManager.REMOVE_RESULT_SET_EPHEMERAL);
+ assertThat(mUserManager.removeUserOrSetEphemeral(user1.id, /* evenWhenDisallowed= */ false))
+ .isEqualTo(UserManager.REMOVE_RESULT_SET_EPHEMERAL);
assertThat(hasUser(user1.id)).isTrue();
assertThat(getUser(user1.id).isEphemeral()).isTrue();
@@ -276,8 +299,8 @@
public void testRemoveUserOrSetEphemeral_nonCurrentUserRemoved() throws Exception {
final UserInfo user1 = createUser("User 1", /* flags= */ 0);
synchronized (mUserRemoveLock) {
- assertThat(mUserManager.removeUserOrSetEphemeral(user1.id)).isEqualTo(
- UserManager.REMOVE_RESULT_REMOVED);
+ assertThat(mUserManager.removeUserOrSetEphemeral(user1.id,
+ /* evenWhenDisallowed= */ false)).isEqualTo(UserManager.REMOVE_RESULT_REMOVED);
waitForUserRemovalLocked(user1.id);
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
index 0b44c59..b11bb85 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
@@ -366,36 +366,19 @@
actualPackages.add(p.packageName);
}
- // Add auto-generated RRO package to expectedPackages since they are not (supposed to be)
- // in the allowlist but they should be installed.
+ // Add static overlays to expectedPackages since they are not (supposed to be)
+ // in the allowlist but they should be installed if their target is.
for (PackageInfo p : packageInfos) {
- if (p.isOverlayPackage()
- && UserSystemPackageInstaller.hasAutoGeneratedRROSuffix(p.packageName)
- && expectedPackages.contains(p.overlayTarget)) {
+ if (p.isStaticOverlayPackage() && expectedPackages.contains(p.overlayTarget)) {
expectedPackages.add(p.packageName);
}
}
checkPackageDifferences(expectedPackages, actualPackages);
}
- @Test
- public void testAutoGeneratedRROMatchesSuffix() {
- final List<PackageInfo> packageInfos = mContext.getPackageManager()
- .getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES);
-
- Log.v(TAG, "Found total packages: " + packageInfos.size());
-
- for (PackageInfo p : packageInfos) {
- if (p.packageName.contains(".auto_generated_rro_")) {
- assertTrue("Auto-generated RRO package name does not match the suffix: "
- + p.packageName,
- UserSystemPackageInstaller.hasAutoGeneratedRROSuffix(p.packageName));
- }
- }
- }
-
/**
- * Test that overlay package not in allowlist should be installed for all user at Explicit mode.
+ * Test that static overlay package not in allowlist should be installed for all users
+ * based on their targets, in Explicit mode.
*/
@Test
public void testInstallOverlayPackagesExplicitMode() {
@@ -408,19 +391,32 @@
final String packageName2 = "nonWhitelistedPkg";
final String overlayName1 = String.format("%s.auto_generated_rro_product__", packageName1);
final String overlayName2 = String.format("%s.auto_generated_rro_product__", packageName2);
+ final String overlayName3 = String.format("%s.non_static_overlay", packageName1);
+ // Static overlay for allowlisted package1 -> should be installed, like package1
final AndroidPackage overlayPackage1 = ((ParsedPackage) PackageImpl.forTesting(overlayName1)
.setOverlay(true)
+ .setOverlayIsStatic(true)
.setOverlayTarget(packageName1)
.hideAsParsed())
.hideAsFinal();
+ // Static overlay for non-allowlisted package2 -> should not be installed, like package2
final AndroidPackage overlayPackage2 = ((ParsedPackage) PackageImpl.forTesting(overlayName2)
.setOverlay(true)
+ .setOverlayIsStatic(true)
.setOverlayTarget(packageName2)
.hideAsParsed())
.hideAsFinal();
+ // Non-static overlay for package1 -> not explicitly allowlisted, so shouldn't be installed
+ final AndroidPackage overlayPackage3 = ((ParsedPackage) PackageImpl.forTesting(overlayName3)
+ .setOverlay(true)
+ .setOverlayIsStatic(false) // non-static
+ .setOverlayTarget(packageName1)
+ .hideAsParsed())
+ .hideAsFinal();
+
final ArrayMap<String, Long> userTypeWhitelist = new ArrayMap<>();
userTypeWhitelist.put(packageName1, maskOfType);
@@ -428,10 +424,12 @@
userWhitelist.add(packageName1);
boolean implicit = false;
- assertTrue("Overlay for package1 should be installed", UserSystemPackageInstaller
+ assertTrue("Should install static overlay for package1", UserSystemPackageInstaller
.shouldInstallPackage(overlayPackage1, userTypeWhitelist, userWhitelist, implicit));
- assertFalse("Overlay for package2 should not be installed", UserSystemPackageInstaller
+ assertFalse("Should not install static overlay for package2", UserSystemPackageInstaller
.shouldInstallPackage(overlayPackage2, userTypeWhitelist, userWhitelist, implicit));
+ assertFalse("Should not install regular overlay for package1", UserSystemPackageInstaller
+ .shouldInstallPackage(overlayPackage3, userTypeWhitelist, userWhitelist, implicit));
}
/** Asserts that actual is a subset of expected. */
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 7f35511..f07197c 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -77,6 +77,7 @@
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.display.DisplayGroup;
import com.android.server.lights.LightsManager;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.power.PowerManagerService.BatteryReceiver;
@@ -97,9 +98,12 @@
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
/**
* Tests for {@link com.android.server.power.PowerManagerService}.
@@ -178,7 +182,8 @@
.thenReturn(mPowerSaveState);
when(mBatteryManagerInternalMock.isPowered(anyInt())).thenReturn(false);
when(mInattentiveSleepWarningControllerMock.isShown()).thenReturn(false);
- when(mDisplayManagerInternalMock.requestPowerState(any(), anyBoolean())).thenReturn(true);
+ when(mDisplayManagerInternalMock.requestPowerState(anyInt(), any(),
+ anyBoolean())).thenReturn(true);
when(mSystemPropertiesMock.get(eq(SYSTEM_PROPERTY_QUIESCENT), anyString())).thenReturn("");
when(mAmbientDisplayConfigurationMock.ambientDisplayAvailable()).thenReturn(true);
@@ -399,30 +404,33 @@
@Test
public void testGetDesiredScreenPolicy_WithVR() throws Exception {
createService();
+ mService.systemReady(null);
// Brighten up the screen
- mService.setWakefulnessLocked(WAKEFULNESS_AWAKE, PowerManager.WAKE_REASON_UNKNOWN, 0);
- assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
+ mService.setWakefulnessLocked(DisplayGroup.DEFAULT, WAKEFULNESS_AWAKE, 0, 0, 0, 0, null,
+ null);
+ assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
DisplayPowerRequest.POLICY_BRIGHT);
// Move to VR
mService.setVrModeEnabled(true);
- assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
+ assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
DisplayPowerRequest.POLICY_VR);
// Then take a nap
- mService.setWakefulnessLocked(WAKEFULNESS_ASLEEP, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT,
- 0);
- assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
+ mService.setWakefulnessLocked(DisplayGroup.DEFAULT, WAKEFULNESS_ASLEEP, 0, 0, 0, 0, null,
+ null);
+ assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
DisplayPowerRequest.POLICY_OFF);
// Wake up to VR
- mService.setWakefulnessLocked(WAKEFULNESS_AWAKE, PowerManager.WAKE_REASON_UNKNOWN, 0);
- assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
+ mService.setWakefulnessLocked(DisplayGroup.DEFAULT, WAKEFULNESS_AWAKE, 0, 0, 0, 0, null,
+ null);
+ assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
DisplayPowerRequest.POLICY_VR);
// And back to normal
mService.setVrModeEnabled(false);
- assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
+ assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
DisplayPowerRequest.POLICY_BRIGHT);
}
@@ -673,8 +681,9 @@
}
@Test
- public void testForceSuspend_forceSuspendFailurePropogated() {
+ public void testForceSuspend_forceSuspendFailurePropagated() throws Exception {
createService();
+ startSystem();
when(mNativeWrapperMock.nativeForceSuspend()).thenReturn(false);
assertThat(mService.getBinderServiceInstance().forceSuspend()).isFalse();
}
@@ -838,7 +847,7 @@
createService();
startSystem();
- assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
+ assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
DisplayPowerRequest.POLICY_BRIGHT);
}
@@ -857,11 +866,8 @@
public void testQuiescentBoot_DesiredScreenPolicyShouldBeOff() throws Exception {
when(mSystemPropertiesMock.get(eq(SYSTEM_PROPERTY_QUIESCENT), any())).thenReturn("1");
createService();
- assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
- DisplayPowerRequest.POLICY_OFF);
-
startSystem();
- assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
+ assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
DisplayPowerRequest.POLICY_OFF);
}
@@ -871,7 +877,7 @@
createService();
startSystem();
forceAwake();
- assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
+ assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
DisplayPowerRequest.POLICY_BRIGHT);
}
@@ -1143,4 +1149,85 @@
assertFalse(
mService.getBinderServiceInstance().setPowerModeChecked(Mode.INTERACTIVE, false));
}
+
+ @Test
+ public void testMultiDisplay_wakefulnessUpdates() throws Exception {
+ final int nonDefaultDisplayGroupId = DisplayGroup.DEFAULT + 1;
+ final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ listener.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+
+ createService();
+ startSystem();
+ listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ mService.setWakefulnessLocked(DisplayGroup.DEFAULT, WAKEFULNESS_ASLEEP, 0, 0, 0, 0, null,
+ null);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ mService.setWakefulnessLocked(nonDefaultDisplayGroupId, WAKEFULNESS_ASLEEP, 0, 0, 0, 0,
+ null, null);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+
+ mService.setWakefulnessLocked(DisplayGroup.DEFAULT, WAKEFULNESS_AWAKE, 0, 0, 0, 0, null,
+ null);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ }
+
+ @Test
+ public void testMultiDisplay_addDisplayGroup_preservesWakefulness() throws Exception {
+ final int nonDefaultDisplayGroupId = DisplayGroup.DEFAULT + 1;
+ final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ listener.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+
+ createService();
+ startSystem();
+
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ mService.setWakefulnessLocked(DisplayGroup.DEFAULT, WAKEFULNESS_ASLEEP, 0, 0, 0, 0, null,
+ null);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+
+ listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ }
+
+ @Test
+ public void testMultiDisplay_removeDisplayGroup_updatesWakefulness() throws Exception {
+ final int nonDefaultDisplayGroupId = DisplayGroup.DEFAULT + 1;
+ final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ listener.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+
+ createService();
+ startSystem();
+ listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ mService.setWakefulnessLocked(DisplayGroup.DEFAULT, WAKEFULNESS_ASLEEP, 0, 0, 0, 0, null,
+ null);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ listener.get().onDisplayGroupRemoved(nonDefaultDisplayGroupId);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+
+ mService.setWakefulnessLocked(DisplayGroup.DEFAULT, WAKEFULNESS_AWAKE, 0, 0, 0, 0, null,
+ null);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
index b07b8fa..9b8a2a8 100644
--- a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
@@ -35,6 +35,7 @@
import android.content.Context;
import android.content.IntentSender;
import android.content.pm.PackageManager;
+import android.hardware.boot.V1_2.IBootControl;
import android.os.Handler;
import android.os.IPowerManager;
import android.os.IRecoverySystemProgressListener;
@@ -68,12 +69,13 @@
private IThermalService mIThermalService;
private FileWriter mUncryptUpdateFileWriter;
private LockSettingsInternal mLockSettingsInternal;
+ private IBootControl mIBootControl;
private static final String FAKE_OTA_PACKAGE_NAME = "fake.ota.package";
private static final String FAKE_OTHER_PACKAGE_NAME = "fake.other.package";
@Before
- public void setup() {
+ public void setup() throws Exception {
mContext = mock(Context.class);
mSystemProperties = new RecoverySystemServiceTestable.FakeSystemProperties();
mUncryptSocket = mock(RecoverySystemService.UncryptSocket.class);
@@ -88,8 +90,13 @@
PowerManager powerManager = new PowerManager(mock(Context.class), mIPowerManager,
mIThermalService, new Handler(looper));
+ mIBootControl = mock(IBootControl.class);
+ when(mIBootControl.getCurrentSlot()).thenReturn(0);
+ when(mIBootControl.getActiveBootSlot()).thenReturn(1);
+
mRecoverySystemService = new RecoverySystemServiceTestable(mContext, mSystemProperties,
- powerManager, mUncryptUpdateFileWriter, mUncryptSocket, mLockSettingsInternal);
+ powerManager, mUncryptUpdateFileWriter, mUncryptSocket, mLockSettingsInternal,
+ mIBootControl);
}
@Test
@@ -332,6 +339,15 @@
verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean());
}
+
+ @Test
+ public void rebootWithLskf_slotMismatch_Failure() throws Exception {
+ assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, null), is(true));
+ mRecoverySystemService.onPreparedForReboot(true);
+ assertThat(mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, "ab-update", false),
+ is(false));
+ }
+
@Test
public void rebootWithLskf_withoutPrepare_Failure() throws Exception {
assertThat(mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, null, true),
diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java
index 131e4f3..0727e5a 100644
--- a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java
@@ -17,6 +17,7 @@
package com.android.server.recoverysystem;
import android.content.Context;
+import android.hardware.boot.V1_2.IBootControl;
import android.os.PowerManager;
import com.android.internal.widget.LockSettingsInternal;
@@ -30,16 +31,19 @@
private final FileWriter mUncryptPackageFileWriter;
private final UncryptSocket mUncryptSocket;
private final LockSettingsInternal mLockSettingsInternal;
+ private final IBootControl mIBootControl;
MockInjector(Context context, FakeSystemProperties systemProperties,
PowerManager powerManager, FileWriter uncryptPackageFileWriter,
- UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal) {
+ UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal,
+ IBootControl bootControl) {
super(context);
mSystemProperties = systemProperties;
mPowerManager = powerManager;
mUncryptPackageFileWriter = uncryptPackageFileWriter;
mUncryptSocket = uncryptSocket;
mLockSettingsInternal = lockSettingsInternal;
+ mIBootControl = bootControl;
}
@Override
@@ -85,13 +89,19 @@
public LockSettingsInternal getLockSettingsService() {
return mLockSettingsInternal;
}
+
+ @Override
+ public IBootControl getBootControl() {
+ return mIBootControl;
+ }
}
RecoverySystemServiceTestable(Context context, FakeSystemProperties systemProperties,
PowerManager powerManager, FileWriter uncryptPackageFileWriter,
- UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal) {
+ UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal,
+ IBootControl bootControl) {
super(new MockInjector(context, systemProperties, powerManager, uncryptPackageFileWriter,
- uncryptSocket, lockSettingsInternal));
+ uncryptSocket, lockSettingsInternal, bootControl));
}
public static class FakeSystemProperties {
@@ -102,6 +112,8 @@
|| RecoverySystemService.INIT_SERVICE_SETUP_BCB.equals(key)
|| RecoverySystemService.INIT_SERVICE_CLEAR_BCB.equals(key)) {
return null;
+ } else if (RecoverySystemService.AB_UPDATE.equals(key)) {
+ return "true";
} else {
throw new IllegalArgumentException("unexpected test key: " + key);
}
diff --git a/services/tests/servicestests/src/com/android/server/textservices/OWNERS b/services/tests/servicestests/src/com/android/server/textservices/OWNERS
new file mode 100644
index 0000000..0471e29
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/textservices/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 816455
+
+include /services/core/java/com/android/server/textservices/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/GnssTimeUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/GnssTimeUpdateServiceTest.java
new file mode 100644
index 0000000..8ac6dfb
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timedetector/GnssTimeUpdateServiceTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timedetector;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyLong;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.AlarmManager;
+import android.app.timedetector.GnssTimeSuggestion;
+import android.app.timedetector.TimeDetector;
+import android.content.Context;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.location.LocationManagerInternal;
+import android.location.LocationRequest;
+import android.location.LocationTime;
+import android.os.TimestampedValue;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.LocalServices;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public final class GnssTimeUpdateServiceTest {
+ private static final long GNSS_TIME = 999_999_999L;
+ private static final long ELAPSED_REALTIME_NS = 123_000_000L;
+ private static final long ELAPSED_REALTIME_MS = ELAPSED_REALTIME_NS / 1_000_000L;
+
+ @Mock private Context mMockContext;
+ @Mock private TimeDetector mMockTimeDetector;
+ @Mock private AlarmManager mMockAlarmManager;
+ @Mock private LocationManager mMockLocationManager;
+ @Mock private LocationManagerInternal mLocationManagerInternal;
+
+ private GnssTimeUpdateService mGnssTimeUpdateService;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ when(mMockContext.createAttributionContext(anyString()))
+ .thenReturn(mMockContext);
+
+ when(mMockContext.getSystemServiceName(TimeDetector.class))
+ .thenReturn((TimeDetector.class).getSimpleName());
+ when(mMockContext.getSystemService(TimeDetector.class))
+ .thenReturn(mMockTimeDetector);
+
+ when(mMockContext.getSystemServiceName(LocationManager.class))
+ .thenReturn((LocationManager.class).getSimpleName());
+ when(mMockContext.getSystemService(LocationManager.class))
+ .thenReturn(mMockLocationManager);
+
+ when(mMockContext.getSystemServiceName(AlarmManager.class))
+ .thenReturn((AlarmManager.class).getSimpleName());
+ when(mMockContext.getSystemService(AlarmManager.class))
+ .thenReturn(mMockAlarmManager);
+
+ LocalServices.addService(LocationManagerInternal.class, mLocationManagerInternal);
+
+ mGnssTimeUpdateService =
+ new GnssTimeUpdateService(mMockContext);
+ }
+
+ @After
+ public void tearDown() {
+ LocalServices.removeServiceForTest(LocationManagerInternal.class);
+ }
+
+ @Test
+ public void testLocationListenerOnLocationChanged_validLocationTime_suggestsGnssTime() {
+ TimestampedValue<Long> timeSignal = new TimestampedValue<>(
+ ELAPSED_REALTIME_MS, GNSS_TIME);
+ GnssTimeSuggestion timeSuggestion = new GnssTimeSuggestion(timeSignal);
+ LocationTime locationTime = new LocationTime(GNSS_TIME, ELAPSED_REALTIME_NS);
+ doReturn(locationTime).when(mLocationManagerInternal).getGnssTimeMillis();
+
+ mGnssTimeUpdateService.requestGnssTimeUpdates();
+
+ ArgumentCaptor<LocationListener> argumentCaptor =
+ ArgumentCaptor.forClass(LocationListener.class);
+ verify(mMockLocationManager).requestLocationUpdates(
+ eq(LocationManager.GPS_PROVIDER),
+ eq(new LocationRequest.Builder(LocationRequest.PASSIVE_INTERVAL)
+ .setMinUpdateIntervalMillis(0)
+ .build()),
+ any(),
+ argumentCaptor.capture());
+ LocationListener locationListener = argumentCaptor.getValue();
+ Location location = new Location(LocationManager.GPS_PROVIDER);
+
+ locationListener.onLocationChanged(location);
+
+ verify(mMockLocationManager).removeUpdates(locationListener);
+ verify(mMockTimeDetector).suggestGnssTime(timeSuggestion);
+ verify(mMockAlarmManager).set(
+ eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
+ anyLong(),
+ any(),
+ any(),
+ any());
+ }
+
+ @Test
+ public void testLocationListenerOnLocationChanged_nullLocationTime_doesNotSuggestGnssTime() {
+ doReturn(null).when(mLocationManagerInternal).getGnssTimeMillis();
+
+ mGnssTimeUpdateService.requestGnssTimeUpdates();
+
+ ArgumentCaptor<LocationListener> argumentCaptor =
+ ArgumentCaptor.forClass(LocationListener.class);
+ verify(mMockLocationManager).requestLocationUpdates(
+ eq(LocationManager.GPS_PROVIDER),
+ eq(new LocationRequest.Builder(LocationRequest.PASSIVE_INTERVAL)
+ .setMinUpdateIntervalMillis(0)
+ .build()),
+ any(),
+ argumentCaptor.capture());
+ LocationListener locationListener = argumentCaptor.getValue();
+ Location location = new Location(LocationManager.GPS_PROVIDER);
+
+ locationListener.onLocationChanged(location);
+
+ verify(mMockLocationManager).removeUpdates(locationListener);
+ verify(mMockTimeDetector, never()).suggestGnssTime(any());
+ verify(mMockAlarmManager).set(
+ eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
+ anyLong(),
+ any(),
+ any(),
+ any());
+ }
+}
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 bee7392..0fce4ba 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
@@ -213,6 +213,60 @@
}
@Test
+ public void vibrate_singleVibratorPredefinedCancel_cancelsVibrationImmediately()
+ throws Exception {
+ mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+
+ long vibrationId = 1;
+ VibrationEffect effect = VibrationEffect.startComposition()
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 100)
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 100)
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 100)
+ .compose();
+ VibrationThread vibrationThread = startThreadAndDispatcher(vibrationId, effect);
+
+ Thread.sleep(20);
+ assertTrue(vibrationThread.isAlive());
+ assertTrue(vibrationThread.getVibrators().get(VIBRATOR_ID).isVibrating());
+
+ // Run cancel in a separate thread so if VibrationThread.cancel blocks then this test should
+ // fail at waitForCompletion(vibrationThread) if the vibration not cancelled immediately.
+ Thread cancellingThread = new Thread(() -> vibrationThread.cancel());
+ cancellingThread.start();
+
+ waitForCompletion(vibrationThread, 20);
+ waitForCompletion(cancellingThread);
+
+ verify(mThreadCallbacks).onVibrationEnded(eq(vibrationId), eq(Vibration.Status.CANCELLED));
+ assertFalse(vibrationThread.getVibrators().get(VIBRATOR_ID).isVibrating());
+ }
+
+ @Test
+ public void vibrate_singleVibratorWaveformCancel_cancelsVibrationImmediately()
+ throws Exception {
+ mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+
+ long vibrationId = 1;
+ VibrationEffect effect = VibrationEffect.createWaveform(new long[]{100}, new int[]{100}, 0);
+ VibrationThread vibrationThread = startThreadAndDispatcher(vibrationId, effect);
+
+ Thread.sleep(20);
+ assertTrue(vibrationThread.isAlive());
+ assertTrue(vibrationThread.getVibrators().get(VIBRATOR_ID).isVibrating());
+
+ // Run cancel in a separate thread so if VibrationThread.cancel blocks then this test should
+ // fail at waitForCompletion(vibrationThread) if the vibration not cancelled immediately.
+ Thread cancellingThread = new Thread(() -> vibrationThread.cancel());
+ cancellingThread.start();
+
+ waitForCompletion(vibrationThread, 20);
+ waitForCompletion(cancellingThread);
+
+ verify(mThreadCallbacks).onVibrationEnded(eq(vibrationId), eq(Vibration.Status.CANCELLED));
+ assertFalse(vibrationThread.getVibrators().get(VIBRATOR_ID).isVibrating());
+ }
+
+ @Test
public void vibrate_singleVibratorPrebaked_runsVibration() throws Exception {
mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_THUD);
@@ -544,36 +598,70 @@
}
@Test
- public void vibrate_multipleCancelled_allVibratorsStopped() throws Exception {
- mockVibrators(1, 2, 3);
+ public void vibrate_multiplePredefinedCancel_cancelsVibrationImmediately() throws Exception {
+ mockVibrators(1, 2);
+ mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
+ mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+
+ long vibrationId = 1;
+ CombinedVibrationEffect effect = CombinedVibrationEffect.startSynced()
+ .addVibrator(1, VibrationEffect.get(VibrationEffect.EFFECT_CLICK))
+ .addVibrator(2, VibrationEffect.startComposition()
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 100)
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 100)
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 100)
+ .compose())
+ .combine();
+ VibrationThread vibrationThread = startThreadAndDispatcher(vibrationId, effect);
+
+ Thread.sleep(10);
+ assertTrue(vibrationThread.isAlive());
+ assertTrue(vibrationThread.getVibrators().get(1).isVibrating());
+ assertTrue(vibrationThread.getVibrators().get(2).isVibrating());
+
+ // Run cancel in a separate thread so if VibrationThread.cancel blocks then this test should
+ // fail at waitForCompletion(vibrationThread) if the vibration not cancelled immediately.
+ Thread cancellingThread = new Thread(() -> vibrationThread.cancel());
+ cancellingThread.start();
+
+ waitForCompletion(vibrationThread, 20);
+ waitForCompletion(cancellingThread);
+
+ verify(mThreadCallbacks).onVibrationEnded(eq(vibrationId), eq(Vibration.Status.CANCELLED));
+ assertFalse(vibrationThread.getVibrators().get(1).isVibrating());
+ assertFalse(vibrationThread.getVibrators().get(2).isVibrating());
+ }
+
+ @Test
+ public void vibrate_multipleWaveformCancel_cancelsVibrationImmediately() throws Exception {
+ mockVibrators(1, 2);
mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
- mVibratorProviders.get(3).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
long vibrationId = 1;
CombinedVibrationEffect effect = CombinedVibrationEffect.startSynced()
.addVibrator(1, VibrationEffect.createWaveform(
- new long[]{5, 10}, new int[]{1, 2}, 0))
- .addVibrator(2, VibrationEffect.createWaveform(
- new long[]{20, 30}, new int[]{3, 4}, 0))
- .addVibrator(3, VibrationEffect.createWaveform(
- new long[]{10, 40}, new int[]{5, 6}, 0))
+ new long[]{100, 100}, new int[]{1, 2}, 0))
+ .addVibrator(2, VibrationEffect.createOneShot(100, 100))
.combine();
- VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
+ VibrationThread vibrationThread = startThreadAndDispatcher(vibrationId, effect);
- Thread.sleep(15);
- assertTrue(thread.isAlive());
- assertTrue(thread.getVibrators().get(1).isVibrating());
- assertTrue(thread.getVibrators().get(2).isVibrating());
- assertTrue(thread.getVibrators().get(3).isVibrating());
+ Thread.sleep(10);
+ assertTrue(vibrationThread.isAlive());
+ assertTrue(vibrationThread.getVibrators().get(1).isVibrating());
+ assertTrue(vibrationThread.getVibrators().get(2).isVibrating());
- thread.cancel();
- waitForCompletion(thread);
- assertFalse(thread.getVibrators().get(1).isVibrating());
- assertFalse(thread.getVibrators().get(2).isVibrating());
- assertFalse(thread.getVibrators().get(3).isVibrating());
+ // Run cancel in a separate thread so if VibrationThread.cancel blocks then this test should
+ // fail at waitForCompletion(vibrationThread) if the vibration not cancelled immediately.
+ Thread cancellingThread = new Thread(() -> vibrationThread.cancel());
+ cancellingThread.start();
+
+ waitForCompletion(vibrationThread, 20);
+ waitForCompletion(cancellingThread);
verify(mThreadCallbacks).onVibrationEnded(eq(vibrationId), eq(Vibration.Status.CANCELLED));
+ assertFalse(vibrationThread.getVibrators().get(1).isVibrating());
+ assertFalse(vibrationThread.getVibrators().get(2).isVibrating());
}
@Test
@@ -621,11 +709,11 @@
return thread;
}
- private void waitForCompletion(VibrationThread thread) {
+ private void waitForCompletion(Thread thread) {
waitForCompletion(thread, TEST_TIMEOUT_MILLIS);
}
- private void waitForCompletion(VibrationThread thread, long timeout) {
+ private void waitForCompletion(Thread thread, long timeout) {
try {
thread.join(timeout);
} catch (InterruptedException e) {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 35876e4..e8888f4 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -112,9 +112,9 @@
import android.content.ComponentName;
import android.content.ContentUris;
import android.content.Context;
+import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.IIntentSender;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
@@ -1509,20 +1509,6 @@
}
@Test
- public void testCancelImmediatelyAfterEnqueueNotifiesListeners_ForegroundServiceFlag()
- throws Exception {
- final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
- sbn.getNotification().flags =
- Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE;
- mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
- sbn.getId(), sbn.getNotification(), sbn.getUserId());
- mBinderService.cancelNotificationWithTag(PKG, PKG, "tag", sbn.getId(), sbn.getUserId());
- waitForIdle();
- verify(mListeners, times(1)).notifyPostedLocked(any(), any());
- verify(mListeners, times(1)).notifyRemovedLocked(any(), anyInt(), any());
- }
-
- @Test
public void testUserInitiatedClearAll_noLeak() throws Exception {
final NotificationRecord n = generateNotificationRecord(
mTestNotificationChannel, 1, "group", true);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index ef96a2d..6ca9de3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -1251,8 +1251,7 @@
topActivity.setState(RESUMED, "true");
doCallRealMethod().when(mRootWindowContainer).ensureActivitiesVisible(
any() /* starting */, anyInt() /* configChanges */,
- anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */,
- anyBoolean() /* userLeaving */);
+ anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */);
topActivity.setShowWhenLocked(true);
// Verify the stack-top activity is occluded keyguard.
@@ -1299,7 +1298,7 @@
secondActivity.completeFinishing("test");
verify(secondActivity.mDisplayContent).ensureActivitiesVisible(null /* starting */,
0 /* configChanges */ , false /* preserveWindows */,
- true /* notifyClients */, false /* userLeaving */);
+ true /* notifyClients */);
// Finish the first activity
firstActivity.finishing = true;
@@ -1307,7 +1306,7 @@
firstActivity.completeFinishing("test");
verify(firstActivity.mDisplayContent, times(2)).ensureActivitiesVisible(null /* starting */,
0 /* configChanges */ , false /* preserveWindows */,
- true /* notifyClients */, false /* userLeaving */);
+ true /* notifyClients */);
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index fc96b69..22ee886 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -1151,7 +1151,7 @@
final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build();
topActivity.info.flags |= FLAG_RESUME_WHILE_PAUSING;
- task.startPausingLocked(false /* userLeaving */, false /* uiSleeping */, topActivity,
+ task.startPausingLocked(false /* uiSleeping */, topActivity,
"test");
verify(task).completePauseLocked(anyBoolean(), eq(topActivity));
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 11be74d..30c1008 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -89,6 +89,7 @@
import android.annotation.SuppressLint;
import android.app.ActivityTaskManager;
import android.app.WindowConfiguration;
+import android.app.servertransaction.FixedRotationAdjustmentsItem;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.Region;
@@ -1468,6 +1469,33 @@
}
@Test
+ public void testClearIntermediateFixedRotation() throws RemoteException {
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ mDisplayContent.setFixedRotationLaunchingApp(activity,
+ (mDisplayContent.getRotation() + 1) % 4);
+ // Create a window so FixedRotationAdjustmentsItem can be sent.
+ createWindow(null, TYPE_APPLICATION_STARTING, activity, "AppWin");
+ final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ activity2.setVisible(false);
+ clearInvocations(mAtm.getLifecycleManager());
+ // The first activity has applied fixed rotation but the second activity becomes the top
+ // before the transition is done and it has the same rotation as display, so the dispatched
+ // rotation adjustment of first activity must be cleared.
+ mDisplayContent.handleTopActivityLaunchingInDifferentOrientation(activity2,
+ false /* checkOpening */);
+
+ final ArgumentCaptor<FixedRotationAdjustmentsItem> adjustmentsCaptor =
+ ArgumentCaptor.forClass(FixedRotationAdjustmentsItem.class);
+ verify(mAtm.getLifecycleManager(), atLeastOnce()).scheduleTransaction(
+ eq(activity.app.getThread()), adjustmentsCaptor.capture());
+ assertFalse(activity.hasFixedRotationTransform());
+ final FixedRotationAdjustmentsItem clearAdjustments = FixedRotationAdjustmentsItem.obtain(
+ activity.token, null /* fixedRotationAdjustments */);
+ // The captor may match other items. The first one must be the item to clear adjustments.
+ assertEquals(clearAdjustments, adjustmentsCaptor.getAllValues().get(0));
+ }
+
+ @Test
public void testRemoteRotation() {
DisplayContent dc = createNewDisplay();
@@ -1613,12 +1641,11 @@
// The assertion will fail if DisplayArea#ensureActivitiesVisible is called twice.
assertFalse(called[0]);
called[0] = true;
- mDisplayContent.ensureActivitiesVisible(null, 0, false, false, false);
+ mDisplayContent.ensureActivitiesVisible(null, 0, false, false);
return null;
- }).when(mockTda).ensureActivitiesVisible(any(), anyInt(), anyBoolean(), anyBoolean(),
- anyBoolean());
+ }).when(mockTda).ensureActivitiesVisible(any(), anyInt(), anyBoolean(), anyBoolean());
- mDisplayContent.ensureActivitiesVisible(null, 0, false, false, false);
+ mDisplayContent.ensureActivitiesVisible(null, 0, false, false);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index 63ee5d0..d017c19 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -100,8 +100,7 @@
doCallRealMethod().when(mRootWindowContainer).ensureActivitiesVisible(
any() /* starting */, anyInt() /* configChanges */,
- anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */,
- anyBoolean() /* userLeaving */);
+ anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */);
RecentsAnimationCallbacks recentsAnimation = startRecentsActivity(
mRecentsComponent, true /* getRecentsAnimation */);
@@ -192,8 +191,7 @@
doCallRealMethod().when(mRootWindowContainer).ensureActivitiesVisible(
any() /* starting */, anyInt() /* configChanges */,
- anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */,
- anyBoolean() /* userLeaving */);
+ anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */);
doReturn(app).when(mAtm).getProcessController(eq(recentActivity.processName), anyInt());
ClientLifecycleManager lifecycleManager = mAtm.getLifecycleManager();
doNothing().when(lifecycleManager).scheduleTransaction(any());
@@ -349,8 +347,7 @@
doReturn(TEST_USER_ID).when(mAtm).getCurrentUserId();
doCallRealMethod().when(mRootWindowContainer).ensureActivitiesVisible(
any() /* starting */, anyInt() /* configChanges */,
- anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */,
- anyBoolean() /* userLeaving */);
+ anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */);
startRecentsActivity(otherUserHomeActivity.getTask().getBaseIntent().getComponent(),
true);
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index e1bc90a..afaf1b1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -297,7 +297,7 @@
doReturn(true).when(mWmService.mRoot).hasAwakeDisplay();
// Called when moving activity to pinned stack.
doNothing().when(mWmService.mRoot).ensureActivitiesVisible(any(),
- anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
+ anyInt(), anyBoolean(), anyBoolean());
spyOn(mWmService.mDisplayWindowSettings);
spyOn(mWmService.mDisplayWindowSettingsProvider);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
index 10d2da0..d83e9c2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
@@ -352,7 +352,8 @@
boolean reuseCandidate) {
final TaskDisplayArea taskDisplayArea = candidateTask.getDisplayArea();
final Task rootTask = taskDisplayArea.getOrCreateRootTask(windowingMode, activityType,
- false /* onTop */, null /* intent */, candidateTask /* candidateTask */);
+ false /* onTop */, null /* intent */, candidateTask /* candidateTask */,
+ null /* activityOptions */);
assertEquals(reuseCandidate, rootTask == candidateTask);
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
index 6046c9b2..d139141 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
@@ -198,6 +198,10 @@
@Override
public void onTaskRemoved(int taskId) throws RemoteException {
+ if (taskCreatedLaunchLatch.getCount() == 1) {
+ // The test activity hasn't started. Ignore the noise from previous test.
+ return;
+ }
params[0] = taskId;
taskRemovedLatch.countDown();
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index ccf2394..e4b865f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -28,6 +28,7 @@
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.PowerManager.GoToSleepReason;
import android.os.PowerManager.WakeReason;
import android.os.RemoteException;
import android.util.proto.ProtoOutputStream;
@@ -177,19 +178,19 @@
}
@Override
- public void startedWakingUp(@WakeReason int reason) {
+ public void startedWakingUp(@WakeReason int wakeReason) {
}
@Override
- public void finishedWakingUp(@WakeReason int reason) {
+ public void finishedWakingUp(@WakeReason int wakeReason) {
}
@Override
- public void startedGoingToSleep(int why) {
+ public void startedGoingToSleep(@GoToSleepReason int sleepReason) {
}
@Override
- public void finishedGoingToSleep(int why) {
+ public void finishedGoingToSleep(@GoToSleepReason int sleepReason) {
}
@Override
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 8041fa9..4d6536c 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2812,6 +2812,30 @@
public static final String IMSI_KEY_DOWNLOAD_URL_STRING = "imsi_key_download_url_string";
/**
+ * String representation of a carrier's public key used for IMSI encryption for ePDG. If this
+ * is provided, the device will use it as a fallback when no key exists on device, but the key
+ * download will still initiate.
+ * Example string:
+ * "-----BEGIN CERTIFICATE-----\nabcde12345abcde12345abcde12345abcde1234
+ * 5abcde12345abcde12345\nabcde12345abcde12345abcde12345abcde12345a\n-----END CERTIFICATE-----"
+ * @hide
+ */
+ public static final String IMSI_CARRIER_PUBLIC_KEY_EPDG_STRING =
+ "imsi_carrier_public_key_epdg_string";
+
+ /**
+ * String representation of a carrier's public key used for IMSI encryption for WLAN. If this
+ * is provided, the device will use it as a fallback when no key exists on device, but the key
+ * download will still initiate.
+ * Example string:
+ * "-----BEGIN CERTIFICATE-----\nabcde12345abcde12345abcde12345abcde1234
+ * 5abcde12345abcde12345\nabcde12345abcde12345abcde12345abcde12345a\n-----END CERTIFICATE-----"
+ * @hide
+ */
+ public static final String IMSI_CARRIER_PUBLIC_KEY_WLAN_STRING =
+ "imsi_carrier_public_key_wlan_string";
+
+ /**
* Identifies if the key is available for WLAN or EPDG or both. The value is a bitmask.
* 0 indicates that neither EPDG or WLAN is enabled.
* 1 indicates that key type TelephonyManager#KEY_TYPE_EPDG is enabled.
@@ -5015,6 +5039,8 @@
sDefaults.putBoolean(KEY_DISABLE_VOICE_BARRING_NOTIFICATION_BOOL, false);
sDefaults.putInt(IMSI_KEY_AVAILABILITY_INT, 0);
sDefaults.putString(IMSI_KEY_DOWNLOAD_URL_STRING, null);
+ sDefaults.putString(IMSI_CARRIER_PUBLIC_KEY_EPDG_STRING, null);
+ sDefaults.putString(IMSI_CARRIER_PUBLIC_KEY_WLAN_STRING, null);
sDefaults.putBoolean(KEY_CONVERT_CDMA_CALLER_ID_MMI_CODES_WHILE_ROAMING_ON_3GPP_BOOL,
false);
sDefaults.putStringArray(KEY_NON_ROAMING_OPERATOR_STRING_ARRAY, null);
@@ -5212,7 +5238,7 @@
sDefaults.putString(KEY_CALL_COMPOSER_PICTURE_SERVER_URL_STRING, "");
sDefaults.putBoolean(KEY_USE_LOWER_MTU_VALUE_IF_BOTH_RECEIVED, false);
sDefaults.putBoolean(KEY_USE_ACS_FOR_RCS_BOOL, false);
- sDefaults.putBoolean(KEY_NETWORK_TEMP_NOT_METERED_SUPPORTED_BOOL, false);
+ sDefaults.putBoolean(KEY_NETWORK_TEMP_NOT_METERED_SUPPORTED_BOOL, true);
sDefaults.putInt(KEY_DEFAULT_RTT_MODE_INT, 0);
}
diff --git a/telephony/java/android/telephony/ImsiEncryptionInfo.java b/telephony/java/android/telephony/ImsiEncryptionInfo.java
index 75a79d6..4978692 100644
--- a/telephony/java/android/telephony/ImsiEncryptionInfo.java
+++ b/telephony/java/android/telephony/ImsiEncryptionInfo.java
@@ -163,8 +163,8 @@
public String toString(){
return "[ImsiEncryptionInfo "
+ "mcc=" + mcc
- + "mnc=" + mnc
- + "publicKey=" + publicKey
+ + " mnc=" + mnc
+ + " publicKey=" + publicKey
+ ", keyIdentifier=" + keyIdentifier
+ ", keyType=" + keyType
+ ", expirationTime=" + expirationTime
diff --git a/telephony/java/android/telephony/PreciseDisconnectCause.java b/telephony/java/android/telephony/PreciseDisconnectCause.java
index 250d9e8..3b4cf75 100644
--- a/telephony/java/android/telephony/PreciseDisconnectCause.java
+++ b/telephony/java/android/telephony/PreciseDisconnectCause.java
@@ -121,7 +121,7 @@
public static final int BEARER_CAPABILITY_NOT_AUTHORIZED = 57;
/** The requested bearer capability is not available at this time. */
public static final int BEARER_NOT_AVAIL = 58;
- /** The service option is not availble at this time. */
+ /** The service option is not available at this time. */
public static final int SERVICE_OPTION_NOT_AVAILABLE = 63;
/** The equipment sending this cause does not support the bearer capability requested. */
public static final int BEARER_SERVICE_NOT_IMPLEMENTED = 65;
diff --git a/telephony/java/android/telephony/SignalStrengthUpdateRequest.aidl b/telephony/java/android/telephony/SignalStrengthUpdateRequest.aidl
new file mode 100644
index 0000000..a45de2e
--- /dev/null
+++ b/telephony/java/android/telephony/SignalStrengthUpdateRequest.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright (C) 2020 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony;
+
+parcelable SignalStrengthUpdateRequest;
diff --git a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
index 2a16402..af67ed2 100644
--- a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
+++ b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
@@ -17,6 +17,8 @@
package android.telephony;
import android.annotation.NonNull;
+import android.os.Binder;
+import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
@@ -56,6 +58,11 @@
*/
private final boolean mIsSystemThresholdReportingRequestedWhileIdle;
+ /**
+ * A IBinder object as a token for server side to check if the request client is still living.
+ */
+ private final IBinder mLiveToken;
+
private SignalStrengthUpdateRequest(
@NonNull List<SignalThresholdInfo> signalThresholdInfos,
boolean isReportingRequestedWhileIdle,
@@ -66,6 +73,7 @@
mIsReportingRequestedWhileIdle = isReportingRequestedWhileIdle;
mIsSystemThresholdReportingRequestedWhileIdle =
isSystemThresholdReportingRequestedWhileIdle;
+ mLiveToken = new Binder();
}
/**
@@ -148,6 +156,7 @@
mSignalThresholdInfos = in.createTypedArrayList(SignalThresholdInfo.CREATOR);
mIsReportingRequestedWhileIdle = in.readBoolean();
mIsSystemThresholdReportingRequestedWhileIdle = in.readBoolean();
+ mLiveToken = in.readStrongBinder();
}
/**
@@ -178,6 +187,15 @@
return mIsSystemThresholdReportingRequestedWhileIdle;
}
+ /*
+ * @return the live token of the request
+ *
+ * @hide
+ */
+ public @NonNull IBinder getLiveToken() {
+ return mLiveToken;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -188,6 +206,7 @@
dest.writeTypedList(mSignalThresholdInfos);
dest.writeBoolean(mIsReportingRequestedWhileIdle);
dest.writeBoolean(mIsSystemThresholdReportingRequestedWhileIdle);
+ dest.writeStrongBinder(mLiveToken);
}
@Override
@@ -199,10 +218,10 @@
}
SignalStrengthUpdateRequest request = (SignalStrengthUpdateRequest) other;
- return request.mSignalThresholdInfos.equals(mSignalThresholdInfos)
- && request.mIsReportingRequestedWhileIdle == mIsReportingRequestedWhileIdle
- && request.mIsSystemThresholdReportingRequestedWhileIdle
- == mIsSystemThresholdReportingRequestedWhileIdle;
+ return mSignalThresholdInfos.equals(request.mSignalThresholdInfos)
+ && mIsReportingRequestedWhileIdle == request.mIsReportingRequestedWhileIdle
+ && mIsSystemThresholdReportingRequestedWhileIdle
+ == request.mIsSystemThresholdReportingRequestedWhileIdle;
}
@Override
@@ -233,6 +252,8 @@
.append(mIsReportingRequestedWhileIdle)
.append(" mIsSystemThresholdReportingRequestedWhileIdle=")
.append(mIsSystemThresholdReportingRequestedWhileIdle)
+ .append(" mLiveToken")
+ .append(mLiveToken)
.append("}").toString();
}
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index e06dcdb..6c013df 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -384,7 +384,6 @@
* where this operation may fail.
* </p>
*
- *
* @param destinationAddress the address to send the message to
* @param scAddress is the service center address or null to use
* the current default SMSC
@@ -397,7 +396,6 @@
* <code>RESULT_ERROR_RADIO_OFF</code><br>
* <code>RESULT_ERROR_NULL_PDU</code><br>
* <code>RESULT_ERROR_NO_SERVICE</code><br>
- * <code>RESULT_ERROR_NO_SERVICE</code><br>
* <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br>
* <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br>
* <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br>
@@ -514,7 +512,6 @@
* <code>RESULT_ERROR_RADIO_OFF</code><br>
* <code>RESULT_ERROR_NULL_PDU</code><br>
* <code>RESULT_ERROR_NO_SERVICE</code><br>
- * <code>RESULT_ERROR_NO_SERVICE</code><br>
* <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br>
* <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br>
* <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br>
@@ -903,22 +900,20 @@
* where this operation may fail.
* </p>
*
- *
* @param destinationAddress the address to send the message to
* @param scAddress is the service center address or null to use
- * the current default SMSC
+ * the current default SMSC
* @param parts an <code>ArrayList</code> of strings that, in order,
- * comprise the original message
+ * comprise the original message
* @param sentIntents if not null, an <code>ArrayList</code> of
- * <code>PendingIntent</code>s (one for each message part) that is
- * broadcast when the corresponding message part has been sent.
- * The result code will be <code>Activity.RESULT_OK</code> for success,
- * or one of these errors:<br>
+ * <code>PendingIntent</code>s (one for each message part) that is
+ * broadcast when the corresponding message part has been sent.
+ * The result code will be <code>Activity.RESULT_OK</code> for success,
+ * or one of these errors:<br>
* <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
* <code>RESULT_ERROR_RADIO_OFF</code><br>
* <code>RESULT_ERROR_NULL_PDU</code><br>
* <code>RESULT_ERROR_NO_SERVICE</code><br>
- * <code>RESULT_ERROR_NO_SERVICE</code><br>
* <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br>
* <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br>
* <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br>
@@ -974,14 +969,14 @@
* For <code>RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors,
* the sentIntent may include the extra "errorCode" containing a radio technology specific
* value, generally only useful for troubleshooting.<br>
- * The per-application based SMS control checks sentIntent. If sentIntent
- * is NULL the caller will be checked against all unknown applications,
- * which cause smaller number of SMS to be sent in checking period.
+ * The per-application based SMS control checks sentIntent. If sentIntent
+ * is NULL the caller will be checked against all unknown applications,
+ * which cause smaller number of SMS to be sent in checking period.
* @param deliveryIntents if not null, an <code>ArrayList</code> of
- * <code>PendingIntent</code>s (one for each message part) that is
- * broadcast when the corresponding message part has been delivered
- * to the recipient. The raw pdu of the status report is in the
- * extended data ("pdu").
+ * <code>PendingIntent</code>s (one for each message part) that is
+ * broadcast when the corresponding message part has been delivered
+ * to the recipient. The raw pdu of the status report is in the
+ * extended data ("pdu").
*
* @throws IllegalArgumentException if destinationAddress or data are empty
*/
@@ -1163,22 +1158,21 @@
* boolean value {@code true}. See {@link #getDefault()} for more information on the conditions
* where this operation may fail.
* </p>
-
+ *
* @param destinationAddress the address to send the message to
* @param scAddress is the service center address or null to use
- * the current default SMSC
+ * the current default SMSC
* @param parts an <code>ArrayList</code> of strings that, in order,
- * comprise the original message
+ * comprise the original message
* @param sentIntents if not null, an <code>ArrayList</code> of
- * <code>PendingIntent</code>s (one for each message part) that is
- * broadcast when the corresponding message part has been sent.
- * The result code will be <code>Activity.RESULT_OK</code> for success,
- * or one of these errors:<br>
+ * <code>PendingIntent</code>s (one for each message part) that is
+ * broadcast when the corresponding message part has been sent.
+ * The result code will be <code>Activity.RESULT_OK</code> for success,
+ * or one of these errors:<br>
* <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
* <code>RESULT_ERROR_RADIO_OFF</code><br>
* <code>RESULT_ERROR_NULL_PDU</code><br>
* <code>RESULT_ERROR_NO_SERVICE</code><br>
- * <code>RESULT_ERROR_NO_SERVICE</code><br>
* <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br>
* <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br>
* <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br>
@@ -1234,14 +1228,14 @@
* For <code>RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors,
* the sentIntent may include the extra "errorCode" containing a radio technology specific
* value, generally only useful for troubleshooting.<br>
- * The per-application based SMS control checks sentIntent. If sentIntent
- * is NULL the caller will be checked against all unknown applications,
- * which cause smaller number of SMS to be sent in checking period.
+ * The per-application based SMS control checks sentIntent. If sentIntent
+ * is NULL the caller will be checked against all unknown applications,
+ * which cause smaller number of SMS to be sent in checking period.
* @param deliveryIntents if not null, an <code>ArrayList</code> of
- * <code>PendingIntent</code>s (one for each message part) that is
- * broadcast when the corresponding message part has been delivered
- * to the recipient. The raw pdu of the status report is in the
- * extended data ("pdu").
+ * <code>PendingIntent</code>s (one for each message part) that is
+ * broadcast when the corresponding message part has been delivered
+ * to the recipient. The raw pdu of the status report is in the
+ * extended data ("pdu").
* @param priority Priority level of the message
* Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
* ---------------------------------
@@ -1380,7 +1374,6 @@
* <code>RESULT_ERROR_RADIO_OFF</code><br>
* <code>RESULT_ERROR_NULL_PDU</code><br>
* <code>RESULT_ERROR_NO_SERVICE</code><br>
- * <code>RESULT_ERROR_NO_SERVICE</code><br>
* <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br>
* <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br>
* <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br>
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index d4c2bc9..af82991 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -2609,14 +2609,45 @@
* requested state until explicitly cleared, or the next reboot,
* whichever happens first.
* @throws SecurityException if the caller doesn't meet the requirements
- * outlined above.
+ * outlined above.
*/
public void setSubscriptionOverrideUnmetered(int subId, boolean overrideUnmetered,
@DurationMillisLong long timeoutMillis) {
+ setSubscriptionOverrideUnmetered(subId, overrideUnmetered,
+ TelephonyManager.getAllNetworkTypes(), timeoutMillis);
+ }
+ /**
+ * Temporarily override the billing relationship plan between a carrier and
+ * a specific subscriber to be considered unmetered. This will be reflected
+ * to apps via {@link NetworkCapabilities#NET_CAPABILITY_NOT_METERED}.
+ * <p>
+ * This method is only accessible to the following narrow set of apps:
+ * <ul>
+ * <li>The carrier app for this subscriberId, as determined by
+ * {@link TelephonyManager#hasCarrierPrivileges()}.
+ * <li>The carrier app explicitly delegated access through
+ * {@link CarrierConfigManager#KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING}.
+ * </ul>
+ *
+ * @param subId the subscriber this override applies to.
+ * @param overrideUnmetered set if the billing relationship should be
+ * considered unmetered.
+ * @param networkTypes the network types this override applies to.
+ * {@see TelephonyManager#getAllNetworkTypes()}
+ * @param timeoutMillis the timeout after which the requested override will
+ * be automatically cleared, or {@code 0} to leave in the
+ * requested state until explicitly cleared, or the next reboot,
+ * whichever happens first.
+ * @throws SecurityException if the caller doesn't meet the requirements
+ * outlined above.
+ */
+ public void setSubscriptionOverrideUnmetered(int subId, boolean overrideUnmetered,
+ @NonNull @Annotation.NetworkType int[] networkTypes,
+ @DurationMillisLong long timeoutMillis) {
final int overrideValue = overrideUnmetered ? SUBSCRIPTION_OVERRIDE_UNMETERED : 0;
getNetworkPolicyManager().setSubscriptionOverride(subId, SUBSCRIPTION_OVERRIDE_UNMETERED,
- overrideValue, timeoutMillis, mContext.getOpPackageName());
+ overrideValue, networkTypes, timeoutMillis, mContext.getOpPackageName());
}
/**
@@ -2641,13 +2672,46 @@
* requested state until explicitly cleared, or the next reboot,
* whichever happens first.
* @throws SecurityException if the caller doesn't meet the requirements
- * outlined above.
+ * outlined above.
*/
public void setSubscriptionOverrideCongested(int subId, boolean overrideCongested,
@DurationMillisLong long timeoutMillis) {
+ setSubscriptionOverrideCongested(subId, overrideCongested,
+ TelephonyManager.getAllNetworkTypes(), timeoutMillis);
+ }
+
+ /**
+ * Temporarily override the billing relationship plan between a carrier and
+ * a specific subscriber to be considered congested. This will cause the
+ * device to delay certain network requests when possible, such as developer
+ * jobs that are willing to run in a flexible time window.
+ * <p>
+ * This method is only accessible to the following narrow set of apps:
+ * <ul>
+ * <li>The carrier app for this subscriberId, as determined by
+ * {@link TelephonyManager#hasCarrierPrivileges()}.
+ * <li>The carrier app explicitly delegated access through
+ * {@link CarrierConfigManager#KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING}.
+ * </ul>
+ *
+ * @param subId the subscriber this override applies to.
+ * @param overrideCongested set if the subscription should be considered
+ * congested.
+ * @param networkTypes the network types this override applies to.
+ * {@see TelephonyManager#getAllNetworkTypes()}
+ * @param timeoutMillis the timeout after which the requested override will
+ * be automatically cleared, or {@code 0} to leave in the
+ * requested state until explicitly cleared, or the next reboot,
+ * whichever happens first.
+ * @throws SecurityException if the caller doesn't meet the requirements
+ * outlined above.
+ */
+ public void setSubscriptionOverrideCongested(int subId, boolean overrideCongested,
+ @NonNull @Annotation.NetworkType int[] networkTypes,
+ @DurationMillisLong long timeoutMillis) {
final int overrideValue = overrideCongested ? SUBSCRIPTION_OVERRIDE_CONGESTED : 0;
getNetworkPolicyManager().setSubscriptionOverride(subId, SUBSCRIPTION_OVERRIDE_CONGESTED,
- overrideValue, timeoutMillis, mContext.getOpPackageName());
+ overrideValue, networkTypes, timeoutMillis, mContext.getOpPackageName());
}
/**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 2f577a9..216413b 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -7805,18 +7805,23 @@
}
/**
- * Set IMS registration state
+ * Set IMS registration state on all active subscriptions.
+ * <p/>
+ * Use {@link android.telephony.ims.stub.ImsRegistrationImplBase#onRegistered} and
+ * {@link android.telephony.ims.stub.ImsRegistrationImplBase#onDeregistered} to set Ims
+ * registration state instead.
*
- * @param Registration state
+ * @param registered whether ims is registered
+ *
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public void setImsRegistrationState(boolean registered) {
+ public void setImsRegistrationState(final boolean registered) {
try {
- ITelephony telephony = getITelephony();
+ final ITelephony telephony = getITelephony();
if (telephony != null)
telephony.setImsRegistrationState(registered);
- } catch (RemoteException e) {
+ } catch (final RemoteException e) {
}
}
@@ -9806,9 +9811,16 @@
* @return true if mobile data is enabled.
*/
@RequiresPermission(anyOf = {android.Manifest.permission.ACCESS_NETWORK_STATE,
- android.Manifest.permission.MODIFY_PHONE_STATE})
+ android.Manifest.permission.MODIFY_PHONE_STATE,
+ android.Manifest.permission.READ_PHONE_STATE})
public boolean isDataEnabled() {
- return getDataEnabled(getSubId(SubscriptionManager.getDefaultDataSubscriptionId()));
+ try {
+ return isDataEnabledForReason(DATA_ENABLED_REASON_USER);
+ } catch (IllegalStateException ise) {
+ // TODO(b/176163590): Remove this catch once TelephonyManager is booting safely.
+ Log.e(TAG, "Error calling #isDataEnabled, returning default (false).", ise);
+ return false;
+ }
}
/**
@@ -10053,7 +10065,7 @@
@SystemApi
public boolean getDataEnabled(int subId) {
try {
- return isDataEnabledForReason(DATA_ENABLED_REASON_USER);
+ return isDataEnabledForReason(subId, DATA_ENABLED_REASON_USER);
} catch (RuntimeException e) {
Log.e(TAG, "Error calling isDataEnabledForReason e:" + e);
}
@@ -15200,4 +15212,85 @@
return networkType >= TelephonyManager.NETWORK_TYPE_UNKNOWN &&
networkType <= TelephonyManager.NETWORK_TYPE_NR;
}
+
+ /**
+ * Set a {@link SignalStrengthUpdateRequest} to receive notification when signal quality
+ * measurements breach the specified thresholds.
+ *
+ * To be notified, set the signal strength update request and then register
+ * {@link TelephonyManager#listen(PhoneStateListener, int)} with
+ * {@link PhoneStateListener#LISTEN_SIGNAL_STRENGTHS}. The notification will arrive through
+ * {@link PhoneStateListener#onSignalStrengthsChanged(SignalStrength)}.
+ *
+ * To stop receiving the notification over the specified thresholds, pass the same
+ * {@link SignalStrengthUpdateRequest} object to
+ * {@link #clearSignalStrengthUpdateRequest(SignalStrengthUpdateRequest)}.
+ *
+ * System will clean up the {@link SignalStrengthUpdateRequest} if the caller process died
+ * without calling {@link #clearSignalStrengthUpdateRequest(SignalStrengthUpdateRequest)}.
+ *
+ * If this TelephonyManager object has been created with {@link #createForSubscriptionId},
+ * applies to the given subId. Otherwise, applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}. To request for multiple subIds,
+ * pass a request object to each TelephonyManager object created with
+ * {@link #createForSubscriptionId}.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+ * or that the calling app has carrier privileges (see
+ * {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * Note that the thresholds in the request will be used on a best-effort basis; the system may
+ * modify requests to multiplex various request sources or to optimize power consumption. The
+ * caller should not expect to be notified with the exactly the same thresholds.
+ *
+ * @see #clearSignalStrengthUpdateRequest(SignalStrengthUpdateRequest)
+ *
+ * @param request the SignalStrengthUpdateRequest to be set into the System
+ *
+ * @throws IllegalStateException if a new request is set with same subId from the same caller
+ */
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void setSignalStrengthUpdateRequest(@NonNull SignalStrengthUpdateRequest request) {
+ Objects.requireNonNull(request, "request must not be null");
+
+ try {
+ ITelephony service = getITelephony();
+ if (service != null) {
+ service.setSignalStrengthUpdateRequest(getSubId(), request, getOpPackageName());
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelephony#setSignalStrengthUpdateRequest", e);
+ }
+ }
+
+ /**
+ * Clear a {@link SignalStrengthUpdateRequest} from the system.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+ * or that the calling app has carrier privileges (see
+ * {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * <p>If the given request was not set before, this operation is a no-op.
+ *
+ * @see #setSignalStrengthUpdateRequest(SignalStrengthUpdateRequest)
+ *
+ * @param request the SignalStrengthUpdateRequest to be cleared from the System
+ */
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void clearSignalStrengthUpdateRequest(@NonNull SignalStrengthUpdateRequest request) {
+ Objects.requireNonNull(request, "request must not be null");
+
+ try {
+ ITelephony service = getITelephony();
+ if (service != null) {
+ service.clearSignalStrengthUpdateRequest(getSubId(), request, getOpPackageName());
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelephony#clearSignalStrengthUpdateRequest", e);
+ }
+ }
}
diff --git a/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.aidl b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.aidl
new file mode 100644
index 0000000..da31f98
--- /dev/null
+++ b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ package android.telephony.data;
+
+ parcelable EpsBearerQosSessionAttributes;
\ No newline at end of file
diff --git a/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java
new file mode 100644
index 0000000..041edc0
--- /dev/null
+++ b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.data;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.net.QosSessionAttributes;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Provides Qos attributes of an EPS bearer.
+ *
+ * {@hide}
+ */
+@SystemApi
+public final class EpsBearerQosSessionAttributes implements Parcelable, QosSessionAttributes {
+ private static final String TAG = EpsBearerQosSessionAttributes.class.getSimpleName();
+ private final int mQci;
+ private final long mMaxUplinkBitRate;
+ private final long mMaxDownlinkBitRate;
+ private final long mGuaranteedUplinkBitRate;
+ private final long mGuaranteedDownlinkBitRate;
+ @NonNull private final List<InetSocketAddress> mRemoteAddresses;
+
+ /**
+ * Quality of Service Class Identifier (QCI), see 3GPP TS 23.203 and 29.212.
+ * The allowed values are standard values(1-9, 65-68, 69-70, 75, 79-80, 82-85)
+ * defined in the spec and operator specific values in the range 128-254.
+ *
+ * @return the qci of the session
+ */
+ public int getQci() {
+ return mQci;
+ }
+
+ /**
+ * Minimum bit rate in kbps that is guaranteed to be provided by the network on the uplink.
+ *
+ * see 3GPP TS 23.107 section 6.4.3.1
+ *
+ * Note: The Qos Session may be shared with OTHER applications besides yours.
+ *
+ * @return the guaranteed bit rate in kbps
+ */
+ public long getGuaranteedUplinkBitRate() {
+ return mGuaranteedUplinkBitRate;
+ }
+
+ /**
+ * Minimum bit rate in kbps that is guaranteed to be provided by the network on the downlink.
+ *
+ * see 3GPP TS 23.107 section 6.4.3.1
+ *
+ * Note: The Qos Session may be shared with OTHER applications besides yours.
+ *
+ * @return the guaranteed bit rate in kbps
+ */
+ public long getGuaranteedDownlinkBitRate() {
+ return mGuaranteedDownlinkBitRate;
+ }
+
+ /**
+ * The maximum kbps that the network will accept.
+ *
+ * see 3GPP TS 23.107 section 6.4.3.1
+ *
+ * Note: The Qos Session may be shared with OTHER applications besides yours.
+ *
+ * @return the max uplink bit rate in kbps
+ */
+ public long getMaxUplinkBitRate() {
+ return mMaxUplinkBitRate;
+ }
+
+ /**
+ * The maximum kbps that the network can provide.
+ *
+ * see 3GPP TS 23.107 section 6.4.3.1
+ *
+ * Note: The Qos Session may be shared with OTHER applications besides yours.
+ *
+ * @return the max downlink bit rate in kbps
+ */
+ public long getMaxDownlinkBitRate() {
+ return mMaxDownlinkBitRate;
+ }
+
+ /**
+ * List of remote addresses associated with the Qos Session. The given uplink bit rates apply
+ * to this given list of remote addresses.
+ *
+ * Note: In the event that the list is empty, it is assumed that the uplink bit rates apply to
+ * all remote addresses that are not contained in a different set of attributes.
+ *
+ * @return list of remote socket addresses that the attributes apply to
+ */
+ @NonNull
+ public List<InetSocketAddress> getRemoteAddresses() {
+ return mRemoteAddresses;
+ }
+
+ /**
+ * ..ctor for attributes
+ *
+ * @param qci quality class indicator
+ * @param maxDownlinkBitRate the max downlink bit rate in kbps
+ * @param maxUplinkBitRate the max uplink bit rate in kbps
+ * @param guaranteedDownlinkBitRate the guaranteed downlink bit rate in kbps
+ * @param guaranteedUplinkBitRate the guaranteed uplink bit rate in kbps
+ * @param remoteAddresses the remote addresses that the uplink bit rates apply to
+ *
+ * @hide
+ */
+ public EpsBearerQosSessionAttributes(final int qci,
+ final long maxDownlinkBitRate, final long maxUplinkBitRate,
+ final long guaranteedDownlinkBitRate, final long guaranteedUplinkBitRate,
+ @NonNull final List<InetSocketAddress> remoteAddresses) {
+ Objects.requireNonNull(remoteAddresses, "remoteAddress must be non-null");
+ mQci = qci;
+ mMaxDownlinkBitRate = maxDownlinkBitRate;
+ mMaxUplinkBitRate = maxUplinkBitRate;
+ mGuaranteedDownlinkBitRate = guaranteedDownlinkBitRate;
+ mGuaranteedUplinkBitRate = guaranteedUplinkBitRate;
+
+ final List<InetSocketAddress> remoteAddressesTemp = copySocketAddresses(remoteAddresses);
+ mRemoteAddresses = Collections.unmodifiableList(remoteAddressesTemp);
+ }
+
+ private static List<InetSocketAddress> copySocketAddresses(
+ @NonNull final List<InetSocketAddress> remoteAddresses) {
+ final List<InetSocketAddress> remoteAddressesTemp = new ArrayList<>();
+ for (final InetSocketAddress socketAddress : remoteAddresses) {
+ if (socketAddress != null && socketAddress.getAddress() != null) {
+ remoteAddressesTemp.add(socketAddress);
+ }
+ }
+ return remoteAddressesTemp;
+ }
+
+ private EpsBearerQosSessionAttributes(@NonNull final Parcel in) {
+ mQci = in.readInt();
+ mMaxDownlinkBitRate = in.readLong();
+ mMaxUplinkBitRate = in.readLong();
+ mGuaranteedDownlinkBitRate = in.readLong();
+ mGuaranteedUplinkBitRate = in.readLong();
+
+ final int size = in.readInt();
+ final List<InetSocketAddress> remoteAddresses = new ArrayList<>(size);
+ for (int i = 0; i < size; i++) {
+ final byte[] addressBytes = in.createByteArray();
+ final int port = in.readInt();
+ try {
+ remoteAddresses.add(
+ new InetSocketAddress(InetAddress.getByAddress(addressBytes), port));
+ } catch (final UnknownHostException e) {
+ // Impossible case since we filter out null values in the ..ctor
+ Log.e(TAG, "unable to unparcel remote address at index: " + i, e);
+ }
+ }
+ mRemoteAddresses = Collections.unmodifiableList(remoteAddresses);
+ }
+
+ /**
+ * Creates attributes based off of a parcel
+ * @param in the parcel
+ * @return the attributes
+ */
+ @NonNull
+ public static EpsBearerQosSessionAttributes create(@NonNull final Parcel in) {
+ return new EpsBearerQosSessionAttributes(in);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull final Parcel dest, final int flags) {
+ dest.writeInt(mQci);
+ dest.writeLong(mMaxDownlinkBitRate);
+ dest.writeLong(mMaxUplinkBitRate);
+ dest.writeLong(mGuaranteedDownlinkBitRate);
+ dest.writeLong(mGuaranteedUplinkBitRate);
+
+ final int size = mRemoteAddresses.size();
+ dest.writeInt(size);
+ for (int i = 0; i < size; i++) {
+ final InetSocketAddress address = mRemoteAddresses.get(i);
+ dest.writeByteArray(address.getAddress().getAddress());
+ dest.writeInt(address.getPort());
+ }
+ }
+
+ @NonNull
+ public static final Creator<EpsBearerQosSessionAttributes> CREATOR =
+ new Creator<EpsBearerQosSessionAttributes>() {
+ @NonNull
+ @Override
+ public EpsBearerQosSessionAttributes createFromParcel(@NonNull final Parcel in) {
+ return new EpsBearerQosSessionAttributes(in);
+ }
+
+ @NonNull
+ @Override
+ public EpsBearerQosSessionAttributes[] newArray(final int size) {
+ return new EpsBearerQosSessionAttributes[size];
+ }
+ };
+}
diff --git a/telephony/java/android/telephony/ims/ImsReasonInfo.java b/telephony/java/android/telephony/ims/ImsReasonInfo.java
index c140249..dda021e 100644
--- a/telephony/java/android/telephony/ims/ImsReasonInfo.java
+++ b/telephony/java/android/telephony/ims/ImsReasonInfo.java
@@ -891,6 +891,12 @@
public static final int CODE_WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION = 1623;
/**
+ * Call failed because of network congestion, resource is not available,
+ * or no circuit or channel available, etc.
+ */
+ public static final int CODE_NETWORK_CONGESTION = 1624;
+
+ /**
* The dialed RTT call should be retried without RTT
* @hide
*/
@@ -1076,6 +1082,7 @@
CODE_REJECT_VT_AVPF_NOT_ALLOWED,
CODE_REJECT_ONGOING_ENCRYPTED_CALL,
CODE_REJECT_ONGOING_CS_CALL,
+ CODE_NETWORK_CONGESTION,
CODE_RETRY_ON_IMS_WITHOUT_RTT,
CODE_OEM_CAUSE_1,
CODE_OEM_CAUSE_2,
@@ -1268,6 +1275,7 @@
sImsCodeMap.put(CODE_REJECT_VT_AVPF_NOT_ALLOWED, "CODE_REJECT_VT_AVPF_NOT_ALLOWED");
sImsCodeMap.put(CODE_REJECT_ONGOING_ENCRYPTED_CALL, "CODE_REJECT_ONGOING_ENCRYPTED_CALL");
sImsCodeMap.put(CODE_REJECT_ONGOING_CS_CALL, "CODE_REJECT_ONGOING_CS_CALL");
+ sImsCodeMap.put(CODE_NETWORK_CONGESTION, "CODE_NETWORK_CONGESTION");
sImsCodeMap.put(CODE_RETRY_ON_IMS_WITHOUT_RTT, "CODE_RETRY_ON_IMS_WITHOUT_RTT");
sImsCodeMap.put(CODE_OEM_CAUSE_1, "CODE_OEM_CAUSE_1");
sImsCodeMap.put(CODE_OEM_CAUSE_2, "CODE_OEM_CAUSE_2");
diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java
index 8ed4838..b430bef 100644
--- a/telephony/java/android/telephony/ims/RegistrationManager.java
+++ b/telephony/java/android/telephony/ims/RegistrationManager.java
@@ -26,6 +26,7 @@
import android.os.Binder;
import android.os.Bundle;
import android.telephony.AccessNetworkConstants;
+import android.telephony.NetworkRegistrationInfo;
import android.telephony.ims.aidl.IImsRegistrationCallback;
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.stub.ImsRegistrationImplBase;
@@ -114,6 +115,22 @@
AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
}};
+ /** @hide */
+ @NonNull
+ static String registrationStateToString(
+ final @NetworkRegistrationInfo.RegistrationState int value) {
+ switch (value) {
+ case REGISTRATION_STATE_NOT_REGISTERED:
+ return "REGISTRATION_STATE_NOT_REGISTERED";
+ case REGISTRATION_STATE_REGISTERING:
+ return "REGISTRATION_STATE_REGISTERING";
+ case REGISTRATION_STATE_REGISTERED:
+ return "REGISTRATION_STATE_REGISTERED";
+ default:
+ return Integer.toString(value);
+ }
+ }
+
/**
* Callback class for receiving IMS network Registration callback events.
* @see #registerImsRegistrationCallback(Executor, RegistrationCallback)
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 46c9dde..15f6c41 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -49,6 +49,7 @@
import android.telephony.RadioAccessSpecifier;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
+import android.telephony.SignalStrengthUpdateRequest;
import android.telephony.TelephonyHistogram;
import android.telephony.VisualVoicemailSmsFilterSettings;
import android.telephony.emergency.EmergencyNumber;
@@ -2388,4 +2389,17 @@
* their mobile plan.
*/
String getMobileProvisioningUrl();
+
+ /**
+ * Set a SignalStrengthUpdateRequest to receive notification when Signal Strength breach the
+ * specified thresholds.
+ */
+ void setSignalStrengthUpdateRequest(int subId, in SignalStrengthUpdateRequest request,
+ String callingPackage);
+
+ /**
+ * Clear a SignalStrengthUpdateRequest from system.
+ */
+ void clearSignalStrengthUpdateRequest(int subId, in SignalStrengthUpdateRequest request,
+ String callingPackage);
}
diff --git a/test-mock/api/current.txt b/test-mock/api/current.txt
index 1110790..d1a68d4 100644
--- a/test-mock/api/current.txt
+++ b/test-mock/api/current.txt
@@ -117,6 +117,7 @@
method public void sendOrderedBroadcast(android.content.Intent, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle);
method public void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle);
method public void sendStickyBroadcast(android.content.Intent);
+ method public void sendStickyBroadcast(android.content.Intent, android.os.Bundle);
method public void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
method public void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle);
method public void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle);
diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java
index 98e7b53..5391bd8 100644
--- a/test-mock/src/android/test/mock/MockContext.java
+++ b/test-mock/src/android/test/mock/MockContext.java
@@ -493,6 +493,11 @@
}
@Override
+ public void sendStickyBroadcast(Intent intent, Bundle options) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public void sendStickyOrderedBroadcast(Intent intent,
BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData,
Bundle initialExtras) {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
index 412a3c3..907c9b5 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
@@ -16,6 +16,7 @@
package com.android.server.wm.flicker.ime
+import androidx.test.filters.FlakyTest
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
@@ -51,6 +52,7 @@
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest(bugId = 178015460)
class CloseImeAutoOpenWindowToAppTest(
testName: String,
flickerSpec: Flicker
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
index 663d456..4fd88f1 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
@@ -16,6 +16,7 @@
package com.android.server.wm.flicker.ime
+import androidx.test.filters.FlakyTest
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
@@ -51,6 +52,7 @@
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest(bugId = 178015460)
class CloseImeWindowToAppTest(
testName: String,
flickerSpec: Flicker
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index bfe5264..765bf6d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -16,6 +16,7 @@
package com.android.server.wm.flicker.ime
+import androidx.test.filters.FlakyTest
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
@@ -52,6 +53,7 @@
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest(bugId = 178015460)
class CloseImeWindowToHomeTest(
testName: String,
flickerSpec: Flicker
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
index 28a8bd3..b937f08 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -16,6 +16,7 @@
package com.android.server.wm.flicker.ime
+import androidx.test.filters.FlakyTest
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
@@ -53,6 +54,7 @@
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest(bugId = 178015460)
class OpenImeWindowTest(
testName: String,
flickerSpec: Flicker
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 3d8deb5..401d87a 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -88,7 +88,7 @@
* Enable rollback phase.
*/
@Test
- public void testBadApkOnly_Phase1() throws Exception {
+ public void testBadApkOnly_Phase1_Install() throws Exception {
Uninstall.packages(TestApp.A);
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
@@ -104,7 +104,7 @@
* Confirm that rollback was successfully enabled.
*/
@Test
- public void testBadApkOnly_Phase2() throws Exception {
+ public void testBadApkOnly_Phase2_VerifyInstall() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
InstallUtils.processUserData(TestApp.A);
@@ -129,7 +129,7 @@
* Trigger rollback phase.
*/
@Test
- public void testBadApkOnly_Phase3() throws Exception {
+ public void testBadApkOnly_Phase3_Crash() throws Exception {
// One more crash to trigger rollback
RollbackUtils.sendCrashBroadcast(TestApp.A, 1);
}
@@ -139,7 +139,7 @@
* Confirm rollback phase.
*/
@Test
- public void testBadApkOnly_Phase4() throws Exception {
+ public void testBadApkOnly_Phase4_VerifyRollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
InstallUtils.processUserData(TestApp.A);
@@ -158,7 +158,7 @@
* Stage install an apk with rollback that will be later triggered by unattributable crash.
*/
@Test
- public void testNativeWatchdogTriggersRollback_Phase1() throws Exception {
+ public void testNativeWatchdogTriggersRollback_Phase1_Install() throws Exception {
Uninstall.packages(TestApp.A);
Install.single(TestApp.A1).commit();
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
@@ -170,7 +170,7 @@
* Verify the rollback is available.
*/
@Test
- public void testNativeWatchdogTriggersRollback_Phase2() throws Exception {
+ public void testNativeWatchdogTriggersRollback_Phase2_VerifyInstall() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
RollbackManager rm = RollbackUtils.getRollbackManager();
assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
@@ -181,7 +181,7 @@
* Verify the rollback is committed after crashing.
*/
@Test
- public void testNativeWatchdogTriggersRollback_Phase3() throws Exception {
+ public void testNativeWatchdogTriggersRollback_Phase3_VerifyRollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
RollbackManager rm = RollbackUtils.getRollbackManager();
assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
@@ -192,7 +192,7 @@
* Stage install an apk with rollback that will be later triggered by unattributable crash.
*/
@Test
- public void testNativeWatchdogTriggersRollbackForAll_Phase1() throws Exception {
+ public void testNativeWatchdogTriggersRollbackForAll_Phase1_InstallA() throws Exception {
Uninstall.packages(TestApp.A);
Install.single(TestApp.A1).commit();
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
@@ -204,7 +204,7 @@
* Verify the rollback is available and then install another package with rollback.
*/
@Test
- public void testNativeWatchdogTriggersRollbackForAll_Phase2() throws Exception {
+ public void testNativeWatchdogTriggersRollbackForAll_Phase2_InstallB() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
RollbackManager rm = RollbackUtils.getRollbackManager();
assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
@@ -222,7 +222,7 @@
* Verify the rollbacks are available.
*/
@Test
- public void testNativeWatchdogTriggersRollbackForAll_Phase3() throws Exception {
+ public void testNativeWatchdogTriggersRollbackForAll_Phase3_VerifyInstall() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
RollbackManager rm = RollbackUtils.getRollbackManager();
@@ -236,7 +236,7 @@
* Verify the rollbacks are committed after crashing.
*/
@Test
- public void testNativeWatchdogTriggersRollbackForAll_Phase4() throws Exception {
+ public void testNativeWatchdogTriggersRollbackForAll_Phase4_VerifyRollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1);
RollbackManager rm = RollbackUtils.getRollbackManager();
@@ -247,7 +247,7 @@
}
@Test
- public void testPreviouslyAbandonedRollbacks_Phase1() throws Exception {
+ public void testPreviouslyAbandonedRollbacks_Phase1_InstallAndAbandon() throws Exception {
Uninstall.packages(TestApp.A);
Install.single(TestApp.A1).commit();
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
@@ -261,7 +261,7 @@
}
@Test
- public void testPreviouslyAbandonedRollbacks_Phase2() throws Exception {
+ public void testPreviouslyAbandonedRollbacks_Phase2_Rollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
InstallUtils.processUserData(TestApp.A);
@@ -272,7 +272,7 @@
}
@Test
- public void testPreviouslyAbandonedRollbacks_Phase3() throws Exception {
+ public void testPreviouslyAbandonedRollbacks_Phase3_VerifyRollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
InstallUtils.processUserData(TestApp.A);
Uninstall.packages(TestApp.A);
@@ -284,7 +284,7 @@
}
@Test
- public void testRollbackWhitelistedApp_Phase1() throws Exception {
+ public void testRollbackAllowlistedApp_Phase1_Install() throws Exception {
// Remove available rollbacks
String pkgName = getModuleMetadataPackageName();
RollbackUtils.getRollbackManager().expireRollbackForPackage(pkgName);
@@ -296,7 +296,7 @@
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.MANAGE_ROLLBACKS);
- // Re-install a whitelisted app with rollbacks enabled
+ // Re-install a allowlisted app with rollbacks enabled
String filePath = InstrumentationRegistry.getInstrumentation().getContext()
.getPackageManager().getPackageInfo(pkgName, 0).applicationInfo.sourceDir;
TestApp app = new TestApp("ModuleMetadata", pkgName, -1, false, new File(filePath));
@@ -305,12 +305,12 @@
}
@Test
- public void testRollbackWhitelistedApp_Phase2() throws Exception {
+ public void testRollbackAllowlistedApp_Phase2_VerifyInstall() throws Exception {
assertThat(RollbackUtils.getAvailableRollback(getModuleMetadataPackageName())).isNotNull();
}
@Test
- public void testRollbackDataPolicy_Phase1() throws Exception {
+ public void testRollbackDataPolicy_Phase1_Install() throws Exception {
Uninstall.packages(TestApp.A, TestApp.B, TestApp.C);
Install.multi(TestApp.A1, TestApp.B1, TestApp.C1).commit();
// Write user data version = 1
@@ -328,7 +328,7 @@
}
@Test
- public void testRollbackDataPolicy_Phase2() throws Exception {
+ public void testRollbackDataPolicy_Phase2_Rollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
// Write user data version = 2
@@ -341,7 +341,7 @@
}
@Test
- public void testRollbackDataPolicy_Phase3() throws Exception {
+ public void testRollbackDataPolicy_Phase3_VerifyRollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1);
assertThat(InstallUtils.getInstalledVersion(TestApp.C)).isEqualTo(1);
@@ -355,7 +355,7 @@
}
@Test
- public void testCleanUp() throws Exception {
+ public void expireRollbacks() throws Exception {
// testNativeWatchdogTriggersRollback will fail if multiple staged sessions are
// committed on a device which doesn't support checkpoint. Let's clean up all rollbacks
// so there is only one rollback to commit when testing native crashes.
@@ -378,7 +378,7 @@
APK_IN_APEX_TESTAPEX_NAME + "_v2Crashing.apex");
@Test
- public void testRollbackApexWithApk_Phase1() throws Exception {
+ public void testRollbackApexWithApk_Phase1_Install() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
InstallUtils.processUserData(TestApp.A);
@@ -388,7 +388,7 @@
}
@Test
- public void testRollbackApexWithApk_Phase2() throws Exception {
+ public void testRollbackApexWithApk_Phase2_Rollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(APK_IN_APEX_TESTAPEX_NAME)).isEqualTo(2);
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
InstallUtils.processUserData(TestApp.A);
@@ -416,7 +416,7 @@
}
@Test
- public void testRollbackApexWithApk_Phase3() throws Exception {
+ public void testRollbackApexWithApk_Phase3_VerifyRollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(APK_IN_APEX_TESTAPEX_NAME)).isEqualTo(1);
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
InstallUtils.processUserData(TestApp.A);
@@ -426,7 +426,7 @@
* Installs an apex with an apk that can crash.
*/
@Test
- public void testRollbackApexWithApkCrashing_Phase1() throws Exception {
+ public void testRollbackApexWithApkCrashing_Phase1_Install() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
int sessionId = Install.single(TEST_APEX_WITH_APK_V2_CRASHING).setStaged()
.setEnableRollback().commit();
@@ -437,7 +437,7 @@
* Verifies rollback has been enabled successfully. Then makes TestApp.A crash.
*/
@Test
- public void testRollbackApexWithApkCrashing_Phase2() throws Exception {
+ public void testRollbackApexWithApkCrashing_Phase2_Crash() throws Exception {
assertThat(InstallUtils.getInstalledVersion(APK_IN_APEX_TESTAPEX_NAME)).isEqualTo(2);
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
@@ -452,20 +452,20 @@
}
@Test
- public void testRollbackApexWithApkCrashing_Phase3() throws Exception {
+ public void testRollbackApexWithApkCrashing_Phase3_VerifyRollback() throws Exception {
assertThat(InstallUtils.getInstalledVersion(APK_IN_APEX_TESTAPEX_NAME)).isEqualTo(1);
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
}
@Test
- public void testRollbackApexDataDirectories_Phase1() throws Exception {
+ public void testRollbackApexDataDirectories_Phase1_Install() throws Exception {
int sessionId = Install.single(TEST_APEX_WITH_APK_V2).setStaged().setEnableRollback()
.commit();
InstallUtils.waitForSessionReady(sessionId);
}
@Test
- public void testRollbackApexDataDirectories_Phase2() throws Exception {
+ public void testRollbackApexDataDirectories_Phase2_Rollback() throws Exception {
RollbackInfo available = RollbackUtils.getAvailableRollback(APK_IN_APEX_TESTAPEX_NAME);
RollbackUtils.rollback(available.getRollbackId(), TEST_APEX_WITH_APK_V2);
@@ -477,19 +477,19 @@
}
@Test
- public void testRollbackApkDataDirectories_Phase1() throws Exception {
+ public void testRollbackApkDataDirectories_Phase1_InstallV1() throws Exception {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
Install.single(TestApp.A1).commit();
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
}
@Test
- public void testRollbackApkDataDirectories_Phase2() throws Exception {
+ public void testRollbackApkDataDirectories_Phase2_InstallV2() throws Exception {
Install.single(TestApp.A2).setStaged().setEnableRollback().commit();
}
@Test
- public void testRollbackApkDataDirectories_Phase3() throws Exception {
+ public void testRollbackApkDataDirectories_Phase3_Rollback() throws Exception {
RollbackInfo available = RollbackUtils.getAvailableRollback(TestApp.A);
RollbackUtils.rollback(available.getRollbackId(), TestApp.A2);
RollbackInfo committed = RollbackUtils.getCommittedRollbackById(available.getRollbackId());
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index 94950dc..1d5730f 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -97,14 +97,14 @@
public void setUp() throws Exception {
deleteFiles("/system/apex/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex",
"/data/apex/active/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex");
- runPhase("testCleanUp");
+ runPhase("expireRollbacks");
mLogger.start(getDevice());
}
@After
public void tearDown() throws Exception {
mLogger.stop();
- runPhase("testCleanUp");
+ runPhase("expireRollbacks");
deleteFiles("/system/apex/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex",
"/data/apex/active/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex",
apexDataDirDeSys(APK_IN_APEX_TESTAPEX_NAME) + "*",
@@ -139,22 +139,27 @@
}
}
+ private void waitForDeviceNotAvailable(long timeout, TimeUnit unit) {
+ assertWithMessage("waitForDeviceNotAvailable() timed out in %s %s", timeout, unit)
+ .that(getDevice().waitForDeviceNotAvailable(unit.toMillis(timeout))).isTrue();
+ }
+
/**
* Tests watchdog triggered staged rollbacks involving only apks.
*/
@Test
public void testBadApkOnly() throws Exception {
- runPhase("testBadApkOnly_Phase1");
+ runPhase("testBadApkOnly_Phase1_Install");
getDevice().reboot();
- runPhase("testBadApkOnly_Phase2");
+ runPhase("testBadApkOnly_Phase2_VerifyInstall");
// Trigger rollback and wait for reboot to happen
- runPhase("testBadApkOnly_Phase3");
- assertThat(getDevice().waitForDeviceNotAvailable(TimeUnit.MINUTES.toMillis(2))).isTrue();
+ runPhase("testBadApkOnly_Phase3_Crash");
+ waitForDeviceNotAvailable(2, TimeUnit.MINUTES);
getDevice().waitForDeviceAvailable();
- runPhase("testBadApkOnly_Phase4");
+ runPhase("testBadApkOnly_Phase4_VerifyRollback");
assertThat(mLogger).eventOccurred(ROLLBACK_INITIATE, null, REASON_APP_CRASH, TESTAPP_A);
assertThat(mLogger).eventOccurred(ROLLBACK_BOOT_TRIGGERED, null, null, null);
@@ -163,12 +168,12 @@
@Test
public void testNativeWatchdogTriggersRollback() throws Exception {
- runPhase("testNativeWatchdogTriggersRollback_Phase1");
+ runPhase("testNativeWatchdogTriggersRollback_Phase1_Install");
// Reboot device to activate staged package
getDevice().reboot();
- runPhase("testNativeWatchdogTriggersRollback_Phase2");
+ runPhase("testNativeWatchdogTriggersRollback_Phase2_VerifyInstall");
// crash system_server enough times to trigger a rollback
crashProcess("system_server", NATIVE_CRASHES_THRESHOLD);
@@ -181,11 +186,11 @@
// 3. Staged rollback session becomes ready.
// 4. Device actually reboots.
// So we give a generous timeout here.
- assertThat(getDevice().waitForDeviceNotAvailable(TimeUnit.MINUTES.toMillis(5))).isTrue();
+ waitForDeviceNotAvailable(5, TimeUnit.MINUTES);
getDevice().waitForDeviceAvailable();
// verify rollback committed
- runPhase("testNativeWatchdogTriggersRollback_Phase3");
+ runPhase("testNativeWatchdogTriggersRollback_Phase3_VerifyRollback");
assertThat(mLogger).eventOccurred(ROLLBACK_INITIATE, null, REASON_NATIVE_CRASH, null);
assertThat(mLogger).eventOccurred(ROLLBACK_BOOT_TRIGGERED, null, null, null);
@@ -198,15 +203,15 @@
assumeTrue(isCheckpointSupported());
// Install a package with rollback enabled.
- runPhase("testNativeWatchdogTriggersRollbackForAll_Phase1");
+ runPhase("testNativeWatchdogTriggersRollbackForAll_Phase1_InstallA");
getDevice().reboot();
// Once previous staged install is applied, install another package
- runPhase("testNativeWatchdogTriggersRollbackForAll_Phase2");
+ runPhase("testNativeWatchdogTriggersRollbackForAll_Phase2_InstallB");
getDevice().reboot();
// Verify the new staged install has also been applied successfully.
- runPhase("testNativeWatchdogTriggersRollbackForAll_Phase3");
+ runPhase("testNativeWatchdogTriggersRollbackForAll_Phase3_VerifyInstall");
// crash system_server enough times to trigger a rollback
crashProcess("system_server", NATIVE_CRASHES_THRESHOLD);
@@ -219,11 +224,11 @@
// 3. Staged rollback session becomes ready.
// 4. Device actually reboots.
// So we give a generous timeout here.
- assertThat(getDevice().waitForDeviceNotAvailable(TimeUnit.MINUTES.toMillis(5))).isTrue();
+ waitForDeviceNotAvailable(5, TimeUnit.MINUTES);
getDevice().waitForDeviceAvailable();
// verify all available rollbacks have been committed
- runPhase("testNativeWatchdogTriggersRollbackForAll_Phase4");
+ runPhase("testNativeWatchdogTriggersRollbackForAll_Phase4_VerifyRollback");
assertThat(mLogger).eventOccurred(ROLLBACK_INITIATE, null, REASON_NATIVE_CRASH, null);
assertThat(mLogger).eventOccurred(ROLLBACK_BOOT_TRIGGERED, null, null, null);
@@ -235,33 +240,33 @@
*/
@Test
public void testPreviouslyAbandonedRollbacks() throws Exception {
- runPhase("testPreviouslyAbandonedRollbacks_Phase1");
+ runPhase("testPreviouslyAbandonedRollbacks_Phase1_InstallAndAbandon");
getDevice().reboot();
- runPhase("testPreviouslyAbandonedRollbacks_Phase2");
+ runPhase("testPreviouslyAbandonedRollbacks_Phase2_Rollback");
getDevice().reboot();
- runPhase("testPreviouslyAbandonedRollbacks_Phase3");
+ runPhase("testPreviouslyAbandonedRollbacks_Phase3_VerifyRollback");
}
/**
- * Tests we can enable rollback for a whitelisted app.
+ * Tests we can enable rollback for a allowlisted app.
*/
@Test
- public void testRollbackWhitelistedApp() throws Exception {
+ public void testRollbackAllowlistedApp() throws Exception {
assumeTrue(hasMainlineModule());
- runPhase("testRollbackWhitelistedApp_Phase1");
+ runPhase("testRollbackAllowlistedApp_Phase1_Install");
getDevice().reboot();
- runPhase("testRollbackWhitelistedApp_Phase2");
+ runPhase("testRollbackAllowlistedApp_Phase2_VerifyInstall");
}
@Test
public void testRollbackDataPolicy() throws Exception {
List<String> before = getSnapshotDirectories("/data/misc_ce/0/rollback");
- runPhase("testRollbackDataPolicy_Phase1");
+ runPhase("testRollbackDataPolicy_Phase1_Install");
getDevice().reboot();
- runPhase("testRollbackDataPolicy_Phase2");
+ runPhase("testRollbackDataPolicy_Phase2_Rollback");
getDevice().reboot();
- runPhase("testRollbackDataPolicy_Phase3");
+ runPhase("testRollbackDataPolicy_Phase3_VerifyRollback");
// Verify snapshots are deleted after restoration
List<String> after = getSnapshotDirectories("/data/misc_ce/0/rollback");
@@ -279,11 +284,11 @@
public void testRollbackApexWithApk() throws Exception {
getDevice().uninstallPackage("com.android.cts.install.lib.testapp.A");
pushTestApex();
- runPhase("testRollbackApexWithApk_Phase1");
+ runPhase("testRollbackApexWithApk_Phase1_Install");
getDevice().reboot();
- runPhase("testRollbackApexWithApk_Phase2");
+ runPhase("testRollbackApexWithApk_Phase2_Rollback");
getDevice().reboot();
- runPhase("testRollbackApexWithApk_Phase3");
+ runPhase("testRollbackApexWithApk_Phase3_VerifyRollback");
}
/**
@@ -295,15 +300,15 @@
pushTestApex();
// Install an apex with apk that crashes
- runPhase("testRollbackApexWithApkCrashing_Phase1");
+ runPhase("testRollbackApexWithApkCrashing_Phase1_Install");
getDevice().reboot();
// Verify apex was installed and then crash the apk
- runPhase("testRollbackApexWithApkCrashing_Phase2");
+ runPhase("testRollbackApexWithApkCrashing_Phase2_Crash");
// Wait for crash to trigger rollback
- assertThat(getDevice().waitForDeviceNotAvailable(TimeUnit.MINUTES.toMillis(5))).isTrue();
+ waitForDeviceNotAvailable(5, TimeUnit.MINUTES);
getDevice().waitForDeviceAvailable();
// Verify rollback occurred due to crash of apk-in-apex
- runPhase("testRollbackApexWithApkCrashing_Phase3");
+ runPhase("testRollbackApexWithApkCrashing_Phase3_VerifyRollback");
assertThat(mLogger).eventOccurred(ROLLBACK_INITIATE, null, REASON_APP_CRASH, TESTAPP_A);
assertThat(mLogger).eventOccurred(ROLLBACK_BOOT_TRIGGERED, null, null, null);
@@ -323,12 +328,12 @@
String oldFilePath2 =
apexDataDirDeSys(APK_IN_APEX_TESTAPEX_NAME) + TEST_SUBDIR + TEST_FILENAME_2;
runAsRoot(() -> {
- assertThat(getDevice().pushString(TEST_STRING_1, oldFilePath1)).isTrue();
- assertThat(getDevice().pushString(TEST_STRING_2, oldFilePath2)).isTrue();
+ pushString(TEST_STRING_1, oldFilePath1);
+ pushString(TEST_STRING_2, oldFilePath2);
});
// Install new version of the APEX with rollback enabled
- runPhase("testRollbackApexDataDirectories_Phase1");
+ runPhase("testRollbackApexDataDirectories_Phase1_Install");
getDevice().reboot();
// Replace files in data directory
@@ -338,20 +343,20 @@
runAsRoot(() -> {
getDevice().deleteFile(oldFilePath1);
getDevice().deleteFile(oldFilePath2);
- assertThat(getDevice().pushString(TEST_STRING_3, newFilePath3)).isTrue();
- assertThat(getDevice().pushString(TEST_STRING_4, newFilePath4)).isTrue();
+ pushString(TEST_STRING_3, newFilePath3);
+ pushString(TEST_STRING_4, newFilePath4);
});
// Roll back the APEX
- runPhase("testRollbackApexDataDirectories_Phase2");
+ runPhase("testRollbackApexDataDirectories_Phase2_Rollback");
getDevice().reboot();
// Verify that old files have been restored and new files are gone
runAsRoot(() -> {
- assertThat(getDevice().pullFileContents(oldFilePath1)).isEqualTo(TEST_STRING_1);
- assertThat(getDevice().pullFileContents(oldFilePath2)).isEqualTo(TEST_STRING_2);
- assertThat(getDevice().pullFile(newFilePath3)).isNull();
- assertThat(getDevice().pullFile(newFilePath4)).isNull();
+ assertFileContents(TEST_STRING_1, oldFilePath1);
+ assertFileContents(TEST_STRING_2, oldFilePath2);
+ assertFileNotExists(newFilePath3);
+ assertFileNotExists(newFilePath4);
});
// Verify snapshots are deleted after restoration
@@ -377,12 +382,12 @@
String oldFilePath2 =
apexDataDirDeUser(APK_IN_APEX_TESTAPEX_NAME, 0) + TEST_SUBDIR + TEST_FILENAME_2;
runAsRoot(() -> {
- assertThat(getDevice().pushString(TEST_STRING_1, oldFilePath1)).isTrue();
- assertThat(getDevice().pushString(TEST_STRING_2, oldFilePath2)).isTrue();
+ pushString(TEST_STRING_1, oldFilePath1);
+ pushString(TEST_STRING_2, oldFilePath2);
});
// Install new version of the APEX with rollback enabled
- runPhase("testRollbackApexDataDirectories_Phase1");
+ runPhase("testRollbackApexDataDirectories_Phase1_Install");
getDevice().reboot();
// Replace files in data directory
@@ -393,20 +398,20 @@
runAsRoot(() -> {
getDevice().deleteFile(oldFilePath1);
getDevice().deleteFile(oldFilePath2);
- assertThat(getDevice().pushString(TEST_STRING_3, newFilePath3)).isTrue();
- assertThat(getDevice().pushString(TEST_STRING_4, newFilePath4)).isTrue();
+ pushString(TEST_STRING_3, newFilePath3);
+ pushString(TEST_STRING_4, newFilePath4);
});
// Roll back the APEX
- runPhase("testRollbackApexDataDirectories_Phase2");
+ runPhase("testRollbackApexDataDirectories_Phase2_Rollback");
getDevice().reboot();
// Verify that old files have been restored and new files are gone
runAsRoot(() -> {
- assertThat(getDevice().pullFileContents(oldFilePath1)).isEqualTo(TEST_STRING_1);
- assertThat(getDevice().pullFileContents(oldFilePath2)).isEqualTo(TEST_STRING_2);
- assertThat(getDevice().pullFile(newFilePath3)).isNull();
- assertThat(getDevice().pullFile(newFilePath4)).isNull();
+ assertFileContents(TEST_STRING_1, oldFilePath1);
+ assertFileContents(TEST_STRING_2, oldFilePath2);
+ assertFileNotExists(newFilePath3);
+ assertFileNotExists(newFilePath4);
});
// Verify snapshots are deleted after restoration
@@ -431,12 +436,12 @@
String oldFilePath2 =
apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + TEST_SUBDIR + TEST_FILENAME_2;
runAsRoot(() -> {
- assertThat(getDevice().pushString(TEST_STRING_1, oldFilePath1)).isTrue();
- assertThat(getDevice().pushString(TEST_STRING_2, oldFilePath2)).isTrue();
+ pushString(TEST_STRING_1, oldFilePath1);
+ pushString(TEST_STRING_2, oldFilePath2);
});
// Install new version of the APEX with rollback enabled
- runPhase("testRollbackApexDataDirectories_Phase1");
+ runPhase("testRollbackApexDataDirectories_Phase1_Install");
getDevice().reboot();
// Replace files in data directory
@@ -446,20 +451,20 @@
runAsRoot(() -> {
getDevice().deleteFile(oldFilePath1);
getDevice().deleteFile(oldFilePath2);
- assertThat(getDevice().pushString(TEST_STRING_3, newFilePath3)).isTrue();
- assertThat(getDevice().pushString(TEST_STRING_4, newFilePath4)).isTrue();
+ pushString(TEST_STRING_3, newFilePath3);
+ pushString(TEST_STRING_4, newFilePath4);
});
// Roll back the APEX
- runPhase("testRollbackApexDataDirectories_Phase2");
+ runPhase("testRollbackApexDataDirectories_Phase2_Rollback");
getDevice().reboot();
// Verify that old files have been restored and new files are gone
runAsRoot(() -> {
- assertThat(getDevice().pullFileContents(oldFilePath1)).isEqualTo(TEST_STRING_1);
- assertThat(getDevice().pullFileContents(oldFilePath2)).isEqualTo(TEST_STRING_2);
- assertThat(getDevice().pullFile(newFilePath3)).isNull();
- assertThat(getDevice().pullFile(newFilePath4)).isNull();
+ assertFileContents(TEST_STRING_1, oldFilePath1);
+ assertFileContents(TEST_STRING_2, oldFilePath2);
+ assertFileNotExists(newFilePath3);
+ assertFileNotExists(newFilePath4);
});
// Verify snapshots are deleted after restoration
@@ -477,18 +482,18 @@
@Test
public void testRollbackApkDataDirectories_De() throws Exception {
// Install version 1 of TESTAPP_A
- runPhase("testRollbackApkDataDirectories_Phase1");
+ runPhase("testRollbackApkDataDirectories_Phase1_InstallV1");
// Push files to apk data directory
String oldFilePath1 = apkDataDirDe(TESTAPP_A, 0) + "/" + TEST_FILENAME_1;
String oldFilePath2 = apkDataDirDe(TESTAPP_A, 0) + TEST_SUBDIR + TEST_FILENAME_2;
runAsRoot(() -> {
- assertThat(getDevice().pushString(TEST_STRING_1, oldFilePath1)).isTrue();
- assertThat(getDevice().pushString(TEST_STRING_2, oldFilePath2)).isTrue();
+ pushString(TEST_STRING_1, oldFilePath1);
+ pushString(TEST_STRING_2, oldFilePath2);
});
// Install version 2 of TESTAPP_A with rollback enabled
- runPhase("testRollbackApkDataDirectories_Phase2");
+ runPhase("testRollbackApkDataDirectories_Phase2_InstallV2");
getDevice().reboot();
// Replace files in data directory
@@ -497,20 +502,20 @@
runAsRoot(() -> {
getDevice().deleteFile(oldFilePath1);
getDevice().deleteFile(oldFilePath2);
- assertThat(getDevice().pushString(TEST_STRING_3, newFilePath3)).isTrue();
- assertThat(getDevice().pushString(TEST_STRING_4, newFilePath4)).isTrue();
+ pushString(TEST_STRING_3, newFilePath3);
+ pushString(TEST_STRING_4, newFilePath4);
});
// Roll back the APK
- runPhase("testRollbackApkDataDirectories_Phase3");
+ runPhase("testRollbackApkDataDirectories_Phase3_Rollback");
getDevice().reboot();
// Verify that old files have been restored and new files are gone
runAsRoot(() -> {
- assertThat(getDevice().pullFileContents(oldFilePath1)).isEqualTo(TEST_STRING_1);
- assertThat(getDevice().pullFileContents(oldFilePath2)).isEqualTo(TEST_STRING_2);
- assertThat(getDevice().pullFile(newFilePath3)).isNull();
- assertThat(getDevice().pullFile(newFilePath4)).isNull();
+ assertFileContents(TEST_STRING_1, oldFilePath1);
+ assertFileContents(TEST_STRING_2, oldFilePath2);
+ assertFileNotExists(newFilePath3);
+ assertFileNotExists(newFilePath4);
});
}
@@ -524,12 +529,12 @@
String oldFilePath2 =
apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + TEST_SUBDIR + TEST_FILENAME_2;
runAsRoot(() -> {
- assertThat(getDevice().pushString(TEST_STRING_1, oldFilePath1)).isTrue();
- assertThat(getDevice().pushString(TEST_STRING_2, oldFilePath2)).isTrue();
+ pushString(TEST_STRING_1, oldFilePath1);
+ pushString(TEST_STRING_2, oldFilePath2);
});
// Install new version of the APEX with rollback enabled
- runPhase("testRollbackApexDataDirectories_Phase1");
+ runPhase("testRollbackApexDataDirectories_Phase1_Install");
getDevice().reboot();
List<String> after = getSnapshotDirectories("/data/misc_ce/0/apexrollback");
@@ -538,10 +543,10 @@
// There should be only one /data/misc_ce/0/apexrollback/<rollbackId> created during test
assertThat(after).hasSize(1);
// Expire all rollbacks and check CE snapshot directories are deleted
- runPhase("testCleanUp");
+ runPhase("expireRollbacks");
runAsRoot(() -> {
for (String dir : after) {
- assertThat(getDevice().getFileEntry(dir)).isNull();
+ assertFileNotExists(dir);
}
});
}
@@ -560,6 +565,23 @@
getDevice().reboot();
}
+ private void pushString(String contents, String path) throws Exception {
+ assertWithMessage("Failed to push file to device, content=%s path=%s", contents, path)
+ .that(getDevice().pushString(contents, path)).isTrue();
+ }
+
+ private void assertFileContents(String expectedContents, String path) throws Exception {
+ String actualContents = getDevice().pullFileContents(path);
+ assertWithMessage("Failed to retrieve file=%s", path).that(actualContents).isNotNull();
+ assertWithMessage("Mismatched file contents, path=%s", path)
+ .that(actualContents).isEqualTo(expectedContents);
+ }
+
+ private void assertFileNotExists(String path) throws Exception {
+ assertWithMessage("File shouldn't exist, path=%s", path)
+ .that(getDevice().getFileEntry(path)).isNull();
+ }
+
private static String apexDataDirDeSys(String apexName) {
return String.format("/data/misc/apexdata/%s", apexName);
}
diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
index 3d4dc4d..dc9e587 100644
--- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
+++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -31,6 +31,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
+import android.annotation.NonNull;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
@@ -40,6 +41,7 @@
import android.net.NetworkCapabilities;
import android.net.NetworkProvider;
import android.net.NetworkSpecifier;
+import android.net.QosFilter;
import android.net.SocketKeepalive;
import android.net.UidRange;
import android.os.ConditionVariable;
@@ -47,10 +49,12 @@
import android.os.Message;
import android.util.Log;
+import com.android.net.module.util.ArrayTrackRecord;
import com.android.server.connectivity.ConnectivityConstants;
import com.android.testutils.HandlerUtils;
import com.android.testutils.TestableNetworkCallback;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -71,6 +75,8 @@
// start/stop. Useful when simulate KeepaliveTracker is waiting for response from modem.
private long mKeepaliveResponseDelay = 0L;
private Integer mExpectedKeepaliveSlot = null;
+ private final ArrayTrackRecord<CallbackType>.ReadHead mCallbackHistory =
+ new ArrayTrackRecord<CallbackType>().newReadHead();
public NetworkAgentWrapper(int transport, LinkProperties linkProperties,
NetworkCapabilities ncTemplate, Context context) throws Exception {
@@ -157,6 +163,20 @@
}
@Override
+ public void onQosCallbackRegistered(final int qosCallbackId,
+ final @NonNull QosFilter filter) {
+ Log.i(mWrapper.mLogTag, "onQosCallbackRegistered");
+ mWrapper.mCallbackHistory.add(
+ new CallbackType.OnQosCallbackRegister(qosCallbackId, filter));
+ }
+
+ @Override
+ public void onQosCallbackUnregistered(final int qosCallbackId) {
+ Log.i(mWrapper.mLogTag, "onQosCallbackUnregistered");
+ mWrapper.mCallbackHistory.add(new CallbackType.OnQosCallbackUnregister(qosCallbackId));
+ }
+
+ @Override
protected void preventAutomaticReconnect() {
mWrapper.mPreventReconnectReceived.open();
}
@@ -279,7 +299,60 @@
return mNetworkCapabilities;
}
+ public @NonNull ArrayTrackRecord<CallbackType>.ReadHead getCallbackHistory() {
+ return mCallbackHistory;
+ }
+
public void waitForIdle(long timeoutMs) {
HandlerUtils.waitForIdle(mHandlerThread, timeoutMs);
}
+
+ abstract static class CallbackType {
+ final int mQosCallbackId;
+
+ protected CallbackType(final int qosCallbackId) {
+ mQosCallbackId = qosCallbackId;
+ }
+
+ static class OnQosCallbackRegister extends CallbackType {
+ final QosFilter mFilter;
+ OnQosCallbackRegister(final int qosCallbackId, final QosFilter filter) {
+ super(qosCallbackId);
+ mFilter = filter;
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ final OnQosCallbackRegister that = (OnQosCallbackRegister) o;
+ return mQosCallbackId == that.mQosCallbackId
+ && Objects.equals(mFilter, that.mFilter);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mQosCallbackId, mFilter);
+ }
+ }
+
+ static class OnQosCallbackUnregister extends CallbackType {
+ OnQosCallbackUnregister(final int qosCallbackId) {
+ super(qosCallbackId);
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ final OnQosCallbackUnregister that = (OnQosCallbackUnregister) o;
+ return mQosCallbackId == that.mQosCallbackId;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mQosCallbackId);
+ }
+ }
+ }
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 4630269..c5e6c35 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -167,6 +167,7 @@
import android.net.INetworkMonitorCallbacks;
import android.net.INetworkPolicyListener;
import android.net.INetworkStatsService;
+import android.net.IQosCallback;
import android.net.InetAddresses;
import android.net.InterfaceConfigurationParcel;
import android.net.IpPrefix;
@@ -190,6 +191,9 @@
import android.net.NetworkState;
import android.net.NetworkTestResultParcelable;
import android.net.ProxyInfo;
+import android.net.QosCallbackException;
+import android.net.QosFilter;
+import android.net.QosSession;
import android.net.ResolverParamsParcel;
import android.net.RouteInfo;
import android.net.RouteInfoParcel;
@@ -218,6 +222,7 @@
import android.os.Parcelable;
import android.os.Process;
import android.os.RemoteException;
+import android.os.ServiceSpecificException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
@@ -226,10 +231,12 @@
import android.security.KeyStore;
import android.system.Os;
import android.telephony.TelephonyManager;
+import android.telephony.data.EpsBearerQosSessionAttributes;
import android.test.mock.MockContentResolver;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
+import android.util.Pair;
import android.util.SparseArray;
import androidx.test.InstrumentationRegistry;
@@ -251,6 +258,7 @@
import com.android.server.connectivity.NetworkAgentInfo;
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
import com.android.server.connectivity.ProxyTracker;
+import com.android.server.connectivity.QosCallbackTracker;
import com.android.server.connectivity.Vpn;
import com.android.server.net.NetworkPinner;
import com.android.server.net.NetworkPolicyManagerInternal;
@@ -368,6 +376,8 @@
private WrappedMultinetworkPolicyTracker mPolicyTracker;
private HandlerThread mAlarmManagerThread;
private TestNetIdManager mNetIdManager;
+ private QosCallbackMockHelper mQosCallbackMockHelper;
+ private QosCallbackTracker mQosCallbackTracker;
@Mock DeviceIdleInternal mDeviceIdleInternal;
@Mock INetworkManagementService mNetworkManagementService;
@@ -1395,6 +1405,7 @@
mService.systemReadyInternal();
mockVpn(Process.myUid());
mCm.bindProcessToNetwork(null);
+ mQosCallbackTracker = mock(QosCallbackTracker.class);
// Ensure that the default setting for Captive Portals is used for most tests
setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
@@ -1470,6 +1481,11 @@
mEthernetNetworkAgent.disconnect();
mEthernetNetworkAgent = null;
}
+
+ if (mQosCallbackMockHelper != null) {
+ mQosCallbackMockHelper.tearDown();
+ mQosCallbackMockHelper = null;
+ }
mMockVpn.disconnect();
waitForIdle();
@@ -4379,7 +4395,7 @@
}
private Network connectKeepaliveNetwork(LinkProperties lp) throws Exception {
- // Ensure the network is disconnected before we do anything.
+ // Ensure the network is disconnected before anything else occurs
if (mWiFiNetworkAgent != null) {
assertNull(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()));
}
@@ -8512,7 +8528,7 @@
TelephonyManager.getNetworkTypeName(TelephonyManager.NETWORK_TYPE_LTE));
return new NetworkAgentInfo(null, new Network(NET_ID), info, new LinkProperties(),
nc, 0, mServiceContext, null, new NetworkAgentConfig(), mService, null, null, null,
- 0, INVALID_UID);
+ 0, INVALID_UID, mQosCallbackTracker);
}
@Test
@@ -8890,7 +8906,7 @@
@Test
public void testInvalidRequestTypes() {
- final int[] invalidReqTypeInts = new int[] {-1, NetworkRequest.Type.NONE.ordinal(),
+ final int[] invalidReqTypeInts = new int[]{-1, NetworkRequest.Type.NONE.ordinal(),
NetworkRequest.Type.LISTEN.ordinal(), NetworkRequest.Type.values().length};
final NetworkCapabilities nc = new NetworkCapabilities().addTransportType(TRANSPORT_WIFI);
@@ -8903,4 +8919,151 @@
);
}
}
+
+ private class QosCallbackMockHelper {
+ @NonNull public final QosFilter mFilter;
+ @NonNull public final IQosCallback mCallback;
+ @NonNull public final TestNetworkAgentWrapper mAgentWrapper;
+ @NonNull private final List<IQosCallback> mCallbacks = new ArrayList();
+
+ QosCallbackMockHelper() throws Exception {
+ Log.d(TAG, "QosCallbackMockHelper: ");
+ mFilter = mock(QosFilter.class);
+
+ // Ensure the network is disconnected before anything else occurs
+ assertNull(mCellNetworkAgent);
+
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+
+ verifyActiveNetwork(TRANSPORT_CELLULAR);
+ waitForIdle();
+ final Network network = mCellNetworkAgent.getNetwork();
+
+ final Pair<IQosCallback, IBinder> pair = createQosCallback();
+ mCallback = pair.first;
+
+ when(mFilter.getNetwork()).thenReturn(network);
+ when(mFilter.validate()).thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
+ mAgentWrapper = mCellNetworkAgent;
+ }
+
+ void registerQosCallback(@NonNull final QosFilter filter,
+ @NonNull final IQosCallback callback) {
+ mCallbacks.add(callback);
+ final NetworkAgentInfo nai =
+ mService.getNetworkAgentInfoForNetwork(filter.getNetwork());
+ mService.registerQosCallbackInternal(filter, callback, nai);
+ }
+
+ void tearDown() {
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ mService.unregisterQosCallback(mCallbacks.get(i));
+ }
+ }
+ }
+
+ private Pair<IQosCallback, IBinder> createQosCallback() {
+ final IQosCallback callback = mock(IQosCallback.class);
+ final IBinder binder = mock(Binder.class);
+ when(callback.asBinder()).thenReturn(binder);
+ when(binder.isBinderAlive()).thenReturn(true);
+ return new Pair<>(callback, binder);
+ }
+
+
+ @Test
+ public void testQosCallbackRegistration() throws Exception {
+ mQosCallbackMockHelper = new QosCallbackMockHelper();
+ final NetworkAgentWrapper wrapper = mQosCallbackMockHelper.mAgentWrapper;
+
+ when(mQosCallbackMockHelper.mFilter.validate())
+ .thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
+ mQosCallbackMockHelper.registerQosCallback(
+ mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
+
+ final NetworkAgentWrapper.CallbackType.OnQosCallbackRegister cbRegister1 =
+ (NetworkAgentWrapper.CallbackType.OnQosCallbackRegister)
+ wrapper.getCallbackHistory().poll(1000, x -> true);
+ assertNotNull(cbRegister1);
+
+ final int registerCallbackId = cbRegister1.mQosCallbackId;
+ mService.unregisterQosCallback(mQosCallbackMockHelper.mCallback);
+ final NetworkAgentWrapper.CallbackType.OnQosCallbackUnregister cbUnregister;
+ cbUnregister = (NetworkAgentWrapper.CallbackType.OnQosCallbackUnregister)
+ wrapper.getCallbackHistory().poll(1000, x -> true);
+ assertNotNull(cbUnregister);
+ assertEquals(registerCallbackId, cbUnregister.mQosCallbackId);
+ assertNull(wrapper.getCallbackHistory().poll(200, x -> true));
+ }
+
+ @Test
+ public void testQosCallbackNoRegistrationOnValidationError() throws Exception {
+ mQosCallbackMockHelper = new QosCallbackMockHelper();
+
+ when(mQosCallbackMockHelper.mFilter.validate())
+ .thenReturn(QosCallbackException.EX_TYPE_FILTER_NETWORK_RELEASED);
+ mQosCallbackMockHelper.registerQosCallback(
+ mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
+ waitForIdle();
+ verify(mQosCallbackMockHelper.mCallback)
+ .onError(eq(QosCallbackException.EX_TYPE_FILTER_NETWORK_RELEASED));
+ }
+
+ @Test
+ public void testQosCallbackAvailableAndLost() throws Exception {
+ mQosCallbackMockHelper = new QosCallbackMockHelper();
+ final int sessionId = 10;
+ final int qosCallbackId = 1;
+
+ when(mQosCallbackMockHelper.mFilter.validate())
+ .thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
+ mQosCallbackMockHelper.registerQosCallback(
+ mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
+ waitForIdle();
+
+ final EpsBearerQosSessionAttributes attributes = new EpsBearerQosSessionAttributes(
+ 1, 2, 3, 4, 5, new ArrayList<>());
+ mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
+ .sendQosSessionAvailable(qosCallbackId, sessionId, attributes);
+ waitForIdle();
+
+ verify(mQosCallbackMockHelper.mCallback).onQosEpsBearerSessionAvailable(argThat(session ->
+ session.getSessionId() == sessionId
+ && session.getSessionType() == QosSession.TYPE_EPS_BEARER), eq(attributes));
+
+ mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
+ .sendQosSessionLost(qosCallbackId, sessionId);
+ waitForIdle();
+ verify(mQosCallbackMockHelper.mCallback).onQosSessionLost(argThat(session ->
+ session.getSessionId() == sessionId
+ && session.getSessionType() == QosSession.TYPE_EPS_BEARER));
+ }
+
+ @Test
+ public void testQosCallbackTooManyRequests() throws Exception {
+ mQosCallbackMockHelper = new QosCallbackMockHelper();
+
+ when(mQosCallbackMockHelper.mFilter.validate())
+ .thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
+ for (int i = 0; i < 100; i++) {
+ final Pair<IQosCallback, IBinder> pair = createQosCallback();
+
+ try {
+ mQosCallbackMockHelper.registerQosCallback(
+ mQosCallbackMockHelper.mFilter, pair.first);
+ } catch (ServiceSpecificException e) {
+ assertEquals(e.errorCode, ConnectivityManager.Errors.TOO_MANY_REQUESTS);
+ if (i < 50) {
+ fail("TOO_MANY_REQUESTS thrown too early, the count is " + i);
+ }
+
+ // As long as there is at least 50 requests, it is safe to assume it works.
+ // Note: The count isn't being tested precisely against 100 because the counter
+ // is shared with request network.
+ return;
+ }
+ }
+ fail("TOO_MANY_REQUESTS never thrown");
+ }
}
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 4d151af..52cb836 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -78,6 +78,7 @@
@Mock Context mCtx;
@Mock NetworkNotificationManager mNotifier;
@Mock Resources mResources;
+ @Mock QosCallbackTracker mQosCallbackTracker;
@Before
public void setUp() {
@@ -358,7 +359,7 @@
NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info,
new LinkProperties(), caps, 50, mCtx, null, new NetworkAgentConfig() /* config */,
mConnService, mNetd, mDnsResolver, mNMS, NetworkProvider.ID_NONE,
- Binder.getCallingUid());
+ Binder.getCallingUid(), mQosCallbackTracker);
nai.everValidated = true;
return nai;
}
diff --git a/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java b/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
index 25bd7c0..1102624 100644
--- a/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
+++ b/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
@@ -29,7 +29,6 @@
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -197,6 +196,11 @@
}
@Override
+ public void sendStickyBroadcast(Intent intent, Bundle options) {
+ sendBroadcast(intent);
+ }
+
+ @Override
public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
sendBroadcast(intent);
}
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index 696110f..29cfdb6f 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -23,10 +23,15 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.argThat;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -35,8 +40,10 @@
import android.app.AppOpsManager;
import android.content.Context;
import android.net.ConnectivityManager;
+import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
import android.net.vcn.VcnConfig;
import android.net.vcn.VcnConfigTest;
+import android.os.IBinder;
import android.os.ParcelUuid;
import android.os.PersistableBundle;
import android.os.Process;
@@ -126,6 +133,10 @@
private final VcnManagementService mVcnMgmtSvc;
+ private final IVcnUnderlyingNetworkPolicyListener mMockPolicyListener =
+ mock(IVcnUnderlyingNetworkPolicyListener.class);
+ private final IBinder mMockIBinder = mock(IBinder.class);
+
public VcnManagementServiceTest() throws Exception {
setupSystemService(mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
setupSystemService(mTelMgr, Context.TELEPHONY_SERVICE, TelephonyManager.class);
@@ -169,6 +180,8 @@
setupMockedCarrierPrivilege(true);
mVcnMgmtSvc = new VcnManagementService(mMockContext, mMockDeps);
+ doReturn(mMockIBinder).when(mMockPolicyListener).asBinder();
+
// Make sure the profiles are loaded.
mTestLooper.dispatchAll();
}
@@ -438,4 +451,40 @@
mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2);
verify(vcnInstance).teardownAsynchronously();
}
+
+ @Test
+ public void testAddVcnUnderlyingNetworkPolicyListener() throws Exception {
+ doNothing()
+ .when(mMockContext)
+ .enforceCallingPermission(eq(android.Manifest.permission.NETWORK_FACTORY), any());
+
+ mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+ verify(mMockIBinder).linkToDeath(any(), anyInt());
+ }
+
+ @Test(expected = SecurityException.class)
+ public void testAddVcnUnderlyingNetworkPolicyListenerInvalidPermission() {
+ doThrow(new SecurityException())
+ .when(mMockContext)
+ .enforceCallingPermission(eq(android.Manifest.permission.NETWORK_FACTORY), any());
+
+ mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+ }
+
+ @Test
+ public void testRemoveVcnUnderlyingNetworkPolicyListener() {
+ // verify listener added
+ doNothing()
+ .when(mMockContext)
+ .enforceCallingPermission(eq(android.Manifest.permission.NETWORK_FACTORY), any());
+ mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+ mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+ }
+
+ @Test
+ public void testRemoveVcnUnderlyingNetworkPolicyListenerNeverRegistered() {
+ mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+ }
}