diff options
295 files changed, 6268 insertions, 3395 deletions
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchEmail.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchEmail.java index 5f2fabe52929..beb9ad3d27ea 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchEmail.java +++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchEmail.java @@ -27,8 +27,6 @@ import android.app.appsearch.AppSearchSchema.PropertyConfig; * * <p>This class is a higher level implement of {@link GenericDocument}. * - * <p>This class will eventually migrate to Jetpack, where it will become public API. - * * @hide */ @@ -99,10 +97,9 @@ public class AppSearchEmail extends GenericDocument { } /** - * Get the from address of {@link AppSearchEmail}. + * Gets the from address of {@link AppSearchEmail}. * - * @return Returns the subject of {@link AppSearchEmail} or {@code null} if it's not been set - * yet. + * @return The subject of {@link AppSearchEmail} or {@code null} if it's not been set yet. */ @Nullable public String getFrom() { @@ -110,10 +107,10 @@ public class AppSearchEmail extends GenericDocument { } /** - * Get the destination addresses of {@link AppSearchEmail}. + * Gets the destination addresses of {@link AppSearchEmail}. * - * @return Returns the destination addresses of {@link AppSearchEmail} or {@code null} if it's - * not been set yet. + * @return The destination addresses of {@link AppSearchEmail} or {@code null} if it's not + * been set yet. */ @Nullable public String[] getTo() { @@ -121,10 +118,9 @@ public class AppSearchEmail extends GenericDocument { } /** - * Get the CC list of {@link AppSearchEmail}. + * Gets the CC list of {@link AppSearchEmail}. * - * @return Returns the CC list of {@link AppSearchEmail} or {@code null} if it's not been set - * yet. + * @return The CC list of {@link AppSearchEmail} or {@code null} if it's not been set yet. */ @Nullable public String[] getCc() { @@ -132,10 +128,9 @@ public class AppSearchEmail extends GenericDocument { } /** - * Get the BCC list of {@link AppSearchEmail}. + * Gets the BCC list of {@link AppSearchEmail}. * - * @return Returns the BCC list of {@link AppSearchEmail} or {@code null} if it's not been set - * yet. + * @return The BCC list of {@link AppSearchEmail} or {@code null} if it's not been set yet. */ @Nullable public String[] getBcc() { @@ -143,10 +138,9 @@ public class AppSearchEmail extends GenericDocument { } /** - * Get the subject of {@link AppSearchEmail}. + * Gets the subject of {@link AppSearchEmail}. * - * @return Returns the value subject of {@link AppSearchEmail} or {@code null} if it's not been - * set yet. + * @return The value subject of {@link AppSearchEmail} or {@code null} if it's not been set yet. */ @Nullable public String getSubject() { @@ -154,9 +148,9 @@ public class AppSearchEmail extends GenericDocument { } /** - * Get the body of {@link AppSearchEmail}. + * Gets the body of {@link AppSearchEmail}. * - * @return Returns the body of {@link AppSearchEmail} or {@code null} if it's not been set yet. + * @return The body of {@link AppSearchEmail} or {@code null} if it's not been set yet. */ @Nullable public String getBody() { @@ -169,7 +163,8 @@ public class AppSearchEmail extends GenericDocument { public static class Builder extends GenericDocument.Builder<AppSearchEmail.Builder> { /** - * Create a new {@link AppSearchEmail.Builder} + * Creates a new {@link AppSearchEmail.Builder} + * * @param uri The Uri of the Email. */ public Builder(@NonNull String uri) { @@ -177,56 +172,56 @@ public class AppSearchEmail extends GenericDocument { } /** - * Set the from address of {@link AppSearchEmail} + * Sets the from address of {@link AppSearchEmail} */ @NonNull public AppSearchEmail.Builder setFrom(@NonNull String from) { - setProperty(KEY_FROM, from); + setPropertyString(KEY_FROM, from); return this; } /** - * Set the destination address of {@link AppSearchEmail} + * Sets the destination address of {@link AppSearchEmail} */ @NonNull public AppSearchEmail.Builder setTo(@NonNull String... to) { - setProperty(KEY_TO, to); + setPropertyString(KEY_TO, to); return this; } /** - * Set the CC list of {@link AppSearchEmail} + * Sets the CC list of {@link AppSearchEmail} */ @NonNull public AppSearchEmail.Builder setCc(@NonNull String... cc) { - setProperty(KEY_CC, cc); + setPropertyString(KEY_CC, cc); return this; } /** - * Set the BCC list of {@link AppSearchEmail} + * Sets the BCC list of {@link AppSearchEmail} */ @NonNull public AppSearchEmail.Builder setBcc(@NonNull String... bcc) { - setProperty(KEY_BCC, bcc); + setPropertyString(KEY_BCC, bcc); return this; } /** - * Set the subject of {@link AppSearchEmail} + * Sets the subject of {@link AppSearchEmail} */ @NonNull public AppSearchEmail.Builder setSubject(@NonNull String subject) { - setProperty(KEY_SUBJECT, subject); + setPropertyString(KEY_SUBJECT, subject); return this; } /** - * Set the body of {@link AppSearchEmail} + * Sets the body of {@link AppSearchEmail} */ @NonNull public AppSearchEmail.Builder setBody(@NonNull String body) { - setProperty(KEY_BODY, body); + setPropertyString(KEY_BODY, body); return this; } diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSchema.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSchema.java index 90e4df68f734..3933726d6729 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSchema.java +++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSchema.java @@ -16,10 +16,12 @@ package android.app.appsearch; +import android.annotation.SuppressLint; import android.os.Bundle; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.appsearch.exceptions.IllegalSchemaException; import android.util.ArraySet; @@ -28,6 +30,8 @@ import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.Set; /** @@ -39,13 +43,8 @@ import java.util.Set; * @hide */ public final class AppSearchSchema { - /** @hide */ - - public static final String SCHEMA_TYPE_FIELD = "schemaType"; - - /** @hide */ - - public static final String PROPERTIES_FIELD = "properties"; + private static final String SCHEMA_TYPE_FIELD = "schemaType"; + private static final String PROPERTIES_FIELD = "properties"; private final Bundle mBundle; @@ -71,10 +70,35 @@ public final class AppSearchSchema { return mBundle.toString(); } + /** Returns the name of this schema type, e.g. Email. */ + @NonNull + public String getSchemaTypeName() { + return mBundle.getString(SCHEMA_TYPE_FIELD, ""); + } + + /** + * Returns the list of {@link PropertyConfig}s that are part of this schema. + * + * <p>This method creates a new list when called. + */ + @NonNull + public List<PropertyConfig> getProperties() { + ArrayList<Bundle> propertyBundles = + mBundle.getParcelableArrayList(AppSearchSchema.PROPERTIES_FIELD); + if (propertyBundles.isEmpty()) { + return Collections.emptyList(); + } + List<PropertyConfig> ret = new ArrayList<>(propertyBundles.size()); + for (int i = 0; i < propertyBundles.size(); i++) { + ret.add(new PropertyConfig(propertyBundles.get(i))); + } + return ret; + } + /** Builder for {@link AppSearchSchema objects}. */ public static final class Builder { private final String mTypeName; - private final ArrayList<Bundle> mProperties = new ArrayList<>(); + private final ArrayList<Bundle> mPropertyBundles = new ArrayList<>(); private final Set<String> mPropertyNames = new ArraySet<>(); private boolean mBuilt = false; @@ -85,15 +109,19 @@ public final class AppSearchSchema { } /** Adds a property to the given type. */ + // TODO(b/171360120): MissingGetterMatchingBuilder expects a method called getPropertys, but + // we provide the (correct) method getProperties. Once the bug referenced in this TODO is + // fixed, remove this SuppressLint. + @SuppressLint("MissingGetterMatchingBuilder") @NonNull public AppSearchSchema.Builder addProperty(@NonNull PropertyConfig propertyConfig) { Preconditions.checkState(!mBuilt, "Builder has already been used"); Preconditions.checkNotNull(propertyConfig); - if (!mPropertyNames.add(propertyConfig.mName)) { - throw new IllegalSchemaException( - "Property defined more than once: " + propertyConfig.mName); + String name = propertyConfig.getName(); + if (!mPropertyNames.add(name)) { + throw new IllegalSchemaException("Property defined more than once: " + name); } - mProperties.add(propertyConfig.mBundle); + mPropertyBundles.add(propertyConfig.mBundle); return this; } @@ -107,7 +135,7 @@ public final class AppSearchSchema { Preconditions.checkState(!mBuilt, "Builder has already been used"); Bundle bundle = new Bundle(); bundle.putString(AppSearchSchema.SCHEMA_TYPE_FIELD, mTypeName); - bundle.putParcelableArrayList(AppSearchSchema.PROPERTIES_FIELD, mProperties); + bundle.putParcelableArrayList(AppSearchSchema.PROPERTIES_FIELD, mPropertyBundles); mBuilt = true; return new AppSearchSchema(bundle); } @@ -120,29 +148,12 @@ public final class AppSearchSchema { * a property. */ public static final class PropertyConfig { - /** @hide */ - - public static final String NAME_FIELD = "name"; - - /** @hide */ - - public static final String DATA_TYPE_FIELD = "dataType"; - - /** @hide */ - - public static final String SCHEMA_TYPE_FIELD = "schemaType"; - - /** @hide */ - - public static final String CARDINALITY_FIELD = "cardinality"; - - /** @hide */ - - public static final String INDEXING_TYPE_FIELD = "indexingType"; - - /** @hide */ - - public static final String TOKENIZER_TYPE_FIELD = "tokenizerType"; + 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"; /** * Physical data-types of the contents of the property. @@ -259,11 +270,9 @@ public final class AppSearchSchema { /** Tokenization for plain text. */ public static final int TOKENIZER_TYPE_PLAIN = 1; - final String mName; final Bundle mBundle; - PropertyConfig(@NonNull String name, @NonNull Bundle bundle) { - mName = Preconditions.checkNotNull(name); + PropertyConfig(@NonNull Bundle bundle) { mBundle = Preconditions.checkNotNull(bundle); } @@ -272,6 +281,45 @@ public final class AppSearchSchema { 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); + } + + /** Returns how the property is indexed. */ + public @IndexingType int getIndexingType() { + return mBundle.getInt(INDEXING_TYPE_FIELD); + } + + /** Returns how this property is tokenized (split into words). */ + public @TokenizerType int getTokenizerType() { + return mBundle.getInt(TOKENIZER_TYPE_FIELD); + } + /** * Builder for {@link PropertyConfig}. * @@ -286,13 +334,11 @@ public final class AppSearchSchema { * is also required. */ public static final class Builder { - private final String mName; private final Bundle mBundle = new Bundle(); private boolean mBuilt = false; /** Creates a new {@link PropertyConfig.Builder}. */ public Builder(@NonNull String propertyName) { - mName = Preconditions.checkNotNull(propertyName); mBundle.putString(NAME_FIELD, propertyName); } @@ -386,7 +432,7 @@ public final class AppSearchSchema { throw new IllegalSchemaException("Missing field: cardinality"); } mBuilt = true; - return new PropertyConfig(mName, mBundle); + return new PropertyConfig(mBundle); } } } diff --git a/apex/appsearch/framework/java/android/app/appsearch/GenericDocument.java b/apex/appsearch/framework/java/android/app/appsearch/GenericDocument.java index 9fe2c67d00f2..48d3ac09d997 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/GenericDocument.java +++ b/apex/appsearch/framework/java/android/app/appsearch/GenericDocument.java @@ -30,6 +30,7 @@ import com.android.internal.util.Preconditions; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Set; /** @@ -65,20 +66,14 @@ public class GenericDocument { /** The default time-to-live in millisecond of a document, which is infinity. */ private static final long DEFAULT_TTL_MILLIS = 0L; - /** @hide */ - - public static final String PROPERTIES_FIELD = "properties"; - - /** @hide */ - - public static final String BYTE_ARRAY_FIELD = "byteArray"; - - static final String SCHEMA_TYPE_FIELD = "schemaType"; - static final String URI_FIELD = "uri"; - static final String SCORE_FIELD = "score"; - static final String TTL_MILLIS_FIELD = "ttlMillis"; - static final String CREATION_TIMESTAMP_MILLIS_FIELD = "creationTimestampMillis"; - static final String NAMESPACE_FIELD = "namespace"; + private static final String PROPERTIES_FIELD = "properties"; + private static final String BYTE_ARRAY_FIELD = "byteArray"; + private static final String SCHEMA_TYPE_FIELD = "schemaType"; + private static final String URI_FIELD = "uri"; + private static final String SCORE_FIELD = "score"; + private static final String TTL_MILLIS_FIELD = "ttlMillis"; + private static final String CREATION_TIMESTAMP_MILLIS_FIELD = "creationTimestampMillis"; + private static final String NAMESPACE_FIELD = "namespace"; /** * The maximum number of indexed properties a document can have. @@ -190,6 +185,12 @@ public class GenericDocument { return mBundle.getInt(SCORE_FIELD, DEFAULT_SCORE); } + /** Returns the names of all properties defined in this document. */ + @NonNull + public Set<String> getPropertyNames() { + return Collections.unmodifiableSet(mProperties.keySet()); + } + /** * Retrieves a {@link String} value by key. * @@ -437,8 +438,6 @@ public class GenericDocument { @Override public boolean equals(@Nullable Object other) { - // Check only proto's equality is sufficient here since all properties in - // mProperties are ordered by keys and stored in proto. if (this == other) { return true; } @@ -450,8 +449,8 @@ public class GenericDocument { } /** - * Deeply checks two bundle is equally or not. - * <p> Two bundle will be considered equally if they contains same content. + * Deeply checks two bundles are equally or not. + * <p> Two bundles will be considered equally if they contain same content. */ @SuppressWarnings("unchecked") private static boolean bundleEquals(Bundle one, Bundle two) { @@ -472,7 +471,7 @@ public class GenericDocument { return false; } else if (valueOne == null && (valueTwo != null || !two.containsKey(key))) { // If we call bundle.get(key) when the 'key' doesn't actually exist in the - // bundle, we'll get back a null. So make sure that both values are null and + // bundle, we'll get back a null. So make sure that both values are null and // both keys exist in the bundle. return false; } else if (valueOne instanceof boolean[]) { @@ -538,8 +537,8 @@ public class GenericDocument { /** * Calculates the hash code for a bundle. - * <p> The hash code is only effected by the content in the bundle. Bundles will get - * consistent hash code if they have same content. + * <p> The hash code is only effected by the contents in the bundle. Bundles will get + * consistent hash code if they have same contents. */ @SuppressWarnings("unchecked") private static int bundleHashCode(Bundle bundle) { @@ -648,8 +647,11 @@ public class GenericDocument { /** * The builder class for {@link GenericDocument}. * - * @param <BuilderType> Type of subclass who extend this. + * @param <BuilderType> Type of subclass who extends this. */ + // This builder is specifically designed to be extended by classes deriving from + // GenericDocument. + @SuppressLint("StaticFinalBuilder") public static class Builder<BuilderType extends Builder> { private final Bundle mProperties = new Bundle(); @@ -662,12 +664,11 @@ public class GenericDocument { * * @param uri The uri of {@link GenericDocument}. * @param schemaType The schema type of the {@link GenericDocument}. The passed-in - * {@code schemaType} must be defined using {@code AppSearchManager#setSchema} prior + * {@code schemaType} must be defined using {@link AppSearchSession#setSchema} prior * to inserting a document of this {@code schemaType} into the AppSearch index using - * {@code AppSearchManager#putDocuments}. Otherwise, the document will be - * rejected by {@code AppSearchManager#putDocuments}. + * {@link AppSearchSession#putDocuments}. Otherwise, the document will be + * rejected by {@link AppSearchSession#putDocuments}. */ - //TODO(b/157082794) Linkify AppSearchManager once that API is public. @SuppressWarnings("unchecked") public Builder(@NonNull String uri, @NonNull String schemaType) { Preconditions.checkNotNull(uri); @@ -685,9 +686,12 @@ public class GenericDocument { } /** - * Set the app-defined namespace this Document resides in. No special values are - * reserved or understood by the infrastructure. URIs are unique within a namespace. The - * number of namespaces per app should be kept small for efficiency reasons. + * Sets the app-defined namespace this Document resides in. No special values are + * reserved or understood by the infrastructure. + * + * <p>URIs are unique within a namespace. + * + * <p>The number of namespaces per app should be kept small for efficiency reasons. */ @NonNull public BuilderType setNamespace(@NonNull String namespace) { @@ -714,7 +718,7 @@ public class GenericDocument { } /** - * Set the creation timestamp in milliseconds of the {@link GenericDocument}. Should be + * Sets the creation timestamp of the {@link GenericDocument}, in milliseconds. Should be * set using a value obtained from the {@link System#currentTimeMillis()} time base. */ @NonNull @@ -726,7 +730,7 @@ public class GenericDocument { } /** - * Set the TTL (Time To Live) of the {@link GenericDocument}, in milliseconds. + * Sets the TTL (Time To Live) of the {@link GenericDocument}, in milliseconds. * * <p>After this many milliseconds since the {@link #setCreationTimestampMillis creation * timestamp}, the document is deleted. @@ -752,7 +756,7 @@ public class GenericDocument { * @param values The {@code String} values of the property. */ @NonNull - public BuilderType setProperty(@NonNull String key, @NonNull String... values) { + public BuilderType setPropertyString(@NonNull String key, @NonNull String... values) { Preconditions.checkState(!mBuilt, "Builder has already been used"); Preconditions.checkNotNull(key); Preconditions.checkNotNull(values); @@ -768,7 +772,7 @@ public class GenericDocument { * @param values The {@code boolean} values of the property. */ @NonNull - public BuilderType setProperty(@NonNull String key, @NonNull boolean... values) { + public BuilderType setPropertyBoolean(@NonNull String key, @NonNull boolean... values) { Preconditions.checkState(!mBuilt, "Builder has already been used"); Preconditions.checkNotNull(key); Preconditions.checkNotNull(values); @@ -784,7 +788,7 @@ public class GenericDocument { * @param values The {@code long} values of the property. */ @NonNull - public BuilderType setProperty(@NonNull String key, @NonNull long... values) { + public BuilderType setPropertyLong(@NonNull String key, @NonNull long... values) { Preconditions.checkState(!mBuilt, "Builder has already been used"); Preconditions.checkNotNull(key); Preconditions.checkNotNull(values); @@ -800,7 +804,7 @@ public class GenericDocument { * @param values The {@code double} values of the property. */ @NonNull - public BuilderType setProperty(@NonNull String key, @NonNull double... values) { + public BuilderType setPropertyDouble(@NonNull String key, @NonNull double... values) { Preconditions.checkState(!mBuilt, "Builder has already been used"); Preconditions.checkNotNull(key); Preconditions.checkNotNull(values); @@ -815,7 +819,7 @@ public class GenericDocument { * @param values The {@code byte[]} of the property. */ @NonNull - public BuilderType setProperty(@NonNull String key, @NonNull byte[]... values) { + public BuilderType setPropertyBytes(@NonNull String key, @NonNull byte[]... values) { Preconditions.checkState(!mBuilt, "Builder has already been used"); Preconditions.checkNotNull(key); Preconditions.checkNotNull(values); @@ -831,7 +835,8 @@ public class GenericDocument { * @param values The {@link GenericDocument} values of the property. */ @NonNull - public BuilderType setProperty(@NonNull String key, @NonNull GenericDocument... values) { + public BuilderType setPropertyDocument( + @NonNull String key, @NonNull GenericDocument... values) { Preconditions.checkState(!mBuilt, "Builder has already been used"); Preconditions.checkNotNull(key); Preconditions.checkNotNull(values); diff --git a/apex/appsearch/framework/java/android/app/appsearch/GetByUriRequest.java b/apex/appsearch/framework/java/android/app/appsearch/GetByUriRequest.java index 3c0e746f92ab..e1e0eda7558c 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/GetByUriRequest.java +++ b/apex/appsearch/framework/java/android/app/appsearch/GetByUriRequest.java @@ -17,12 +17,12 @@ package android.app.appsearch; import android.annotation.NonNull; - import android.util.ArraySet; import com.android.internal.util.Preconditions; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Set; /** @@ -40,18 +40,16 @@ public final class GetByUriRequest { mUris = uris; } - /** @hide */ - + /** Returns the namespace to get documents from. */ @NonNull public String getNamespace() { return mNamespace; } - /** @hide */ - + /** Returns the URIs to get from the namespace. */ @NonNull public Set<String> getUris() { - return mUris; + return Collections.unmodifiableSet(mUris); } /** Builder for {@link GetByUriRequest} objects. */ @@ -75,14 +73,14 @@ public final class GetByUriRequest { /** Adds one or more URIs to the request. */ @NonNull - public Builder addUris(@NonNull String... uris) { + public Builder addUri(@NonNull String... uris) { Preconditions.checkNotNull(uris); - return addUris(Arrays.asList(uris)); + return addUri(Arrays.asList(uris)); } /** Adds one or more URIs to the request. */ @NonNull - public Builder addUris(@NonNull Collection<String> uris) { + public Builder addUri(@NonNull Collection<String> uris) { Preconditions.checkState(!mBuilt, "Builder has already been used"); Preconditions.checkNotNull(uris); mUris.addAll(uris); diff --git a/apex/appsearch/framework/java/android/app/appsearch/PutDocumentsRequest.java b/apex/appsearch/framework/java/android/app/appsearch/PutDocumentsRequest.java index 7e97542c6f02..1f90bc184f6f 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/PutDocumentsRequest.java +++ b/apex/appsearch/framework/java/android/app/appsearch/PutDocumentsRequest.java @@ -16,13 +16,16 @@ package android.app.appsearch; -import android.annotation.NonNull; +import android.annotation.SuppressLint; +import android.annotation.NonNull; +import android.app.appsearch.exceptions.AppSearchException; 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; /** @@ -38,11 +41,10 @@ public final class PutDocumentsRequest { mDocuments = documents; } - /** @hide */ - + /** Returns the documents that are part of this request. */ @NonNull public List<GenericDocument> getDocuments() { - return mDocuments; + return Collections.unmodifiableList(mDocuments); } /** Builder for {@link PutDocumentsRequest} objects. */ @@ -51,6 +53,7 @@ public final class PutDocumentsRequest { private boolean mBuilt = false; /** Adds one or more documents to the request. */ + @SuppressLint("MissingGetterMatchingBuilder") // Merged list available from getDocuments() @NonNull public Builder addGenericDocument(@NonNull GenericDocument... documents) { Preconditions.checkNotNull(documents); @@ -58,6 +61,7 @@ public final class PutDocumentsRequest { } /** Adds one or more documents to the request. */ + @SuppressLint("MissingGetterMatchingBuilder") // Merged list available from getDocuments() @NonNull public Builder addGenericDocument(@NonNull Collection<GenericDocument> documents) { Preconditions.checkState(!mBuilt, "Builder has already been used"); diff --git a/apex/appsearch/framework/java/android/app/appsearch/RemoveByUriRequest.java b/apex/appsearch/framework/java/android/app/appsearch/RemoveByUriRequest.java index a047041a3082..486857fba1de 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/RemoveByUriRequest.java +++ b/apex/appsearch/framework/java/android/app/appsearch/RemoveByUriRequest.java @@ -17,12 +17,12 @@ package android.app.appsearch; import android.annotation.NonNull; - import android.util.ArraySet; import com.android.internal.util.Preconditions; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Set; /** @@ -40,18 +40,16 @@ public final class RemoveByUriRequest { mUris = uris; } - /** @hide */ - + /** Returns the namespace to remove documents from. */ @NonNull public String getNamespace() { return mNamespace; } - /** @hide */ - + /** Returns the URIs to remove from the namespace. */ @NonNull public Set<String> getUris() { - return mUris; + return Collections.unmodifiableSet(mUris); } /** Builder for {@link RemoveByUriRequest} objects. */ @@ -75,14 +73,14 @@ public final class RemoveByUriRequest { /** Adds one or more URIs to the request. */ @NonNull - public Builder addUris(@NonNull String... uris) { + public Builder addUri(@NonNull String... uris) { Preconditions.checkNotNull(uris); - return addUris(Arrays.asList(uris)); + return addUri(Arrays.asList(uris)); } /** Adds one or more URIs to the request. */ @NonNull - public Builder addUris(@NonNull Collection<String> uris) { + public Builder addUri(@NonNull Collection<String> uris) { Preconditions.checkState(!mBuilt, "Builder has already been used"); Preconditions.checkNotNull(uris); mUris.addAll(uris); diff --git a/apex/appsearch/framework/java/android/app/appsearch/SearchResult.java b/apex/appsearch/framework/java/android/app/appsearch/SearchResult.java index 758280bbc322..99cb2f16ca4d 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/SearchResult.java +++ b/apex/appsearch/framework/java/android/app/appsearch/SearchResult.java @@ -49,19 +49,22 @@ public final class SearchResult { @NonNull private final Bundle mDocumentBundle; + /** Cache of the inflated document. Comes from inflating mDocumentBundle at first use. */ @Nullable private GenericDocument mDocument; - @Nullable - private final List<Bundle> mMatchBundles; - /** - * Contains a list of Snippets that matched the request. Only populated when requested in - * both {@link SearchSpec.Builder#setSnippetCount(int)} - * and {@link SearchSpec.Builder#setSnippetCountPerProperty(int)}. + * Contains a list of MatchInfo bundles that matched the request. + * + * Only populated when requested in both {@link SearchSpec.Builder#setSnippetCount} and + * {@link SearchSpec.Builder#setSnippetCountPerProperty}. * * @see #getMatches() */ + @NonNull + private final List<Bundle> mMatchBundles; + + /** Cache of the inflated matches. Comes from inflating mMatchBundles at first use. */ @Nullable private List<MatchInfo> mMatches; @@ -70,7 +73,7 @@ public final class SearchResult { public SearchResult(@NonNull Bundle bundle) { mBundle = Preconditions.checkNotNull(bundle); mDocumentBundle = Preconditions.checkNotNull(bundle.getBundle(DOCUMENT_FIELD)); - mMatchBundles = bundle.getParcelableArrayList(MATCHES_FIELD); + mMatchBundles = Preconditions.checkNotNull(bundle.getParcelableArrayList(MATCHES_FIELD)); } /** @hide */ @@ -93,19 +96,16 @@ public final class SearchResult { } /** - * Contains a list of Snippets that matched the request. Only populated when requested in - * both {@link SearchSpec.Builder#setSnippetCount(int)} - * and {@link SearchSpec.Builder#setSnippetCountPerProperty(int)}. + * Contains a list of Snippets that matched the request. * - * @return List of matches based on {@link SearchSpec}, if snippeting is disabled and this - * method is called it will return {@code null}. Users can also restrict snippet population - * using {@link SearchSpec.Builder#setSnippetCount} and - * {@link SearchSpec.Builder#setSnippetCountPerProperty(int)}, for all results after that - * value this method will return {@code null}. + * @return List of matches based on {@link SearchSpec}. If snippeting is disabled using + * {@link SearchSpec.Builder#setSnippetCount} or + * {@link SearchSpec.Builder#setSnippetCountPerProperty}, for all results after that + * value, this method returns an empty list. */ - @Nullable + @NonNull public List<MatchInfo> getMatches() { - if (mMatchBundles != null && mMatches == null) { + if (mMatches == null) { mMatches = new ArrayList<>(mMatchBundles.size()); for (int i = 0; i < mMatchBundles.size(); i++) { MatchInfo matchInfo = new MatchInfo(getDocument(), mMatchBundles.get(i)); @@ -119,8 +119,8 @@ public final class SearchResult { * Snippet: It refers to a substring of text from the content of document that is returned as a * part of search result. * This class represents a match objects for any Snippets that might be present in - * {@link SearchResults} from query. Using this class user can get the full text, exact matches - * and Snippets of document content for a given match. + * {@link SearchResults} from query. Using this class + * user can get the full text, exact matches and Snippets of document content for a given match. * * <p>Class Example 1: * A document contains following text in property subject: diff --git a/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java b/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java index c8719059fa8c..15acf103f2e6 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java +++ b/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java @@ -16,16 +16,23 @@ package android.app.appsearch; +import android.annotation.SuppressLint; import android.os.Bundle; import android.annotation.IntDef; import android.annotation.NonNull; +import android.app.appsearch.exceptions.AppSearchException; import android.app.appsearch.exceptions.IllegalSearchSpecException; import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; /** * This class represents the specification logic for AppSearch. It can be used to set the type of @@ -34,69 +41,26 @@ import java.lang.annotation.RetentionPolicy; */ // TODO(sidchhabra) : AddResultSpec fields for Snippets etc. public final class SearchSpec { - /** @hide */ - - public static final String TERM_MATCH_TYPE_FIELD = "termMatchType"; - - /** @hide */ - - public static final String SCHEMA_TYPES_FIELD = "schemaType"; - - /** @hide */ - - public static final String NAMESPACE_FIELD = "namespace"; - - /** @hide */ - - public static final String NUM_PER_PAGE_FIELD = "numPerPage"; - - /** @hide */ - - public static final String RANKING_STRATEGY_FIELD = "rankingStrategy"; - - /** @hide */ - - public static final String ORDER_FIELD = "order"; - - /** @hide */ - - public static final String SNIPPET_COUNT_FIELD = "snippetCount"; - - /** @hide */ - - public static final String SNIPPET_COUNT_PER_PROPERTY_FIELD = "snippetCountPerProperty"; - - /** @hide */ - - public static final String MAX_SNIPPET_FIELD = "maxSnippet"; + static final String TERM_MATCH_TYPE_FIELD = "termMatchType"; + static final String SCHEMA_TYPE_FIELD = "schemaType"; + static final String NAMESPACE_FIELD = "namespace"; + static final String NUM_PER_PAGE_FIELD = "numPerPage"; + static final String RANKING_STRATEGY_FIELD = "rankingStrategy"; + static final String ORDER_FIELD = "order"; + static final String SNIPPET_COUNT_FIELD = "snippetCount"; + static final String SNIPPET_COUNT_PER_PROPERTY_FIELD = "snippetCountPerProperty"; + static final String MAX_SNIPPET_FIELD = "maxSnippet"; /** @hide */ public static final int DEFAULT_NUM_PER_PAGE = 10; + // TODO(b/170371356): In framework, we may want these limits might be flag controlled. private static final int MAX_NUM_PER_PAGE = 10_000; private static final int MAX_SNIPPET_COUNT = 10_000; private static final int MAX_SNIPPET_PER_PROPERTY_COUNT = 10_000; private static final int MAX_SNIPPET_SIZE_LIMIT = 10_000; - private final Bundle mBundle; - - /** @hide */ - - public SearchSpec(@NonNull Bundle bundle) { - Preconditions.checkNotNull(bundle); - mBundle = bundle; - } - - /** - * Returns the {@link Bundle} populated by this builder. - * @hide - */ - @NonNull - public Bundle getBundle() { - return mBundle; - } - /** * Term Match Type for the query. * @hide @@ -108,7 +72,7 @@ public final class SearchSpec { TERM_MATCH_PREFIX }) @Retention(RetentionPolicy.SOURCE) - public @interface TermMatchCode {} + public @interface TermMatch {} /** * Query terms will only match exact tokens in the index. @@ -126,14 +90,14 @@ public final class SearchSpec { * @hide */ // NOTE: The integer values of these constants must match the proto enum constants in - // {@link ScoringSpecProto.RankingStrategy.Code } + // {@link ScoringSpecProto.RankingStrategy.Code} @IntDef(value = { RANKING_STRATEGY_NONE, RANKING_STRATEGY_DOCUMENT_SCORE, RANKING_STRATEGY_CREATION_TIMESTAMP }) @Retention(RetentionPolicy.SOURCE) - public @interface RankingStrategyCode {} + public @interface RankingStrategy {} /** No Ranking, results are returned in arbitrary order.*/ public static final int RANKING_STRATEGY_NONE = 0; @@ -147,23 +111,109 @@ public final class SearchSpec { * @hide */ // NOTE: The integer values of these constants must match the proto enum constants in - // {@link ScoringSpecProto.Order.Code } + // {@link ScoringSpecProto.Order.Code} @IntDef(value = { ORDER_DESCENDING, ORDER_ASCENDING }) @Retention(RetentionPolicy.SOURCE) - public @interface OrderCode {} + public @interface Order {} /** Search results will be returned in a descending order. */ public static final int ORDER_DESCENDING = 0; /** Search results will be returned in an ascending order. */ public static final int ORDER_ASCENDING = 1; + private final Bundle mBundle; + + /** @hide */ + + public SearchSpec(@NonNull Bundle bundle) { + Preconditions.checkNotNull(bundle); + mBundle = bundle; + } + + /** + * Returns the {@link Bundle} populated by this builder. + * @hide + */ + + @NonNull + public Bundle getBundle() { + return mBundle; + } + + /** Returns how the query terms should match terms in the index. */ + public @TermMatch int getTermMatch() { + return mBundle.getInt(TERM_MATCH_TYPE_FIELD, -1); + } + + /** + * Returns the list of schema types to search for. + * + * <p>If empty, the query will search over all schema types. + */ + @NonNull + public List<String> getSchemas() { + List<String> schemas = mBundle.getStringArrayList(SCHEMA_TYPE_FIELD); + if (schemas == null) { + return Collections.emptyList(); + } + return Collections.unmodifiableList(schemas); + } + + /** + * Returns the list of namespaces to search for. + * + * <p>If empty, the query will search over all namespaces. + */ + @NonNull + public List<String> getNamespaces() { + List<String> namespaces = mBundle.getStringArrayList(NAMESPACE_FIELD); + if (namespaces == null) { + return Collections.emptyList(); + } + return Collections.unmodifiableList(namespaces); + } + + /** Returns the number of results per page in the returned object. */ + public int getNumPerPage() { + return mBundle.getInt(NUM_PER_PAGE_FIELD, DEFAULT_NUM_PER_PAGE); + } + + /** Returns the ranking strategy. */ + public @RankingStrategy int getRankingStrategy() { + return mBundle.getInt(RANKING_STRATEGY_FIELD); + } + + /** Returns the order of returned search results (descending or ascending). */ + public @Order int getOrder() { + return mBundle.getInt(ORDER_FIELD); + } + + /** Returns how many documents to generate snippets for. */ + public int getSnippetCount() { + return mBundle.getInt(SNIPPET_COUNT_FIELD); + } + + /** + * Returns how many matches for each property of a matching document to generate snippets for. + */ + public int getSnippetCountPerProperty() { + return mBundle.getInt(SNIPPET_COUNT_PER_PROPERTY_FIELD); + } + + /** Returns the maximum size of a snippet in characters. */ + public int getMaxSnippetSize() { + return mBundle.getInt(MAX_SNIPPET_FIELD); + } + /** Builder for {@link SearchSpec objects}. */ public static final class Builder { private final Bundle mBundle; + private final ArrayList<String> mSchemaTypes = new ArrayList<>(); + private final ArrayList<String> mNamespaces = new ArrayList<>(); private boolean mBuilt = false; /** Creates a new {@link SearchSpec.Builder}. */ @@ -176,7 +226,7 @@ public final class SearchSpec { * Indicates how the query terms should match {@code TermMatchCode} in the index. */ @NonNull - public Builder setTermMatch(@TermMatchCode int termMatchTypeCode) { + public Builder setTermMatch(@TermMatch int termMatchTypeCode) { Preconditions.checkState(!mBuilt, "Builder has already been used"); Preconditions.checkArgumentInRange(termMatchTypeCode, TERM_MATCH_EXACT_ONLY, TERM_MATCH_PREFIX, "Term match type"); @@ -187,13 +237,27 @@ public final class SearchSpec { /** * Adds a Schema type filter to {@link SearchSpec} Entry. Only search for documents that * have the specified schema types. + * * <p>If unset, the query will search over all schema types. */ @NonNull - public Builder setSchemaTypes(@NonNull String... schemaTypes) { + public Builder addSchema(@NonNull String... schemaTypes) { Preconditions.checkNotNull(schemaTypes); Preconditions.checkState(!mBuilt, "Builder has already been used"); - mBundle.putStringArray(SCHEMA_TYPES_FIELD, schemaTypes); + return addSchema(Arrays.asList(schemaTypes)); + } + + /** + * Adds a Schema type filter to {@link SearchSpec} Entry. Only search for documents that + * have the specified schema types. + * + * <p>If unset, the query will search over all schema types. + */ + @NonNull + public Builder addSchema(@NonNull Collection<String> schemaTypes) { + Preconditions.checkNotNull(schemaTypes); + Preconditions.checkState(!mBuilt, "Builder has already been used"); + mSchemaTypes.addAll(schemaTypes); return this; } @@ -203,10 +267,22 @@ public final class SearchSpec { * <p>If unset, the query will search over all namespaces. */ @NonNull - public Builder setNamespaces(@NonNull String... namespaces) { + public Builder addNamespace(@NonNull String... namespaces) { + Preconditions.checkNotNull(namespaces); + Preconditions.checkState(!mBuilt, "Builder has already been used"); + return addNamespace(Arrays.asList(namespaces)); + } + + /** + * Adds a namespace filter to {@link SearchSpec} Entry. Only search for documents that + * have the specified namespaces. + * <p>If unset, the query will search over all namespaces. + */ + @NonNull + public Builder addNamespace(@NonNull Collection<String> namespaces) { Preconditions.checkNotNull(namespaces); Preconditions.checkState(!mBuilt, "Builder has already been used"); - mBundle.putStringArray(NAMESPACE_FIELD, namespaces); + mNamespaces.addAll(namespaces); return this; } @@ -224,7 +300,7 @@ public final class SearchSpec { /** Sets ranking strategy for AppSearch results.*/ @NonNull - public Builder setRankingStrategy(@RankingStrategyCode int rankingStrategy) { + public Builder setRankingStrategy(@RankingStrategy int rankingStrategy) { Preconditions.checkState(!mBuilt, "Builder has already been used"); Preconditions.checkArgumentInRange(rankingStrategy, RANKING_STRATEGY_NONE, RANKING_STRATEGY_CREATION_TIMESTAMP, "Result ranking strategy"); @@ -238,7 +314,7 @@ public final class SearchSpec { * <p>This order field will be ignored if RankingStrategy = {@code RANKING_STRATEGY_NONE}. */ @NonNull - public Builder setOrder(@OrderCode int order) { + public Builder setOrder(@Order int order) { Preconditions.checkState(!mBuilt, "Builder has already been used"); Preconditions.checkArgumentInRange(order, ORDER_DESCENDING, ORDER_ASCENDING, "Result ranking order"); @@ -264,11 +340,12 @@ public final class SearchSpec { } /** - * Only the first {@code matchesCountPerProperty} matches for a every property of - * {@link GenericDocument} will contain snippet information. + * Sets {@code snippetCountPerProperty}. Only the first {@code snippetCountPerProperty} + * snippets for a every property of {@link GenericDocument} will contain snippet + * information. * - * <p>If set to 0, snippeting is disabled and {@link SearchResult#getMatches} will return - * {@code null} for that result. + * <p>If set to 0, snippeting is disabled and {@link SearchResult#getMatches} + * will return {@code null} for that result. * * <p>The value should be set in range[0, 10k]. */ @@ -286,10 +363,13 @@ public final class SearchSpec { * {@code maxSnippetSize/2} bytes before the middle of the matching token and end at * {@code maxSnippetSize/2} bytes after the middle of the matching token. It respects * token boundaries, therefore the returned window may be smaller than requested. + * * <p> Setting {@code maxSnippetSize} to 0 will disable windowing and an empty string will * be returned. If matches enabled is also set to false, then snippeting is disabled. + * * <p>Ex. {@code maxSnippetSize} = 16. "foo bar baz bat rat" with a query of "baz" will * return a window of "bar baz bat" which is only 11 bytes long. + * * <p>The value should be in range[0, 10k]. */ @NonNull @@ -312,6 +392,8 @@ public final class SearchSpec { if (!mBundle.containsKey(TERM_MATCH_TYPE_FIELD)) { throw new IllegalSearchSpecException("Missing termMatchType field."); } + mBundle.putStringArrayList(NAMESPACE_FIELD, mNamespaces); + mBundle.putStringArrayList(SCHEMA_TYPE_FIELD, mSchemaTypes); mBuilt = true; return new SearchSpec(mBundle); } diff --git a/apex/appsearch/framework/java/android/app/appsearch/SetSchemaRequest.java b/apex/appsearch/framework/java/android/app/appsearch/SetSchemaRequest.java index b2e9d469764d..f2c81564908c 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/SetSchemaRequest.java +++ b/apex/appsearch/framework/java/android/app/appsearch/SetSchemaRequest.java @@ -16,13 +16,17 @@ package android.app.appsearch; +import android.annotation.SuppressLint; + import android.annotation.NonNull; +import android.app.appsearch.exceptions.AppSearchException; 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.List; import java.util.Set; /** @@ -40,15 +44,13 @@ public final class SetSchemaRequest { mForceOverride = forceOverride; } - /** @hide */ - + /** Returns the schemas that are part of this request. */ @NonNull public Set<AppSearchSchema> getSchemas() { return mSchemas; } - /** @hide */ - + /** Returns whether this request will force the schema to be overridden. */ public boolean isForceOverride() { return mForceOverride; } diff --git a/apex/appsearch/framework/java/android/app/appsearch/exceptions/AppSearchException.java b/apex/appsearch/framework/java/android/app/appsearch/exceptions/AppSearchException.java index d490469be3d6..15d0992cd081 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/exceptions/AppSearchException.java +++ b/apex/appsearch/framework/java/android/app/appsearch/exceptions/AppSearchException.java @@ -54,6 +54,7 @@ public class AppSearchException extends Exception { mResultCode = resultCode; } + /** Returns the result code this exception was constructed with. */ public @AppSearchResult.ResultCode int getResultCode() { return mResultCode; } 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 7cd6ee24cb20..f2830e5b8e6d 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java @@ -33,11 +33,11 @@ import android.os.UserHandle; import com.android.internal.infra.AndroidFuture; import com.android.internal.util.Preconditions; import com.android.server.SystemService; -import com.android.server.appsearch.external.localbackend.AppSearchImpl; -import com.android.server.appsearch.external.localbackend.converter.GenericDocumentToProtoConverter; -import com.android.server.appsearch.external.localbackend.converter.SchemaToProtoConverter; -import com.android.server.appsearch.external.localbackend.converter.SearchResultToProtoConverter; -import com.android.server.appsearch.external.localbackend.converter.SearchSpecToProtoConverter; +import com.android.server.appsearch.external.localstorage.AppSearchImpl; +import com.android.server.appsearch.external.localstorage.converter.GenericDocumentToProtoConverter; +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.google.android.icing.proto.DocumentProto; import com.google.android.icing.proto.SchemaProto; @@ -46,6 +46,7 @@ import com.google.android.icing.proto.SearchResultProto; import com.google.android.icing.proto.SearchSpecProto; import java.io.IOException; +import java.util.ArrayList; import java.util.List; /** @@ -193,7 +194,12 @@ public class AppSearchManagerService extends SystemService { SearchSpecToProtoConverter.toResultSpecProto(searchSpec), SearchSpecToProtoConverter.toScoringSpecProto(searchSpec)); List<SearchResult> searchResultList = - SearchResultToProtoConverter.convert(searchResultProto); + new ArrayList<>(searchResultProto.getResultsCount()); + for (int i = 0; i < searchResultProto.getResultsCount(); i++) { + SearchResult result = SearchResultToProtoConverter.convertSearchResult( + searchResultProto.getResults(i)); + searchResultList.add(result); + } SearchResults searchResults = new SearchResults(searchResultList, searchResultProto.getNextPageToken()); callback.complete(AppSearchResult.newSuccessfulResult(searchResults)); 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 60f7005a7c0a..2871eb622f11 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java @@ -24,7 +24,7 @@ import android.os.Environment; import android.os.storage.StorageManager; import android.util.SparseArray; -import com.android.server.appsearch.external.localbackend.AppSearchImpl; +import com.android.server.appsearch.external.localstorage.AppSearchImpl; import java.io.File; diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localbackend/AppSearchImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java index 642378d992ac..b1a79f84714d 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/external/localbackend/AppSearchImpl.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.appsearch.external.localbackend; +package com.android.server.appsearch.external.localstorage; import android.util.Log; diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localbackend/converter/GenericDocumentToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverter.java index fdeb90dc9b0e..60684f09a202 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/external/localbackend/converter/GenericDocumentToProtoConverter.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverter.java @@ -14,9 +14,7 @@ * limitations under the License. */ -package com.android.server.appsearch.external.localbackend.converter; - -import android.os.Bundle; +package com.android.server.appsearch.external.localstorage.converter; import android.annotation.NonNull; @@ -43,7 +41,6 @@ public final class GenericDocumentToProtoConverter { @SuppressWarnings("unchecked") public static DocumentProto convert(@NonNull GenericDocument document) { Preconditions.checkNotNull(document); - Bundle properties = document.getBundle().getBundle(GenericDocument.PROPERTIES_FIELD); DocumentProto.Builder mProtoBuilder = DocumentProto.newBuilder(); mProtoBuilder.setUri(document.getUri()) .setSchema(document.getSchemaType()) @@ -51,42 +48,45 @@ public final class GenericDocumentToProtoConverter { .setScore(document.getScore()) .setTtlMs(document.getTtlMillis()) .setCreationTimestampMs(document.getCreationTimestampMillis()); - ArrayList<String> keys = new ArrayList<>(properties.keySet()); + ArrayList<String> keys = new ArrayList<>(document.getPropertyNames()); Collections.sort(keys); for (int i = 0; i < keys.size(); i++) { String name = keys.get(i); - Object values = properties.get(name); PropertyProto.Builder propertyProto = PropertyProto.newBuilder().setName(name); - if (values instanceof boolean[]) { - for (boolean value : (boolean[]) values) { - propertyProto.addBooleanValues(value); + String[] stringValues = document.getPropertyStringArray(name); + long[] longValues = document.getPropertyLongArray(name); + double[] doubleValues = document.getPropertyDoubleArray(name); + boolean[] booleanValues = document.getPropertyBooleanArray(name); + byte[][] bytesValues = document.getPropertyBytesArray(name); + GenericDocument[] documentValues = document.getPropertyDocumentArray(name); + if (stringValues != null) { + for (int j = 0; j < stringValues.length; j++) { + propertyProto.addStringValues(stringValues[j]); } - } else if (values instanceof long[]) { - for (long value : (long[]) values) { - propertyProto.addInt64Values(value); + } else if (longValues != null) { + for (int j = 0; j < longValues.length; j++) { + propertyProto.addInt64Values(longValues[j]); } - } else if (values instanceof double[]) { - for (double value : (double[]) values) { - propertyProto.addDoubleValues(value); + } else if (doubleValues != null) { + for (int j = 0; j < doubleValues.length; j++) { + propertyProto.addDoubleValues(doubleValues[j]); } - } else if (values instanceof String[]) { - for (String value : (String[]) values) { - propertyProto.addStringValues(value); + } else if (booleanValues != null) { + for (int j = 0; j < booleanValues.length; j++) { + propertyProto.addBooleanValues(booleanValues[j]); } - } else if (values instanceof ArrayList) { - for (Bundle bundle : (ArrayList<Bundle>) values) { - byte[] value = bundle.getByteArray(GenericDocument.BYTE_ARRAY_FIELD); - propertyProto.addBytesValues(ByteString.copyFrom(value)); + } else if (bytesValues != null) { + for (int j = 0; j < bytesValues.length; j++) { + propertyProto.addBytesValues(ByteString.copyFrom(bytesValues[j])); } - } else if (values instanceof Bundle[]) { - for (Bundle bundle : (Bundle[]) values) { - GenericDocument value = new GenericDocument(bundle); - propertyProto.addDocumentValues(convert(value)); + } else if (documentValues != null) { + for (int j = 0; j < documentValues.length; j++) { + DocumentProto proto = convert(documentValues[j]); + propertyProto.addDocumentValues(proto); } } else { throw new IllegalStateException( - "Property \"" + name + "\" has unsupported value type \"" - + values.getClass().getSimpleName() + "\""); + "Property \"" + name + "\" has unsupported value type"); } mProtoBuilder.addProperties(propertyProto); } @@ -107,42 +107,42 @@ public final class GenericDocumentToProtoConverter { for (int i = 0; i < proto.getPropertiesCount(); i++) { PropertyProto property = proto.getProperties(i); String name = property.getName(); - if (property.getBooleanValuesCount() > 0) { - boolean[] values = new boolean[property.getBooleanValuesCount()]; + if (property.getStringValuesCount() > 0) { + String[] values = new String[property.getStringValuesCount()]; for (int j = 0; j < values.length; j++) { - values[j] = property.getBooleanValues(j); + values[j] = property.getStringValues(j); } - documentBuilder.setProperty(name, values); + documentBuilder.setPropertyString(name, values); } else if (property.getInt64ValuesCount() > 0) { long[] values = new long[property.getInt64ValuesCount()]; for (int j = 0; j < values.length; j++) { values[j] = property.getInt64Values(j); } - documentBuilder.setProperty(name, values); + documentBuilder.setPropertyLong(name, values); } else if (property.getDoubleValuesCount() > 0) { double[] values = new double[property.getDoubleValuesCount()]; for (int j = 0; j < values.length; j++) { values[j] = property.getDoubleValues(j); } - documentBuilder.setProperty(name, values); - } else if (property.getStringValuesCount() > 0) { - String[] values = new String[property.getStringValuesCount()]; + documentBuilder.setPropertyDouble(name, values); + } else if (property.getBooleanValuesCount() > 0) { + boolean[] values = new boolean[property.getBooleanValuesCount()]; for (int j = 0; j < values.length; j++) { - values[j] = property.getStringValues(j); + values[j] = property.getBooleanValues(j); } - documentBuilder.setProperty(name, values); + documentBuilder.setPropertyBoolean(name, values); } else if (property.getBytesValuesCount() > 0) { byte[][] values = new byte[property.getBytesValuesCount()][]; for (int j = 0; j < values.length; j++) { values[j] = property.getBytesValues(j).toByteArray(); } - documentBuilder.setProperty(name, values); + documentBuilder.setPropertyBytes(name, values); } else if (property.getDocumentValuesCount() > 0) { GenericDocument[] values = new GenericDocument[property.getDocumentValuesCount()]; for (int j = 0; j < values.length; j++) { values[j] = convert(property.getDocumentValues(j)); } - documentBuilder.setProperty(name, values); + documentBuilder.setPropertyDocument(name, values); } else { throw new IllegalStateException("Unknown type of value: " + name); } diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localbackend/converter/SchemaToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverter.java index ca0d2ee970cb..403711f29544 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/external/localbackend/converter/SchemaToProtoConverter.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverter.java @@ -14,9 +14,7 @@ * limitations under the License. */ -package com.android.server.appsearch.external.localbackend.converter; - -import android.os.Bundle; +package com.android.server.appsearch.external.localstorage.converter; import android.annotation.NonNull; @@ -28,7 +26,7 @@ import com.google.android.icing.proto.PropertyConfigProto; import com.google.android.icing.proto.SchemaTypeConfigProto; import com.google.android.icing.proto.TermMatchType; -import java.util.ArrayList; +import java.util.List; /** * Translates an {@link AppSearchSchema} into a {@link SchemaTypeConfigProto}. @@ -45,31 +43,26 @@ public final class SchemaToProtoConverter { @NonNull public static SchemaTypeConfigProto convert(@NonNull AppSearchSchema schema) { Preconditions.checkNotNull(schema); - Bundle bundle = schema.getBundle(); SchemaTypeConfigProto.Builder protoBuilder = - SchemaTypeConfigProto.newBuilder() - .setSchemaType(bundle.getString(AppSearchSchema.SCHEMA_TYPE_FIELD, "")); - ArrayList<Bundle> properties = - bundle.getParcelableArrayList(AppSearchSchema.PROPERTIES_FIELD); - if (properties != null) { - for (int i = 0; i < properties.size(); i++) { - PropertyConfigProto propertyProto = convertProperty(properties.get(i)); - protoBuilder.addProperties(propertyProto); - } + SchemaTypeConfigProto.newBuilder().setSchemaType(schema.getSchemaTypeName()); + List<AppSearchSchema.PropertyConfig> properties = schema.getProperties(); + for (int i = 0; i < properties.size(); i++) { + PropertyConfigProto propertyProto = convertProperty(properties.get(i)); + protoBuilder.addProperties(propertyProto); } return protoBuilder.build(); } @NonNull - private static PropertyConfigProto convertProperty(@NonNull Bundle bundle) { - Preconditions.checkNotNull(bundle); + private static PropertyConfigProto convertProperty( + @NonNull AppSearchSchema.PropertyConfig property) { + Preconditions.checkNotNull(property); PropertyConfigProto.Builder propertyConfigProto = PropertyConfigProto.newBuilder() - .setPropertyName(bundle.getString(AppSearchSchema.PropertyConfig.NAME_FIELD, "")); + .setPropertyName(property.getName()); IndexingConfig.Builder indexingConfig = IndexingConfig.newBuilder(); // Set dataType - @AppSearchSchema.PropertyConfig.DataType int dataType = - bundle.getInt(AppSearchSchema.PropertyConfig.DATA_TYPE_FIELD); + @AppSearchSchema.PropertyConfig.DataType int dataType = property.getDataType(); PropertyConfigProto.DataType.Code dataTypeProto = PropertyConfigProto.DataType.Code.forNumber(dataType); if (dataTypeProto == null) { @@ -78,12 +71,13 @@ public final class SchemaToProtoConverter { propertyConfigProto.setDataType(dataTypeProto); // Set schemaType - propertyConfigProto.setSchemaType( - bundle.getString(AppSearchSchema.PropertyConfig.SCHEMA_TYPE_FIELD, "")); + String schemaType = property.getSchemaType(); + if (schemaType != null) { + propertyConfigProto.setSchemaType(schemaType); + } // Set cardinality - @AppSearchSchema.PropertyConfig.Cardinality int cardinality = - bundle.getInt(AppSearchSchema.PropertyConfig.CARDINALITY_FIELD); + @AppSearchSchema.PropertyConfig.Cardinality int cardinality = property.getCardinality(); PropertyConfigProto.Cardinality.Code cardinalityProto = PropertyConfigProto.Cardinality.Code.forNumber(cardinality); if (cardinalityProto == null) { @@ -92,8 +86,7 @@ public final class SchemaToProtoConverter { propertyConfigProto.setCardinality(cardinalityProto); // Set indexingType - @AppSearchSchema.PropertyConfig.IndexingType int indexingType = - bundle.getInt(AppSearchSchema.PropertyConfig.INDEXING_TYPE_FIELD); + @AppSearchSchema.PropertyConfig.IndexingType int indexingType = property.getIndexingType(); TermMatchType.Code termMatchTypeProto; switch (indexingType) { case AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE: @@ -112,7 +105,7 @@ public final class SchemaToProtoConverter { // Set tokenizerType @AppSearchSchema.PropertyConfig.TokenizerType int tokenizerType = - bundle.getInt(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_FIELD); + property.getTokenizerType(); IndexingConfig.TokenizerType.Code tokenizerTypeProto = IndexingConfig.TokenizerType.Code.forNumber(tokenizerType); if (tokenizerTypeProto == null) { diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localbackend/converter/SearchResultToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java index 524c80dd0609..9f7c6968e993 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/external/localbackend/converter/SearchResultToProtoConverter.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.appsearch.external.localbackend.converter; +package com.android.server.appsearch.external.localstorage.converter; import android.os.Bundle; @@ -22,43 +22,32 @@ import android.annotation.NonNull; import android.app.appsearch.GenericDocument; import android.app.appsearch.SearchResult; -import android.app.appsearch.SearchResults; import com.google.android.icing.proto.SearchResultProto; import com.google.android.icing.proto.SnippetMatchProto; import com.google.android.icing.proto.SnippetProto; import java.util.ArrayList; -import java.util.List; /** - * Translates a {@link SearchResultProto} into {@link SearchResults}. + * Translates a {@link SearchResultProto} into {@link SearchResult}s. + * * @hide */ public class SearchResultToProtoConverter { private SearchResultToProtoConverter() {} - /** Translates a {@link SearchResultProto} into a list of {@link SearchResult}. */ - @NonNull - public static List<SearchResult> convert(@NonNull SearchResultProto searchResultProto) { - List<SearchResult> results = new ArrayList<>(searchResultProto.getResultsCount()); - for (int i = 0; i < searchResultProto.getResultsCount(); i++) { - results.add(convertSearchResult(searchResultProto.getResults(i))); - } - return results; - } - /** Translate a {@link SearchResultProto.ResultProto} into {@link SearchResult}. */ @NonNull - static SearchResult convertSearchResult(@NonNull SearchResultProto.ResultProto proto) { + public static SearchResult convertSearchResult( + @NonNull SearchResultProto.ResultProtoOrBuilder proto) { Bundle bundle = new Bundle(); GenericDocument document = GenericDocumentToProtoConverter.convert(proto.getDocument()); bundle.putBundle(SearchResult.DOCUMENT_FIELD, document.getBundle()); - ArrayList<Bundle> matchList = null; + ArrayList<Bundle> matchList = new ArrayList<>(); if (proto.hasSnippet()) { - matchList = new ArrayList<>(); for (int i = 0; i < proto.getSnippet().getEntriesCount(); i++) { SnippetProto.EntryProto entry = proto.getSnippet().getEntries(i); for (int j = 0; j < entry.getSnippetMatchesCount(); j++) { diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localbackend/converter/SearchSpecToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchSpecToProtoConverter.java index a5d913a20590..14822dcdc793 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/external/localbackend/converter/SearchSpecToProtoConverter.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchSpecToProtoConverter.java @@ -14,9 +14,7 @@ * limitations under the License. */ -package com.android.server.appsearch.external.localbackend.converter; - -import android.os.Bundle; +package com.android.server.appsearch.external.localstorage.converter; import android.annotation.NonNull; @@ -28,8 +26,6 @@ import com.google.android.icing.proto.ScoringSpecProto; import com.google.android.icing.proto.SearchSpecProto; import com.google.android.icing.proto.TermMatchType; -import java.util.Arrays; - /** * Translates a {@link SearchSpec} into icing search protos. * @hide @@ -42,25 +38,17 @@ public final class SearchSpecToProtoConverter { @NonNull public static SearchSpecProto toSearchSpecProto(@NonNull SearchSpec spec) { Preconditions.checkNotNull(spec); - Bundle bundle = spec.getBundle(); - SearchSpecProto.Builder protoBuilder = SearchSpecProto.newBuilder(); + SearchSpecProto.Builder protoBuilder = SearchSpecProto.newBuilder() + .addAllSchemaTypeFilters(spec.getSchemas()) + .addAllNamespaceFilters(spec.getNamespaces()); - @SearchSpec.TermMatchCode int termMatchCode = - bundle.getInt(SearchSpec.TERM_MATCH_TYPE_FIELD); + @SearchSpec.TermMatch int termMatchCode = spec.getTermMatch(); TermMatchType.Code termMatchCodeProto = TermMatchType.Code.forNumber(termMatchCode); if (termMatchCodeProto == null || termMatchCodeProto.equals(TermMatchType.Code.UNKNOWN)) { throw new IllegalArgumentException("Invalid term match type: " + termMatchCode); } protoBuilder.setTermMatchType(termMatchCodeProto); - String[] schemaTypes = bundle.getStringArray(SearchSpec.SCHEMA_TYPES_FIELD); - if (schemaTypes != null) { - protoBuilder.addAllSchemaTypeFilters(Arrays.asList(schemaTypes)); - } - String[] namespaces = bundle.getStringArray(SearchSpec.NAMESPACE_FIELD); - if (namespaces != null) { - protoBuilder.addAllNamespaceFilters(Arrays.asList(namespaces)); - } return protoBuilder.build(); } @@ -68,27 +56,23 @@ public final class SearchSpecToProtoConverter { @NonNull public static ResultSpecProto toResultSpecProto(@NonNull SearchSpec spec) { Preconditions.checkNotNull(spec); - Bundle bundle = spec.getBundle(); return ResultSpecProto.newBuilder() - .setNumPerPage(bundle.getInt( - SearchSpec.NUM_PER_PAGE_FIELD, SearchSpec.DEFAULT_NUM_PER_PAGE)) - .setSnippetSpec(ResultSpecProto.SnippetSpecProto.newBuilder() - .setNumToSnippet(bundle.getInt(SearchSpec.SNIPPET_COUNT_FIELD)) - .setNumMatchesPerProperty( - bundle.getInt(SearchSpec.SNIPPET_COUNT_PER_PROPERTY_FIELD)) - .setMaxWindowBytes(bundle.getInt(SearchSpec.MAX_SNIPPET_FIELD))) + .setNumPerPage(spec.getNumPerPage()) + .setSnippetSpec( + ResultSpecProto.SnippetSpecProto.newBuilder() + .setNumToSnippet(spec.getSnippetCount()) + .setNumMatchesPerProperty(spec.getSnippetCountPerProperty()) + .setMaxWindowBytes(spec.getMaxSnippetSize())) .build(); - } /** Extracts {@link ScoringSpecProto} information from a {@link SearchSpec}. */ @NonNull public static ScoringSpecProto toScoringSpecProto(@NonNull SearchSpec spec) { Preconditions.checkNotNull(spec); - Bundle bundle = spec.getBundle(); ScoringSpecProto.Builder protoBuilder = ScoringSpecProto.newBuilder(); - @SearchSpec.OrderCode int orderCode = bundle.getInt(SearchSpec.ORDER_FIELD); + @SearchSpec.Order int orderCode = spec.getOrder(); ScoringSpecProto.Order.Code orderCodeProto = ScoringSpecProto.Order.Code.forNumber(orderCode); if (orderCodeProto == null) { @@ -96,8 +80,7 @@ public final class SearchSpecToProtoConverter { } protoBuilder.setOrderBy(orderCodeProto); - @SearchSpec.RankingStrategyCode int rankingStrategyCode = - bundle.getInt(SearchSpec.RANKING_STRATEGY_FIELD); + @SearchSpec.RankingStrategy int rankingStrategyCode = spec.getRankingStrategy(); ScoringSpecProto.RankingStrategy.Code rankingStrategyCodeProto = ScoringSpecProto.RankingStrategy.Code.forNumber(rankingStrategyCode); if (rankingStrategyCodeProto == null) { diff --git a/apex/extservices/Android.bp b/apex/extservices/Android.bp deleted file mode 100644 index 0c6c4c23dce1..000000000000 --- a/apex/extservices/Android.bp +++ /dev/null @@ -1,39 +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. - -apex { - name: "com.android.extservices", - defaults: ["com.android.extservices-defaults"], - manifest: "apex_manifest.json", -} - -apex_defaults { - name: "com.android.extservices-defaults", - updatable: true, - min_sdk_version: "current", - key: "com.android.extservices.key", - certificate: ":com.android.extservices.certificate", - apps: ["ExtServices"], -} - -apex_key { - name: "com.android.extservices.key", - public_key: "com.android.extservices.avbpubkey", - private_key: "com.android.extservices.pem", -} - -android_app_certificate { - name: "com.android.extservices.certificate", - certificate: "com.android.extservices", -} diff --git a/apex/extservices/apex_manifest.json b/apex/extservices/apex_manifest.json deleted file mode 100644 index b4acf1283d3e..000000000000 --- a/apex/extservices/apex_manifest.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "com.android.extservices", - "version": 300000000 -} diff --git a/apex/extservices/com.android.extservices.avbpubkey b/apex/extservices/com.android.extservices.avbpubkey Binary files differdeleted file mode 100644 index f37d3e4a14d4..000000000000 --- a/apex/extservices/com.android.extservices.avbpubkey +++ /dev/null diff --git a/apex/extservices/com.android.extservices.pem b/apex/extservices/com.android.extservices.pem deleted file mode 100644 index 7bfbd34ff9b9..000000000000 --- a/apex/extservices/com.android.extservices.pem +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIJKAIBAAKCAgEAuYshVDiRkt3tmBhqcWkKOm5GcviKpLbHSPpYQDHGDwS0dqqL -SqAd1/BgT/bVVtUkAciFApPnXn96WhNYCypptyC5FHCxM21uBCGmow+3WermD++w -5dQk4QP2ONPIpG+KzOWBl9SiBud4SpOHDyr0JycBsrXS89Tln9kAsTDuDEFfXL/J -8cX/S3IUwhPV0pAlgUIHdDp0DGFjZaJlEZBZ+HmImriC/AUNUMVb5lfbczXOEZPF -0A9+JzYschfXUxn8nu1N7RN5GDbq+chszx1FMVhuFUheukkd4dLNSDl0O0RlUnD+ -C/xz1ilDzEVZhnMtMnxS9oJ8bA/HUVMfsFnaQbgGmQ0CcxFxnfbYyGXGG1H+b8vA -MTVQi5rZXG2p+VgHIAKVrYmpETVnRPgoMqp18KuGtp5SDngi13G3YEzS7iFbqfYh -6iW2G974nD/Dq0cSire8Oljd9PEaMCMZiP5PTFJp0G/mtw7ROoyZqsSM6rX3XVTo -Y5dBmBMctSJ8rgDMi0ZNvRH+rq/E5+RT6yMAJ7DDbOJzBnQ3IIoGn8NzUT3P1FCB -HYEp1U2N7QNirIQMAuVz3IlHae9N1kl3eGAO6f2CjV7vZmFpDeWw+KSYs71mRkOb -WBgl6D9FFq4u1azrU3AwV0dj3x1eU6yVnKUy1J7ppF/mcR+VzH7ThzTdV7cCAwEA -AQKCAgEApWFU2Mv/PYhg0bPZlLLKsiA+3RWaBo0AfpTd+oIjBpnr/OWweFjVoPcZ -8cyShe4/RPOlUxHgJcO8m/MoA/PO/LLHJWf5GlzMthQEgs1sYVJVtBiydXitUn+E -hUyIR8FAV7et1lZqAXtqJhbvSF7B9u/2vIMCv+GgtuTmkAmL9RKD3Jj6eG1CS84o -oICrkx52v4rKOBgt/icEQMAKFCi1eRti3n3eCqK6JqdzbZIcAcoQnmw34mccy/im -jx+fBuxf1oywa8NyqVmyAehazBVL6lrm7ENwY9zuLK4H2fuUFYu2QFCEsMxZt6da -TgX2cTfSLnDQRfcyzeMWhu9vjHHabjpLNjiCKhIhGyO0rO1rtea8ajZHgM/2sxXq -6gLynW0dlatlxmjANlN9WQPGNdzvcIFJ0TLnI4mlJnWpqCsN9iW1d4ey13WiZUVR -DgtnR60zao+LRCCM4D3cuVLq0DjL2BlHGXnOPK/LpQG1LbI1TroZpgSEHSZlQRzT -ql9txgNqTHxijXuPL2VhhwhW7cqDoO8sLwV3BqDMIH56U0cbUBiSA/G9fKeI/DEG -i7LcrMgrBk+xnuAWoFHuzfBMAdD9i3kYyk+41tOmcza2TNJgxadVYp5woHFvYvS/ -GKaNiRz0XmcijO5Ir0yxgCq21BdkWzo5zVrTFABiKeR7YXiee8kCggEBAOeULWgR -spolJJrACWJspRvKb9FGnbGiYOnCGJoAc751kuXmNxoyWnEwgcjrSEoayNPUfOtz -IgA+twqjgl0Zec2XFPfUcgWUBrrvvUEV4NIH5ibaR7ezHGeovCWs9XoDyzHHvhDr -c6T5kXFZ60rS5h6LGUnE1hkHFJoHuTIBbn9j7eIbri8S71i7HWQ04s4KuQ+Bwbxm -UnkEhbc+zMWHXfXy7rx4/eEZcZwtEybIORcHXYNPGeqMfOlcEMHpKEOi+NvDA6cp -vTaTSwJ6ZBgYh7Tw3bNgRxSknaIhcGwMD0ojStjC5xzXT1Zr2Z3GXwYvOGcq3MeZ -z+V2cx5xuwyp7R0CggEBAM0cKKNZEZwi/1zBPUDMFB4iJoX12BxQX6e5wdlHGXgF -XeZwCnaIxOxMDxH79M5Svmpdu/jkUijI/pRvcE1iohFyIBvTUSDmlAoy4keXqMEQ -M2hA+TwVA3JLmMcV8HKy/MFlwwKJB1JDcoxGjnXsM5UjVTD2jilO7vlJZs3+0ws0 -R7qzRT3ED25QTpZyDYcKE2otc5bzIZG3yAaJtWd3NugWsKpxDgr2RFUGJiHBq72n -48FkSjfgaDTn83zYcPvS0Uykb2ho8G/N+EurstL41n3nQo0I7FLbyptOopDDwsSp -Ndejn08NVAQ+xFAafOyqHkA3Ytpl0QCZDpMBuLdvw+MCggEAOVMt1kgjPRMat4/4 -ArxANtvqyBRB7vnyIYthiaW5ARmbrntJgpuaVdCbIABWGbn9oqpD7gjHDuZ3axPE -roUi6KiQkTSusQDOlbHI2Haw+2znJRD9ldSpoGNdh7oD3htYTk9Sll+ideEthrCq -lRAV1NO8A83M7c8Z43Mr/dvq3XAAL+uIN7DpPL687NRGnJh87QDC039ExR5Ad3b9 -O5xhvwNO46rTtcgVnoJt7ji8IR46oMmQ8cWrGh0nLMkppWyPS98/ZT7ozryxYcCo -TGquFTVWvBOGJO8G8l5ytNxbYI/R9Exy52nJAuyZpvu3BBHmVWt/0Y0asIOcxZmD -owPhZQKCAQAfWAFBzReq05JQe1s/7q/YVwGqEQKgeQvVFsbvzDSxKajK0S5YJNhq -/8iByA4GBZEBsidKhqGjh+uXhVwVB1Ca9+S+O9G3BGV1FYeMxzlLn40rjlpH+zIW -okTLj6e5724+o61kUspioNn9Y77beGf9j3OyUsswttZAFB54tktL+AZKGqEnKjHt -eqo3xWAZ1clXvXBfjfIAUaRok1y8XfRvDSCcO0CZHj8c+x6SpAT5q5FbeVb6KPnj -s9p6ppzFbtb7Llm0C+1KOKCL98YRBWPJw7Bg2w86LkpM53xiQPgfk3gd5uwuaWwA -ZhMb5qBWjjynNY+OrmZ8/+bBQk8XASZfAoIBAFkHOnZOD1JJQ0QvaJ9tuCgHi216 -I8QPMMTdm3ZEDHSYMNwl7ayeseBcmB2zaqBKYz75qcU0SK4lnZkR2wIpbsHZNSVM -J0WpN6r9G4JdnVi11J04RsfSMjCUr/PTVMmPvw8xPHrCxkJmB+d56olSE80I1Jrx -djCv1LtSsT10W7FIcY82/cOi4xxGLOA70lDCf+szofQgVP8WvuOA1YaFw98ca8zc -A401CyNexk24/c3d6C19YW/MppdE0uGMxL/oHsPgwkZAf6LmvF/UF71PsBUEniLc -YFaJl3wn1cPfBBo9L4sZzyP2qokL8YHdg+wW7b4IOsYwbeqceBvqPtcUUPs= ------END RSA PRIVATE KEY----- diff --git a/apex/extservices/com.android.extservices.pk8 b/apex/extservices/com.android.extservices.pk8 Binary files differdeleted file mode 100644 index 59585a212592..000000000000 --- a/apex/extservices/com.android.extservices.pk8 +++ /dev/null diff --git a/apex/extservices/com.android.extservices.x509.pem b/apex/extservices/com.android.extservices.x509.pem deleted file mode 100644 index e0343b81d279..000000000000 --- a/apex/extservices/com.android.extservices.x509.pem +++ /dev/null @@ -1,36 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIGLTCCBBWgAwIBAgIUdqdMmx/5OsCP3Ew3/hcr7+1ACHEwDQYJKoZIhvcNAQEL -BQAwgaQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH -DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy -b2lkMSAwHgYDVQQDDBdjb20uYW5kcm9pZC5leHRzZXJ2aWNlczEiMCAGCSqGSIb3 -DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAgFw0yMDAxMTcxMDIxMzZaGA80NzU3 -MTIxMzEwMjEzNlowgaQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlh -MRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYD -VQQLDAdBbmRyb2lkMSAwHgYDVQQDDBdjb20uYW5kcm9pZC5leHRzZXJ2aWNlczEi -MCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCAiIwDQYJKoZIhvcN -AQEBBQADggIPADCCAgoCggIBANKaSeLGaFRRt779vAtTfG3t2aQZrWOByUYc7yUN -RdmJqWxU47OL5urYmanWPbz2f972Q9oi8x+8y4ny9SEY3wg0pUbzvKNTXpkxWyG1 -HE2C2zTfzuDDLpDIf2usWynt1wLVhpYC3k+7Yv2vOIK5dKkezh6PfdKmsbDae5DE -d22tTSYZ5KwNpIWrgQle26cRG5sqhAFdkpgGMF00Huz06cjUoTjs2sNSlXTRBOTP -CCy8UoRjBivQZkwHbddfsn+Z22ARPG8JDg/n4mEi8C0T6bJeQeirSPkBCkD6Djgq -7RddJ2eLYZII8l8r6A6x+6cnTkXHaV5g3LUwPvi8XEn9IUuT9WJNRje/vfYLycTQ -kP415CZMxDvsi1Ul4YsbL3enE89ryGMTpVZPogch/36DG5Sye28yISItNUy3urJa -OXbg7mh+MwPd4bQaW4CJk+AUweKaF4aV0SZFT+nCewL4xLdGdy889KazlW98NqtK -hOSxIg1jHkZq48ajuq2A+ns1yDKt1l0f9IYCz3mz/IXInokbkjPvHahJTJ+OMHXO -THD8e5gBzcK841jJk+H3EsIYOHsp66uy2IgEHN+9pAS6vI0xfrXOYuKzuSL3oxcV -FlVTimt4xokMMerdcW4KD+MC5NFEip4DUS4JKCyG0wRI3ffEs9Zcpxi3QSibrjLW -rz+hAgMBAAGjUzBRMB0GA1UdDgQWBBTP2AhZzEUUgtAFlkaMaq+RvY06fDAfBgNV -HSMEGDAWgBTP2AhZzEUUgtAFlkaMaq+RvY06fDAPBgNVHRMBAf8EBTADAQH/MA0G -CSqGSIb3DQEBCwUAA4ICAQCbwtfo37j62Sudmt32PCfRN/r5ZNDNNA2JhR8uDUmX -xXfF5YfDvSKsNLiQKcDagu6a+0C+QnzXHXCBlXZFrTJ8NAVMlmqdHGwoFoYMfJZH -R1lCTidyFMoMLJ8GRGPJjzDkKnOeAqKMCtKvXoH2r12+JB2/ov4ooLREu/wPkEXT -OymkyWNP5XLQTKWqfEQyXXFpuwZ+m35Wkr0Fm92mZeJpVeIZPK7M7aK3zyoj7XJP -YLMsR/AQs8OULdpfNMddAuN3ndlYu03LZlsF6LG5bduaDDcESJ5hdJrgBa/NBKRU -IbS+q/6WAjYKMNRT/fPGew4wUzlWKi1Ihdk79oaqKKijE1b2JSJD1/SEYiBf+JPE -bXobUrMbBwFpdhT+YLMF9FsuPQKsUIONaWiO4QcQoY/rQwGxPP6fV8ZbBrUWJewj -MpSdU9foZNa/TmOAgfS/JxH+nXnG4+H1m8mdNBsxvsYmF2ZuGb/jdEeA2cuHIJDZ -FJeWwCFxzlCGZJaUsxsnZByADBuufUVaO/9gGs0YQC/JP1i9hK4DyZdKwZpXdLi2 -Nw27Qma4WEIZnMb6Rgk1nTV+7ALcOSIhGgFOOeDTuCGfnEcz2coai5fbD/K6Q7Xu -IRNyxHQjheZPdei2x912Ex/KqKGfaFaZJxrvCSKdhzxcTFIsO4JuZs+SDpRTKcI7 -Cw== ------END CERTIFICATE----- diff --git a/apex/extservices/testing/Android.bp b/apex/extservices/testing/Android.bp deleted file mode 100644 index 88a47246c824..000000000000 --- a/apex/extservices/testing/Android.bp +++ /dev/null @@ -1,25 +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. - -apex_test { - name: "test_com.android.extservices", - visibility: [ - "//system/apex/tests", - ], - defaults: ["com.android.extservices-defaults"], - manifest: "test_manifest.json", - file_contexts: ":com.android.extservices-file_contexts", - // Test APEX, should never be installed - installable: false, -} diff --git a/apex/extservices/testing/test_manifest.json b/apex/extservices/testing/test_manifest.json deleted file mode 100644 index 23a50e37bdd3..000000000000 --- a/apex/extservices/testing/test_manifest.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "com.android.extservices", - "version": 2147483647 -} diff --git a/api/current.txt b/api/current.txt index 9ff7cc255bf4..6459eb4c548a 100644 --- a/api/current.txt +++ b/api/current.txt @@ -11718,10 +11718,9 @@ package android.content.pm { method public long getFirstInstallTime(); method public android.graphics.drawable.Drawable getIcon(int); method public CharSequence getLabel(); + method public float getLoadingProgress(); method public String getName(); - method public float getProgress(); method public android.os.UserHandle getUser(); - method public boolean isLoading(); method public boolean isStartable(); } @@ -11762,7 +11761,7 @@ package android.content.pm { ctor public LauncherApps.Callback(); method public abstract void onPackageAdded(String, android.os.UserHandle); method public abstract void onPackageChanged(String, android.os.UserHandle); - method public void onPackageProgressChanged(@NonNull String, @NonNull android.os.UserHandle, float); + method public void onPackageLoadingProgressChanged(@NonNull String, @NonNull android.os.UserHandle, float); method public abstract void onPackageRemoved(String, android.os.UserHandle); method public abstract void onPackagesAvailable(String[], android.os.UserHandle, boolean); method public void onPackagesSuspended(String[], android.os.UserHandle); @@ -31862,6 +31861,15 @@ package android.net.wifi.aware { method public void onAttached(android.net.wifi.aware.WifiAwareSession); } + public final class AwareResources implements android.os.Parcelable { + method public int describeContents(); + method public int getNumOfAvailableDataPaths(); + method public int getNumOfAvailablePublishSessions(); + method public int getNumOfAvailableSubscribeSessions(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.aware.AwareResources> CREATOR; + } + public final class Characteristics implements android.os.Parcelable { method public int describeContents(); method public int getMaxMatchFilterLength(); @@ -31964,7 +31972,8 @@ package android.net.wifi.aware { public class WifiAwareManager { method public void attach(@NonNull android.net.wifi.aware.AttachCallback, @Nullable android.os.Handler); method public void attach(@NonNull android.net.wifi.aware.AttachCallback, @NonNull android.net.wifi.aware.IdentityChangedListener, @Nullable android.os.Handler); - method public android.net.wifi.aware.Characteristics getCharacteristics(); + method @Nullable public android.net.wifi.aware.AwareResources getAvailableAwareResources(); + method @Nullable public android.net.wifi.aware.Characteristics getCharacteristics(); method public boolean isAvailable(); method public boolean isDeviceAttached(); method public boolean isInstantCommunicationModeEnabled(); diff --git a/api/system-current.txt b/api/system-current.txt index 720bf8c5d471..3dd05af06b24 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5725,7 +5725,7 @@ package android.media.tv.tuner.frontend { method @NonNull public android.media.tv.tuner.frontend.AtscFrontendSettings.Builder setModulation(int); } - public class DtmbFrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities { + public final class DtmbFrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities { method public int getBandwidthCapability(); method public int getCodeRateCapability(); method public int getGuardIntervalCapability(); @@ -5734,7 +5734,7 @@ package android.media.tv.tuner.frontend { method public int getTransmissionModeCapability(); } - public class DtmbFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings { + public final class DtmbFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings { method @NonNull public static android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder builder(); method public int getBandwidth(); method public int getCodeRate(); @@ -7683,8 +7683,11 @@ package android.net.wifi { method public double getSuccessfulRxPacketsPerSecond(); method public double getSuccessfulTxPacketsPerSecond(); method public boolean isEphemeral(); + method public boolean isOemPaid(); + method public boolean isOemPrivate(); method public boolean isOsuAp(); method public boolean isPasspointAp(); + method public boolean isTrusted(); method @Nullable public static String sanitizeSsid(@Nullable String); field public static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00"; field public static final int INVALID_RSSI = -127; // 0xffffff81 @@ -7910,11 +7913,13 @@ package android.net.wifi { public final class WifiNetworkSuggestion implements android.os.Parcelable { method @NonNull public android.net.wifi.WifiConfiguration getWifiConfiguration(); method public boolean isOemPaid(); + method public boolean isOemPrivate(); } public static final class WifiNetworkSuggestion.Builder { method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING) public android.net.wifi.WifiNetworkSuggestion.Builder setCarrierId(int); method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setOemPaid(boolean); + method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setOemPrivate(boolean); } public class WifiScanner { diff --git a/api/test-current.txt b/api/test-current.txt index 785463a92c45..edc422dbf24d 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -290,6 +290,7 @@ package android.app { method @NonNull public android.content.res.Configuration getConfiguration(); method @Nullable public android.app.PictureInPictureParams getPictureInPictureParams(); method @NonNull public android.window.WindowContainerToken getToken(); + method public boolean hasParentTask(); } public class TimePickerDialog extends android.app.AlertDialog implements android.content.DialogInterface.OnClickListener android.widget.TimePicker.OnTimeChangedListener { @@ -970,6 +971,14 @@ package android.media { field public static final String SAMPLE_RATE = "android.media.audiotrack.sampleRate"; } + public abstract class Image implements java.lang.AutoCloseable { + ctor protected Image(); + } + + public abstract static class Image.Plane { + ctor protected Image.Plane(); + } + public final class MediaCas implements java.lang.AutoCloseable { method public void forceResourceLost(); } diff --git a/cmds/statsd/src/anomaly/AlarmTracker.h b/cmds/statsd/src/anomaly/AlarmTracker.h index 2da4a18682ae..406086da557b 100644 --- a/cmds/statsd/src/anomaly/AlarmTracker.h +++ b/cmds/statsd/src/anomaly/AlarmTracker.h @@ -73,6 +73,7 @@ protected: FRIEND_TEST(AlarmTrackerTest, TestTriggerTimestamp); FRIEND_TEST(AlarmE2eTest, TestMultipleAlarms); + FRIEND_TEST(ConfigUpdateTest, TestUpdateAlarms); }; } // namespace statsd diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp index 619752c7c44a..6aa410b180b8 100644 --- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp +++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp @@ -37,14 +37,6 @@ namespace statsd { AnomalyTracker::AnomalyTracker(const Alert& alert, const ConfigKey& configKey) : mAlert(alert), mConfigKey(configKey), mNumOfPastBuckets(mAlert.num_buckets() - 1) { VLOG("AnomalyTracker() called"); - if (mAlert.num_buckets() <= 0) { - ALOGE("Cannot create AnomalyTracker with %lld buckets", (long long)mAlert.num_buckets()); - return; - } - if (!mAlert.has_trigger_if_sum_gt()) { - ALOGE("Cannot create AnomalyTracker without threshold"); - return; - } resetStorage(); // initialization } @@ -52,6 +44,10 @@ AnomalyTracker::~AnomalyTracker() { VLOG("~AnomalyTracker() called"); } +void AnomalyTracker::onConfigUpdated() { + mSubscriptions.clear(); +} + void AnomalyTracker::resetStorage() { VLOG("resetStorage() called."); mPastBuckets.clear(); @@ -259,6 +255,15 @@ bool AnomalyTracker::isInRefractoryPeriod(const int64_t& timestampNs, return false; } +std::pair<bool, uint64_t> AnomalyTracker::getProtoHash() const { + string serializedAlert; + if (!mAlert.SerializeToString(&serializedAlert)) { + ALOGW("Unable to serialize alert %lld", (long long)mAlert.id()); + return {false, 0}; + } + return {true, Hash64(serializedAlert)}; +} + void AnomalyTracker::informSubscribers(const MetricDimensionKey& key, int64_t metric_id, int64_t metricValue) { triggerSubscribers(mAlert.id(), metric_id, key, metricValue, mConfigKey, mSubscriptions); diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.h b/cmds/statsd/src/anomaly/AnomalyTracker.h index bf36a3bc8990..9a578ee0696d 100644 --- a/cmds/statsd/src/anomaly/AnomalyTracker.h +++ b/cmds/statsd/src/anomaly/AnomalyTracker.h @@ -16,15 +16,15 @@ #pragma once -#include <stdlib.h> - #include <gtest/gtest_prod.h> +#include <stdlib.h> #include <utils/RefBase.h> #include "AlarmMonitor.h" #include "config/ConfigKey.h" -#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // Alert +#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // Alert #include "frameworks/base/cmds/statsd/src/statsd_metadata.pb.h" // AlertMetadata +#include "hash.h" #include "stats_util.h" // HashableDimensionKey and DimToValMap namespace android { @@ -41,6 +41,9 @@ public: virtual ~AnomalyTracker(); + // Reset appropriate state on a config update. Clear subscriptions so they can be reset. + void onConfigUpdated(); + // Add subscriptions that depend on this alert. void addSubscription(const Subscription& subscription) { mSubscriptions.push_back(subscription); @@ -106,6 +109,26 @@ public: return mNumOfPastBuckets; } + std::pair<bool, uint64_t> getProtoHash() const; + + // Sets an alarm for the given timestamp. + // Replaces previous alarm if one already exists. + virtual void startAlarm(const MetricDimensionKey& dimensionKey, const int64_t& eventTime) { + return; // The base AnomalyTracker class doesn't have alarms. + } + + // Stops the alarm. + // If it should have already fired, but hasn't yet (e.g. because the AlarmManager is delayed), + // declare the anomaly now. + virtual void stopAlarm(const MetricDimensionKey& dimensionKey, const int64_t& timestampNs) { + return; // The base AnomalyTracker class doesn't have alarms. + } + + // Stop all the alarms owned by this tracker. Does not declare any anomalies. + virtual void cancelAllAlarms() { + return; // The base AnomalyTracker class doesn't have alarms. + } + // Declares an anomaly for each alarm in firedAlarms that belongs to this AnomalyTracker, // and removes it from firedAlarms. Does NOT remove the alarm from the AlarmMonitor. virtual void informAlarmsFired(const int64_t& timestampNs, @@ -197,6 +220,8 @@ protected: FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket); FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets); FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period); + + FRIEND_TEST(ConfigUpdateTest, TestUpdateAlerts); }; } // namespace statsd diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.h b/cmds/statsd/src/anomaly/DurationAnomalyTracker.h index 686d8f95c7f6..46419149580b 100644 --- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.h +++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.h @@ -34,15 +34,15 @@ public: // Sets an alarm for the given timestamp. // Replaces previous alarm if one already exists. - void startAlarm(const MetricDimensionKey& dimensionKey, const int64_t& eventTime); + void startAlarm(const MetricDimensionKey& dimensionKey, const int64_t& eventTime) override; // Stops the alarm. // If it should have already fired, but hasn't yet (e.g. because the AlarmManager is delayed), // declare the anomaly now. - void stopAlarm(const MetricDimensionKey& dimensionKey, const int64_t& timestampNs); + void stopAlarm(const MetricDimensionKey& dimensionKey, const int64_t& timestampNs) override; // Stop all the alarms owned by this tracker. Does not declare any anomalies. - void cancelAllAlarms(); + void cancelAllAlarms() override; // Declares an anomaly for each alarm in firedAlarms that belongs to this DurationAnomalyTracker // and removes it from firedAlarms. The AlarmMonitor is not informed. diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index a379847f21da..ac2a8e4ffcd2 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -9754,6 +9754,7 @@ message RebootEscrowRecoveryReported { /** * Global display pipeline metrics reported by SurfaceFlinger. + * Metrics exist beginning in Android 11. * Pulled from: * frameworks/native/services/surfaceflinger/TimeStats/TimeStats.cpp */ @@ -9785,18 +9786,48 @@ message SurfaceflingerStatsGlobalInfo { // perform due to falling back into GPU composition. optional FrameTimingHistogram render_engine_timing = 8 [(android.os.statsd.log_mode) = MODE_BYTES]; + // Number of frames where SF saw a frame, based on its frame timeline. + // Frame timelines may include transactions without updating buffer contents. + // Introduced in Android 12. + optional int32 total_timeline_frames = 9; + // Number of frames where SF saw a janky frame. + // Introduced in Android 12. + optional int32 total_janky_frames = 10; + // Number of janky frames where SF spent a long time on the CPU. + // Introduced in Android 12. + optional int32 total_janky_frames_with_long_cpu = 11; + // Number of janky frames where SF spent a long time on the GPU. + // Introduced in Android 12. + optional int32 total_janky_frames_with_long_gpu = 12; + // Number of janky frames where SF missed the frame deadline, but there + // was not an attributed reason (e.g., maybe HWC missed?) + // Introduced in Android 12. + optional int32 total_janky_frames_sf_unattributed = 13; + // Number of janky frames where the app missed the frame deadline, but + // there was not an attributed reason + // Introduced in Android 12. + optional int32 total_janky_frames_app_unattributed = 14; + + // Next ID: 15 } /** * Per-layer display pipeline metrics reported by SurfaceFlinger. - * The number of layers uploaded will be restricted due to size limitations. + * Metrics exist beginning in Android 11. + * The number of layers uploaded may be restricted due to size limitations. * Pulled from: * frameworks/native/services/surfaceflinger/TimeStats/TimeStats.cpp */ message SurfaceflingerStatsLayerInfo { + // UID of the application who submitted this layer for presentation + // This is intended to be used as a dimension for surfacing rendering + // statistics to applications. + // Introduced in Android 12. + optional int32 uid = 12 [(is_uid) = true]; // The layer for this set of metrics - // For now we can infer that the package name is included in the layer - // name. + // In many scenarios the package name is included in the layer name, e.g., + // layers created by Window Manager. But this is not a guarantee - in the + // general case layer names are arbitrary debug names. optional string layer_name = 1; // Total number of frames presented optional int64 total_frames = 2; @@ -9830,6 +9861,29 @@ message SurfaceflingerStatsLayerInfo { optional int64 late_acquire_frames = 10; // Frames latched early because the desired present time was bad optional int64 bad_desired_present_frames = 11; + // Number of frames where SF saw a frame, based on its frame timeline. + // Frame timelines may include transactions without updating buffer contents. + // Introduced in Android 12. + optional int32 total_timeline_frames = 13; + // Number of frames where SF saw a janky frame. + // Introduced in Android 12. + optional int32 total_janky_frames = 14; + // Number of janky frames where SF spent a long time on the CPU. + // Introduced in Android 12. + optional int32 total_janky_frames_with_long_cpu = 15; + // Number of janky frames where SF spent a long time on the GPU. + // Introduced in Android 12. + optional int32 total_janky_frames_with_long_gpu = 16; + // Number of janky frames where SF missed the frame deadline, but there + // was not an attributed reason (e.g., maybe HWC missed?) + // Introduced in Android 12. + optional int32 total_janky_frames_sf_unattributed = 17; + // Number of janky frames where the app missed the frame deadline, but + // there was not an attributed reason + // Introduced in Android 12. + optional int32 total_janky_frames_app_unattributed = 18; + + // Next ID: 19 } /** diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp index b2c0b32bf5ef..8869241ab8aa 100644 --- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp +++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp @@ -234,14 +234,26 @@ sp<AnomalyTracker> DurationMetricProducer::addAnomalyTracker( return nullptr; } } - sp<DurationAnomalyTracker> anomalyTracker = - new DurationAnomalyTracker(alert, mConfigKey, anomalyAlarmMonitor); - if (anomalyTracker != nullptr) { - mAnomalyTrackers.push_back(anomalyTracker); - } + sp<AnomalyTracker> anomalyTracker = + new DurationAnomalyTracker(alert, mConfigKey, anomalyAlarmMonitor); + addAnomalyTrackerLocked(anomalyTracker); return anomalyTracker; } +// Adds an AnomalyTracker that has already been created. +// Note: this gets called on config updates, and will only get called if the metric and the +// associated alert are preserved, which means the AnomalyTracker must be a DurationAnomalyTracker. +void DurationMetricProducer::addAnomalyTracker(sp<AnomalyTracker>& anomalyTracker) { + std::lock_guard<std::mutex> lock(mMutex); + addAnomalyTrackerLocked(anomalyTracker); +} + +void DurationMetricProducer::addAnomalyTrackerLocked(sp<AnomalyTracker>& anomalyTracker) { + mAnomalyTrackers.push_back(anomalyTracker); + for (const auto& [_, durationTracker] : mCurrentSlicedDurationTrackerMap) { + durationTracker->addAnomalyTracker(anomalyTracker); + } +} void DurationMetricProducer::onStateChanged(const int64_t eventTimeNs, const int32_t atomId, const HashableDimensionKey& primaryKey, const FieldValue& oldState, diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h index 01198a9271d3..5feb09fc1c98 100644 --- a/cmds/statsd/src/metrics/DurationMetricProducer.h +++ b/cmds/statsd/src/metrics/DurationMetricProducer.h @@ -55,6 +55,8 @@ public: sp<AnomalyTracker> addAnomalyTracker(const Alert &alert, const sp<AlarmMonitor>& anomalyAlarmMonitor) override; + void addAnomalyTracker(sp<AnomalyTracker>& anomalyTracker) override; + void onStateChanged(const int64_t eventTimeNs, const int32_t atomId, const HashableDimensionKey& primaryKey, const FieldValue& oldState, const FieldValue& newState) override; @@ -128,6 +130,8 @@ private: std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap, std::vector<int>& metricsWithActivation) override; + void addAnomalyTrackerLocked(sp<AnomalyTracker>& anomalyTracker); + const DurationMetric_AggregationType mAggregationType; // Index of the SimpleAtomMatcher which defines the start. @@ -164,9 +168,6 @@ private: std::unique_ptr<DurationTracker> createDurationTracker( const MetricDimensionKey& eventKey) const; - // This hides the base class's std::vector<sp<AnomalyTracker>> mAnomalyTrackers - std::vector<sp<DurationAnomalyTracker>> mAnomalyTrackers; - // Util function to check whether the specified dimension hits the guardrail. bool hitGuardRailLocked(const MetricDimensionKey& newKey); @@ -185,6 +186,7 @@ private: FRIEND_TEST(DurationMetricProducerTest_PartialBucket, TestMaxDurationWithSplitInNextBucket); FRIEND_TEST(ConfigUpdateTest, TestUpdateDurationMetrics); + FRIEND_TEST(ConfigUpdateTest, TestUpdateAlerts); }; } // namespace statsd diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp index 95a7d40ea9a9..5b321a0e3d60 100644 --- a/cmds/statsd/src/metrics/MetricProducer.cpp +++ b/cmds/statsd/src/metrics/MetricProducer.cpp @@ -101,6 +101,7 @@ bool MetricProducer::onConfigUpdatedLocked( } mEventActivationMap = newEventActivationMap; mEventDeactivationMap = newEventDeactivationMap; + mAnomalyTrackers.clear(); return true; } diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h index 92c1a6e62640..0dc8edae8056 100644 --- a/cmds/statsd/src/metrics/MetricProducer.h +++ b/cmds/statsd/src/metrics/MetricProducer.h @@ -155,6 +155,7 @@ public: // Update appropriate state on config updates. Primarily, all indices need to be updated. // This metric and all of its dependencies are guaranteed to be preserved across the update. // This function also updates several maps used by metricsManager. + // This function clears all anomaly trackers. All anomaly trackers need to be added again. bool onConfigUpdated( const StatsdConfig& config, const int configIndex, const int metricIndex, const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, @@ -237,9 +238,6 @@ public: dumpLatency, str_set, protoOutput); } - // Update appropriate state on config updates. Primarily, all indices need to be updated. - // This metric and all of its dependencies are guaranteed to be preserved across the update. - // This function also updates several maps used by metricsManager. virtual bool onConfigUpdatedLocked( const StatsdConfig& config, const int configIndex, const int metricIndex, const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, @@ -338,16 +336,20 @@ public: return mSlicedStateAtoms; } - /* If alert is valid, adds an AnomalyTracker and returns it. If invalid, returns nullptr. */ + /* Adds an AnomalyTracker and returns it. */ virtual sp<AnomalyTracker> addAnomalyTracker(const Alert &alert, const sp<AlarmMonitor>& anomalyAlarmMonitor) { std::lock_guard<std::mutex> lock(mMutex); sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, mConfigKey); - if (anomalyTracker != nullptr) { - mAnomalyTrackers.push_back(anomalyTracker); - } + mAnomalyTrackers.push_back(anomalyTracker); return anomalyTracker; } + + /* Adds an AnomalyTracker that has already been created */ + virtual void addAnomalyTracker(sp<AnomalyTracker>& anomalyTracker) { + std::lock_guard<std::mutex> lock(mMutex); + mAnomalyTrackers.push_back(anomalyTracker); + } // End: getters/setters protected: /** @@ -571,6 +573,7 @@ protected: FRIEND_TEST(ConfigUpdateTest, TestUpdateGaugeMetrics); FRIEND_TEST(ConfigUpdateTest, TestUpdateDurationMetrics); FRIEND_TEST(ConfigUpdateTest, TestUpdateMetricsMultipleTypes); + FRIEND_TEST(ConfigUpdateTest, TestUpdateAlerts); }; } // namespace statsd diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp index ab0d286d6b29..d80f9dbb4256 100644 --- a/cmds/statsd/src/metrics/MetricsManager.cpp +++ b/cmds/statsd/src/metrics/MetricsManager.cpp @@ -209,6 +209,9 @@ bool MetricsManager::updateConfig(const StatsdConfig& config, const int64_t time map<int64_t, uint64_t> newStateProtoHashes; vector<sp<MetricProducer>> newMetricProducers; unordered_map<int64_t, int> newMetricProducerMap; + vector<sp<AnomalyTracker>> newAnomalyTrackers; + unordered_map<int64_t, int> newAlertTrackerMap; + vector<sp<AlarmTracker>> newPeriodicAlarmTrackers; mTagIds.clear(); mConditionToMetricMap.clear(); mTrackerToMetricMap.clear(); @@ -221,11 +224,13 @@ bool MetricsManager::updateConfig(const StatsdConfig& config, const int64_t time mConfigKey, config, mUidMap, mPullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, timeBaseNs, currentTimeNs, mAllAtomMatchingTrackers, mAtomMatchingTrackerMap, mAllConditionTrackers, mConditionTrackerMap, mAllMetricProducers, mMetricProducerMap, - mStateProtoHashes, mTagIds, newAtomMatchingTrackers, newAtomMatchingTrackerMap, - newConditionTrackers, newConditionTrackerMap, newMetricProducers, newMetricProducerMap, - mConditionToMetricMap, mTrackerToMetricMap, mTrackerToConditionMap, - mActivationAtomTrackerToMetricMap, mDeactivationAtomTrackerToMetricMap, - mMetricIndexesWithActivation, newStateProtoHashes, mNoReportMetricIds); + mAllAnomalyTrackers, mAlertTrackerMap, mStateProtoHashes, mTagIds, + newAtomMatchingTrackers, newAtomMatchingTrackerMap, newConditionTrackers, + newConditionTrackerMap, newMetricProducers, newMetricProducerMap, newAnomalyTrackers, + newAlertTrackerMap, newPeriodicAlarmTrackers, mConditionToMetricMap, + mTrackerToMetricMap, mTrackerToConditionMap, mActivationAtomTrackerToMetricMap, + mDeactivationAtomTrackerToMetricMap, mMetricIndexesWithActivation, newStateProtoHashes, + mNoReportMetricIds); mAllAtomMatchingTrackers = newAtomMatchingTrackers; mAtomMatchingTrackerMap = newAtomMatchingTrackerMap; mAllConditionTrackers = newConditionTrackers; @@ -233,6 +238,9 @@ bool MetricsManager::updateConfig(const StatsdConfig& config, const int64_t time mAllMetricProducers = newMetricProducers; mMetricProducerMap = newMetricProducerMap; mStateProtoHashes = newStateProtoHashes; + mAllAnomalyTrackers = newAnomalyTrackers; + mAlertTrackerMap = newAlertTrackerMap; + mAllPeriodicAlarmTrackers = newPeriodicAlarmTrackers; return mConfigValid; } diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h index 657b2e4c3ddf..cf1f437c4168 100644 --- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h +++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h @@ -71,7 +71,7 @@ public: sp<ConditionWizard> wizard, int conditionIndex, bool nesting, int64_t currentBucketStartNs, int64_t currentBucketNum, int64_t startTimeNs, int64_t bucketSizeNs, bool conditionSliced, bool fullLink, - const std::vector<sp<DurationAnomalyTracker>>& anomalyTrackers) + const std::vector<sp<AnomalyTracker>>& anomalyTrackers) : mConfigKey(key), mTrackerId(id), mEventKey(eventKey), @@ -93,6 +93,7 @@ public: sp<ConditionWizard> tmpWizard = mWizard; mWizard = wizard; mConditionTrackerIndex = conditionTrackerIndex; + mAnomalyTrackers.clear(); }; virtual void noteStart(const HashableDimensionKey& key, bool condition, const int64_t eventTime, @@ -120,7 +121,7 @@ public: std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>* output) = 0; // Predict the anomaly timestamp given the current status. - virtual int64_t predictAnomalyTimestampNs(const DurationAnomalyTracker& anomalyTracker, + virtual int64_t predictAnomalyTimestampNs(const AnomalyTracker& anomalyTracker, const int64_t currentTimestamp) const = 0; // Dump internal states for debugging virtual void dumpStates(FILE* out, bool verbose) const = 0; @@ -132,6 +133,10 @@ public: // Replace old value with new value for the given state atom. virtual void updateCurrentStateKey(const int32_t atomId, const FieldValue& newState) = 0; + void addAnomalyTracker(sp<AnomalyTracker>& anomalyTracker) { + mAnomalyTrackers.push_back(anomalyTracker); + } + protected: int64_t getCurrentBucketEndTimeNs() const { return mStartTimeNs + (mCurrentBucketNum + 1) * mBucketSizeNs; @@ -218,13 +223,14 @@ protected: bool mHasLinksToAllConditionDimensionsInTracker; - std::vector<sp<DurationAnomalyTracker>> mAnomalyTrackers; + std::vector<sp<AnomalyTracker>> mAnomalyTrackers; FRIEND_TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp); FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm); FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm); FRIEND_TEST(ConfigUpdateTest, TestUpdateDurationMetrics); + FRIEND_TEST(ConfigUpdateTest, TestUpdateAlerts); }; } // namespace statsd diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp index ee4e1672411f..62f49824b874 100644 --- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp +++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp @@ -30,7 +30,7 @@ MaxDurationTracker::MaxDurationTracker(const ConfigKey& key, const int64_t& id, int64_t currentBucketStartNs, int64_t currentBucketNum, int64_t startTimeNs, int64_t bucketSizeNs, bool conditionSliced, bool fullLink, - const vector<sp<DurationAnomalyTracker>>& anomalyTrackers) + const vector<sp<AnomalyTracker>>& anomalyTrackers) : DurationTracker(key, id, eventKey, wizard, conditionIndex, nesting, currentBucketStartNs, currentBucketNum, startTimeNs, bucketSizeNs, conditionSliced, fullLink, anomalyTrackers) { @@ -288,7 +288,7 @@ void MaxDurationTracker::noteConditionChanged(const HashableDimensionKey& key, b // Note that we don't update mDuration here since it's only updated during noteStop. } -int64_t MaxDurationTracker::predictAnomalyTimestampNs(const DurationAnomalyTracker& anomalyTracker, +int64_t MaxDurationTracker::predictAnomalyTimestampNs(const AnomalyTracker& anomalyTracker, const int64_t currentTimestamp) const { // The allowed time we can continue in the current state is the // (anomaly threshold) - max(elapsed time of the started mInfos). diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h index 2891c6e1138a..be2707c60c1b 100644 --- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h +++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h @@ -29,12 +29,10 @@ namespace statsd { class MaxDurationTracker : public DurationTracker { public: MaxDurationTracker(const ConfigKey& key, const int64_t& id, const MetricDimensionKey& eventKey, - sp<ConditionWizard> wizard, int conditionIndex, - bool nesting, - int64_t currentBucketStartNs, int64_t currentBucketNum, - int64_t startTimeNs, int64_t bucketSizeNs, bool conditionSliced, - bool fullLink, - const std::vector<sp<DurationAnomalyTracker>>& anomalyTrackers); + sp<ConditionWizard> wizard, int conditionIndex, bool nesting, + int64_t currentBucketStartNs, int64_t currentBucketNum, int64_t startTimeNs, + int64_t bucketSizeNs, bool conditionSliced, bool fullLink, + const std::vector<sp<AnomalyTracker>>& anomalyTrackers); MaxDurationTracker(const MaxDurationTracker& tracker) = default; @@ -57,7 +55,7 @@ public: void onStateChanged(const int64_t timestamp, const int32_t atomId, const FieldValue& newState) override; - int64_t predictAnomalyTimestampNs(const DurationAnomalyTracker& anomalyTracker, + int64_t predictAnomalyTimestampNs(const AnomalyTracker& anomalyTracker, const int64_t currentTimestamp) const override; void dumpStates(FILE* out, bool verbose) const override; diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp index 0d49bbc269a3..247e2e01c992 100644 --- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp +++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp @@ -28,7 +28,7 @@ OringDurationTracker::OringDurationTracker( const ConfigKey& key, const int64_t& id, const MetricDimensionKey& eventKey, sp<ConditionWizard> wizard, int conditionIndex, bool nesting, int64_t currentBucketStartNs, int64_t currentBucketNum, int64_t startTimeNs, int64_t bucketSizeNs, bool conditionSliced, - bool fullLink, const vector<sp<DurationAnomalyTracker>>& anomalyTrackers) + bool fullLink, const vector<sp<AnomalyTracker>>& anomalyTrackers) : DurationTracker(key, id, eventKey, wizard, conditionIndex, nesting, currentBucketStartNs, currentBucketNum, startTimeNs, bucketSizeNs, conditionSliced, fullLink, anomalyTrackers), @@ -344,9 +344,8 @@ void OringDurationTracker::onStateChanged(const int64_t timestamp, const int32_t updateCurrentStateKey(atomId, newState); } -int64_t OringDurationTracker::predictAnomalyTimestampNs( - const DurationAnomalyTracker& anomalyTracker, const int64_t eventTimestampNs) const { - +int64_t OringDurationTracker::predictAnomalyTimestampNs(const AnomalyTracker& anomalyTracker, + const int64_t eventTimestampNs) const { // The anomaly threshold. const int64_t thresholdNs = anomalyTracker.getAnomalyThreshold(); diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h index bd8017a7decd..6eddee7da252 100644 --- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h +++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h @@ -31,7 +31,7 @@ public: int conditionIndex, bool nesting, int64_t currentBucketStartNs, int64_t currentBucketNum, int64_t startTimeNs, int64_t bucketSizeNs, bool conditionSliced, bool fullLink, - const std::vector<sp<DurationAnomalyTracker>>& anomalyTrackers); + const std::vector<sp<AnomalyTracker>>& anomalyTrackers); OringDurationTracker(const OringDurationTracker& tracker) = default; @@ -54,7 +54,7 @@ public: int64_t timestampNs, std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>* output) override; - int64_t predictAnomalyTimestampNs(const DurationAnomalyTracker& anomalyTracker, + int64_t predictAnomalyTimestampNs(const AnomalyTracker& anomalyTracker, const int64_t currentTimestamp) const override; void dumpStates(FILE* out, bool verbose) const override; diff --git a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp index 335f7753e5e3..637236145bf5 100644 --- a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp +++ b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp @@ -115,7 +115,6 @@ bool updateAtomMatchingTrackers(const StatsdConfig& config, const sp<UidMap>& ui vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers, set<int64_t>& replacedMatchers) { const int atomMatcherCount = config.atom_matcher_size(); - vector<AtomMatcher> matcherProtos; matcherProtos.reserve(atomMatcherCount); newAtomMatchingTrackers.reserve(atomMatcherCount); @@ -891,6 +890,111 @@ bool updateMetrics(const ConfigKey& key, const StatsdConfig& config, const int64 return true; } +bool determineAlertUpdateStatus(const Alert& alert, + const unordered_map<int64_t, int>& oldAlertTrackerMap, + const vector<sp<AnomalyTracker>>& oldAnomalyTrackers, + const set<int64_t>& replacedMetrics, UpdateStatus& updateStatus) { + // Check if new alert. + const auto& oldAnomalyTrackerIt = oldAlertTrackerMap.find(alert.id()); + if (oldAnomalyTrackerIt == oldAlertTrackerMap.end()) { + updateStatus = UPDATE_NEW; + return true; + } + + // This is an existing alert, check if it has changed. + string serializedAlert; + if (!alert.SerializeToString(&serializedAlert)) { + ALOGW("Unable to serialize alert %lld", (long long)alert.id()); + return false; + } + uint64_t newProtoHash = Hash64(serializedAlert); + const auto [success, oldProtoHash] = + oldAnomalyTrackers[oldAnomalyTrackerIt->second]->getProtoHash(); + if (!success) { + return false; + } + if (newProtoHash != oldProtoHash) { + updateStatus = UPDATE_REPLACE; + return true; + } + + // Check if the metric this alert relies on has changed. + if (replacedMetrics.find(alert.metric_id()) != replacedMetrics.end()) { + updateStatus = UPDATE_REPLACE; + return true; + } + + updateStatus = UPDATE_PRESERVE; + return true; +} + +bool updateAlerts(const StatsdConfig& config, const unordered_map<int64_t, int>& metricProducerMap, + const set<int64_t>& replacedMetrics, + const unordered_map<int64_t, int>& oldAlertTrackerMap, + const vector<sp<AnomalyTracker>>& oldAnomalyTrackers, + const sp<AlarmMonitor>& anomalyAlarmMonitor, + vector<sp<MetricProducer>>& allMetricProducers, + unordered_map<int64_t, int>& newAlertTrackerMap, + vector<sp<AnomalyTracker>>& newAnomalyTrackers) { + int alertCount = config.alert_size(); + vector<UpdateStatus> alertUpdateStatuses(alertCount); + for (int i = 0; i < alertCount; i++) { + if (!determineAlertUpdateStatus(config.alert(i), oldAlertTrackerMap, oldAnomalyTrackers, + replacedMetrics, alertUpdateStatuses[i])) { + return false; + } + } + + for (int i = 0; i < alertCount; i++) { + const Alert& alert = config.alert(i); + newAlertTrackerMap[alert.id()] = newAnomalyTrackers.size(); + switch (alertUpdateStatuses[i]) { + case UPDATE_PRESERVE: { + // Find the alert and update it. + const auto& oldAnomalyTrackerIt = oldAlertTrackerMap.find(alert.id()); + if (oldAnomalyTrackerIt == oldAlertTrackerMap.end()) { + ALOGW("Could not find AnomalyTracker %lld in the previous config, but " + "expected it to be there", + (long long)alert.id()); + return false; + } + sp<AnomalyTracker> anomalyTracker = oldAnomalyTrackers[oldAnomalyTrackerIt->second]; + anomalyTracker->onConfigUpdated(); + // Add the alert to the relevant metric. + const auto& metricProducerIt = metricProducerMap.find(alert.metric_id()); + if (metricProducerIt == metricProducerMap.end()) { + ALOGW("alert \"%lld\" has unknown metric id: \"%lld\"", (long long)alert.id(), + (long long)alert.metric_id()); + return false; + } + allMetricProducers[metricProducerIt->second]->addAnomalyTracker(anomalyTracker); + newAnomalyTrackers.push_back(anomalyTracker); + break; + } + case UPDATE_REPLACE: + case UPDATE_NEW: { + optional<sp<AnomalyTracker>> anomalyTracker = createAnomalyTracker( + alert, anomalyAlarmMonitor, metricProducerMap, allMetricProducers); + if (!anomalyTracker) { + return false; + } + newAnomalyTrackers.push_back(anomalyTracker.value()); + break; + } + default: { + ALOGE("Alert \"%lld\" update state is unknown. This should never happen", + (long long)alert.id()); + return false; + } + } + } + if (!initSubscribersForSubscriptionType(config, Subscription::ALERT, newAlertTrackerMap, + newAnomalyTrackers)) { + return false; + } + return true; +} + bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap, const sp<StatsPullerManager>& pullerManager, const sp<AlarmMonitor>& anomalyAlarmMonitor, @@ -902,6 +1006,8 @@ bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const const unordered_map<int64_t, int>& oldConditionTrackerMap, const vector<sp<MetricProducer>>& oldMetricProducers, const unordered_map<int64_t, int>& oldMetricProducerMap, + const vector<sp<AnomalyTracker>>& oldAnomalyTrackers, + const unordered_map<int64_t, int>& oldAlertTrackerMap, const map<int64_t, uint64_t>& oldStateProtoHashes, set<int>& allTagIds, vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers, unordered_map<int64_t, int>& newAtomMatchingTrackerMap, @@ -909,6 +1015,9 @@ bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const unordered_map<int64_t, int>& newConditionTrackerMap, vector<sp<MetricProducer>>& newMetricProducers, unordered_map<int64_t, int>& newMetricProducerMap, + vector<sp<AnomalyTracker>>& newAnomalyTrackers, + unordered_map<int64_t, int>& newAlertTrackerMap, + vector<sp<AlarmTracker>>& newPeriodicAlarmTrackers, unordered_map<int, vector<int>>& conditionToMetricMap, unordered_map<int, vector<int>>& trackerToMetricMap, unordered_map<int, vector<int>>& trackerToConditionMap, @@ -962,10 +1071,23 @@ bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const newMetricProducerMap, newMetricProducers, conditionToMetricMap, trackerToMetricMap, noReportMetricIds, activationTrackerToMetricMap, deactivationTrackerToMetricMap, metricsWithActivation, replacedMetrics)) { - ALOGE("initMetricProducers failed"); + ALOGE("updateMetrics failed"); + return false; + } + + if (!updateAlerts(config, newMetricProducerMap, replacedMetrics, oldAlertTrackerMap, + oldAnomalyTrackers, anomalyAlarmMonitor, newMetricProducers, + newAlertTrackerMap, newAnomalyTrackers)) { + ALOGE("updateAlerts failed"); return false; } + // Alarms do not have any state, so we can reuse the initialization logic. + if (!initAlarms(config, key, periodicAlarmMonitor, timeBaseNs, currentTimeNs, + newPeriodicAlarmTrackers)) { + ALOGE("initAlarms failed"); + return false; + } return true; } diff --git a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h index 3f1c5326b569..178a9d220b4d 100644 --- a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h +++ b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h @@ -19,6 +19,7 @@ #include <vector> #include "anomaly/AlarmMonitor.h" +#include "anomaly/AlarmTracker.h" #include "condition/ConditionTracker.h" #include "external/StatsPullerManager.h" #include "matchers/AtomMatchingTracker.h" @@ -189,6 +190,45 @@ bool updateMetrics( std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap, std::vector<int>& metricsWithActivation, std::set<int64_t>& replacedMetrics); +// Function to determine the update status (preserve/replace/new) of an alert. +// [alert]: the input Alert +// [oldAlertTrackerMap]: alert id to index mapping in the existing MetricsManager +// [oldAnomalyTrackers]: stores the existing AnomalyTrackers +// [replacedMetrics]: set of replaced metric ids. alerts using these metrics must be replaced +// output: +// [updateStatus]: update status of the alert. Will be changed from UPDATE_UNKNOWN +// Returns whether the function was successful or not. +bool determineAlertUpdateStatus(const Alert& alert, + const std::unordered_map<int64_t, int>& oldAlertTrackerMap, + const std::vector<sp<AnomalyTracker>>& oldAnomalyTrackers, + const std::set<int64_t>& replacedMetrics, + UpdateStatus& updateStatus); + +// Update MetricProducers. +// input: +// [config]: the input config +// [metricProducerMap]: metric id to index mapping in the new config +// [replacedMetrics]: set of metric ids that have changed and were replaced +// [oldAlertTrackerMap]: alert id to index mapping in the existing MetricsManager. +// [oldAnomalyTrackers]: stores the existing AnomalyTrackers +// [anomalyAlarmMonitor]: AlarmMonitor used for duration metric anomaly detection +// [allMetricProducers]: stores the sp of the metric producers, AnomalyTrackers need to be added. +// [stateAtomIdMap]: contains the mapping from state ids to atom ids +// [allStateGroupMaps]: contains the mapping from atom ids and state values to +// state group ids for all states +// output: +// [newAlertTrackerMap]: mapping of alert id to index in the new config +// [newAnomalyTrackers]: contains the list of sp to the AnomalyTrackers created. +bool updateAlerts(const StatsdConfig& config, + const std::unordered_map<int64_t, int>& metricProducerMap, + const std::set<int64_t>& replacedMetrics, + const std::unordered_map<int64_t, int>& oldAlertTrackerMap, + const std::vector<sp<AnomalyTracker>>& oldAnomalyTrackers, + const sp<AlarmMonitor>& anomalyAlarmMonitor, + std::vector<sp<MetricProducer>>& allMetricProducers, + std::unordered_map<int64_t, int>& newAlertTrackerMap, + std::vector<sp<AnomalyTracker>>& newAnomalyTrackers); + // Updates the existing MetricsManager from a new StatsdConfig. // Parameters are the members of MetricsManager. See MetricsManager for declaration. bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap, @@ -202,6 +242,8 @@ bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const const std::unordered_map<int64_t, int>& oldConditionTrackerMap, const std::vector<sp<MetricProducer>>& oldMetricProducers, const std::unordered_map<int64_t, int>& oldMetricProducerMap, + const std::vector<sp<AnomalyTracker>>& oldAnomalyTrackers, + const std::unordered_map<int64_t, int>& oldAlertTrackerMap, const std::map<int64_t, uint64_t>& oldStateProtoHashes, std::set<int>& allTagIds, std::vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers, @@ -210,6 +252,9 @@ bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const std::unordered_map<int64_t, int>& newConditionTrackerMap, std::vector<sp<MetricProducer>>& newMetricProducers, std::unordered_map<int64_t, int>& newMetricProducerMap, + std::vector<sp<AnomalyTracker>>& newAlertTrackers, + std::unordered_map<int64_t, int>& newAlertTrackerMap, + std::vector<sp<AlarmTracker>>& newPeriodicAlarmTrackers, std::unordered_map<int, std::vector<int>>& conditionToMetricMap, std::unordered_map<int, std::vector<int>>& trackerToMetricMap, std::unordered_map<int, std::vector<int>>& trackerToConditionMap, diff --git a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp index 8fc039a7d6b3..4474df4346cf 100644 --- a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp +++ b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp @@ -814,6 +814,35 @@ optional<sp<MetricProducer>> createGaugeMetricProducerAndUpdateMetadata( pullerManager, eventActivationMap, eventDeactivationMap)}; } +optional<sp<AnomalyTracker>> createAnomalyTracker( + const Alert& alert, const sp<AlarmMonitor>& anomalyAlarmMonitor, + const unordered_map<int64_t, int>& metricProducerMap, + vector<sp<MetricProducer>>& allMetricProducers) { + const auto& itr = metricProducerMap.find(alert.metric_id()); + if (itr == metricProducerMap.end()) { + ALOGW("alert \"%lld\" has unknown metric id: \"%lld\"", (long long)alert.id(), + (long long)alert.metric_id()); + return nullopt; + } + if (!alert.has_trigger_if_sum_gt()) { + ALOGW("invalid alert: missing threshold"); + return nullopt; + } + if (alert.trigger_if_sum_gt() < 0 || alert.num_buckets() <= 0) { + ALOGW("invalid alert: threshold=%f num_buckets= %d", alert.trigger_if_sum_gt(), + alert.num_buckets()); + return nullopt; + } + const int metricIndex = itr->second; + sp<MetricProducer> metric = allMetricProducers[metricIndex]; + sp<AnomalyTracker> anomalyTracker = metric->addAnomalyTracker(alert, anomalyAlarmMonitor); + if (anomalyTracker == nullptr) { + // The ALOGW for this invalid alert was already displayed in addAnomalyTracker(). + return nullopt; + } + return {anomalyTracker}; +} + bool initAtomMatchingTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap, unordered_map<int64_t, int>& atomMatchingTrackerMap, vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers, @@ -1079,49 +1108,17 @@ bool initAlerts(const StatsdConfig& config, const unordered_map<int64_t, int>& m vector<sp<AnomalyTracker>>& allAnomalyTrackers) { for (int i = 0; i < config.alert_size(); i++) { const Alert& alert = config.alert(i); - const auto& itr = metricProducerMap.find(alert.metric_id()); - if (itr == metricProducerMap.end()) { - ALOGW("alert \"%lld\" has unknown metric id: \"%lld\"", (long long)alert.id(), - (long long)alert.metric_id()); - return false; - } - if (!alert.has_trigger_if_sum_gt()) { - ALOGW("invalid alert: missing threshold"); - return false; - } - if (alert.trigger_if_sum_gt() < 0 || alert.num_buckets() <= 0) { - ALOGW("invalid alert: threshold=%f num_buckets= %d", alert.trigger_if_sum_gt(), - alert.num_buckets()); - return false; - } - const int metricIndex = itr->second; - sp<MetricProducer> metric = allMetricProducers[metricIndex]; - sp<AnomalyTracker> anomalyTracker = metric->addAnomalyTracker(alert, anomalyAlarmMonitor); - if (anomalyTracker == nullptr) { - // The ALOGW for this invalid alert was already displayed in addAnomalyTracker(). - return false; - } alertTrackerMap.insert(std::make_pair(alert.id(), allAnomalyTrackers.size())); - allAnomalyTrackers.push_back(anomalyTracker); - } - for (int i = 0; i < config.subscription_size(); ++i) { - const Subscription& subscription = config.subscription(i); - if (subscription.rule_type() != Subscription::ALERT) { - continue; - } - if (subscription.subscriber_information_case() == - Subscription::SubscriberInformationCase::SUBSCRIBER_INFORMATION_NOT_SET) { - ALOGW("subscription \"%lld\" has no subscriber info.\"", (long long)subscription.id()); - return false; - } - const auto& itr = alertTrackerMap.find(subscription.rule_id()); - if (itr == alertTrackerMap.end()) { - ALOGW("subscription \"%lld\" has unknown rule id: \"%lld\"", - (long long)subscription.id(), (long long)subscription.rule_id()); + optional<sp<AnomalyTracker>> anomalyTracker = createAnomalyTracker( + alert, anomalyAlarmMonitor, metricProducerMap, allMetricProducers); + if (!anomalyTracker) { return false; } - const int anomalyTrackerIndex = itr->second; - allAnomalyTrackers[anomalyTrackerIndex]->addSubscription(subscription); + allAnomalyTrackers.push_back(anomalyTracker.value()); + } + if (!initSubscribersForSubscriptionType(config, Subscription::ALERT, alertTrackerMap, + allAnomalyTrackers)) { + return false; } return true; } @@ -1146,24 +1143,9 @@ bool initAlarms(const StatsdConfig& config, const ConfigKey& key, allAlarmTrackers.push_back( new AlarmTracker(startMillis, currentTimeMillis, alarm, key, periodicAlarmMonitor)); } - for (int i = 0; i < config.subscription_size(); ++i) { - const Subscription& subscription = config.subscription(i); - if (subscription.rule_type() != Subscription::ALARM) { - continue; - } - if (subscription.subscriber_information_case() == - Subscription::SubscriberInformationCase::SUBSCRIBER_INFORMATION_NOT_SET) { - ALOGW("subscription \"%lld\" has no subscriber info.\"", (long long)subscription.id()); - return false; - } - const auto& itr = alarmTrackerMap.find(subscription.rule_id()); - if (itr == alarmTrackerMap.end()) { - ALOGW("subscription \"%lld\" has unknown rule id: \"%lld\"", - (long long)subscription.id(), (long long)subscription.rule_id()); - return false; - } - const int trackerIndex = itr->second; - allAlarmTrackers[trackerIndex]->addSubscription(subscription); + if (!initSubscribersForSubscriptionType(config, Subscription::ALARM, alarmTrackerMap, + allAlarmTrackers)) { + return false; } return true; } diff --git a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h index e4585cd578f8..84e1e4e04339 100644 --- a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h +++ b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h @@ -188,6 +188,41 @@ optional<sp<MetricProducer>> createGaugeMetricProducerAndUpdateMetadata( std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap, std::vector<int>& metricsWithActivation); +// Creates an AnomalyTracker and adds it to the appropriate metric. +// Returns an sp to the AnomalyTracker, or nullopt if there was an error. +optional<sp<AnomalyTracker>> createAnomalyTracker( + const Alert& alert, const sp<AlarmMonitor>& anomalyAlarmMonitor, + const std::unordered_map<int64_t, int>& metricProducerMap, + std::vector<sp<MetricProducer>>& allMetricProducers); + +// Templated function for adding subscriptions to alarms or alerts. Returns true if successful. +template <typename T> +bool initSubscribersForSubscriptionType(const StatsdConfig& config, + const Subscription_RuleType ruleType, + const std::unordered_map<int64_t, int>& ruleMap, + std::vector<T>& allRules) { + for (int i = 0; i < config.subscription_size(); ++i) { + const Subscription& subscription = config.subscription(i); + if (subscription.rule_type() != ruleType) { + continue; + } + if (subscription.subscriber_information_case() == + Subscription::SubscriberInformationCase::SUBSCRIBER_INFORMATION_NOT_SET) { + ALOGW("subscription \"%lld\" has no subscriber info.\"", (long long)subscription.id()); + return false; + } + const auto& itr = ruleMap.find(subscription.rule_id()); + if (itr == ruleMap.end()) { + ALOGW("subscription \"%lld\" has unknown rule id: \"%lld\"", + (long long)subscription.id(), (long long)subscription.rule_id()); + return false; + } + const int ruleIndex = itr->second; + allRules[ruleIndex]->addSubscription(subscription); + } + return true; +} + // Helper functions for MetricsManager to initialize from StatsdConfig. // *Note*: only initStatsdConfig() should be called from outside. // All other functions are intermediate @@ -271,6 +306,12 @@ bool initMetrics( std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap, std::vector<int>& metricsWithActivation); +// Initialize alarms +// Is called both on initialize new configs and config updates since alarms do not have any state. +bool initAlarms(const StatsdConfig& config, const ConfigKey& key, + const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs, + const int64_t currentTimeNs, std::vector<sp<AlarmTracker>>& allAlarmTrackers); + // Initialize MetricsManager from StatsdConfig. // Parameters are the members of MetricsManager. See MetricsManager for declaration. bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap, diff --git a/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp b/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp index 4fa9bf6ffc01..66bab4ea70da 100644 --- a/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp +++ b/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp @@ -52,11 +52,15 @@ namespace statsd { namespace { ConfigKey key(123, 456); -const int64_t timeBaseNs = 1000; +const int64_t timeBaseNs = 1000 * NS_PER_SEC; + sp<UidMap> uidMap = new UidMap(); sp<StatsPullerManager> pullerManager = new StatsPullerManager(); sp<AlarmMonitor> anomalyAlarmMonitor; -sp<AlarmMonitor> periodicAlarmMonitor; +sp<AlarmMonitor> periodicAlarmMonitor = new AlarmMonitor( + /*minDiffToUpdateRegisteredAlarmTimeSec=*/0, + [](const shared_ptr<IStatsCompanionService>&, int64_t) {}, + [](const shared_ptr<IStatsCompanionService>&) {}); set<int> allTagIds; vector<sp<AtomMatchingTracker>> oldAtomMatchingTrackers; unordered_map<int64_t, int> oldAtomMatchingTrackerMap; @@ -65,13 +69,13 @@ unordered_map<int64_t, int> oldConditionTrackerMap; vector<sp<MetricProducer>> oldMetricProducers; unordered_map<int64_t, int> oldMetricProducerMap; std::vector<sp<AnomalyTracker>> oldAnomalyTrackers; +unordered_map<int64_t, int> oldAlertTrackerMap; std::vector<sp<AlarmTracker>> oldAlarmTrackers; unordered_map<int, std::vector<int>> tmpConditionToMetricMap; unordered_map<int, std::vector<int>> tmpTrackerToMetricMap; unordered_map<int, std::vector<int>> tmpTrackerToConditionMap; unordered_map<int, std::vector<int>> tmpActivationAtomTrackerToMetricMap; unordered_map<int, std::vector<int>> tmpDeactivationAtomTrackerToMetricMap; -unordered_map<int64_t, int> alertTrackerMap; vector<int> metricsWithActivation; map<int64_t, uint64_t> oldStateHashes; std::set<int64_t> noReportMetricIds; @@ -96,7 +100,7 @@ public: tmpTrackerToConditionMap.clear(); tmpActivationAtomTrackerToMetricMap.clear(); tmpDeactivationAtomTrackerToMetricMap.clear(); - alertTrackerMap.clear(); + oldAlertTrackerMap.clear(); metricsWithActivation.clear(); oldStateHashes.clear(); noReportMetricIds.clear(); @@ -111,7 +115,7 @@ bool initConfig(const StatsdConfig& config) { oldConditionTrackers, oldConditionTrackerMap, oldMetricProducers, oldMetricProducerMap, oldAnomalyTrackers, oldAlarmTrackers, tmpConditionToMetricMap, tmpTrackerToMetricMap, tmpTrackerToConditionMap, tmpActivationAtomTrackerToMetricMap, - tmpDeactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation, + tmpDeactivationAtomTrackerToMetricMap, oldAlertTrackerMap, metricsWithActivation, oldStateHashes, noReportMetricIds); } @@ -188,6 +192,32 @@ ValueMetric createValueMetric(string name, const AtomMatcher& what, optional<int } return metric; } + +Alert createAlert(string name, int64_t metricId, int buckets, int64_t triggerSum) { + Alert alert; + alert.set_id(StringToId(name)); + alert.set_metric_id(metricId); + alert.set_num_buckets(buckets); + alert.set_trigger_if_sum_gt(triggerSum); + return alert; +} + +Subscription createSubscription(string name, Subscription_RuleType type, int64_t ruleId) { + Subscription subscription; + subscription.set_id(StringToId(name)); + subscription.set_rule_type(type); + subscription.set_rule_id(ruleId); + subscription.mutable_broadcast_subscriber_details(); + return subscription; +} + +Alarm createAlarm(string name, int64_t offsetMillis, int64_t periodMillis) { + Alarm alarm; + alarm.set_id(StringToId(name)); + alarm.set_offset_millis(offsetMillis); + alarm.set_period_millis(periodMillis); + return alarm; +} } // anonymous namespace TEST_F(ConfigUpdateTest, TestSimpleMatcherPreserve) { @@ -3243,6 +3273,305 @@ TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) { // Only reference to the old wizard should be the one in the test. EXPECT_EQ(oldConditionWizard->getStrongCount(), 1); } + +TEST_F(ConfigUpdateTest, TestAlertPreserve) { + StatsdConfig config; + AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher(); + *config.add_atom_matcher() = whatMatcher; + + *config.add_count_metric() = createCountMetric("VALUE1", whatMatcher.id(), nullopt, {}); + + Alert alert = createAlert("Alert1", config.count_metric(0).id(), 1, 1); + *config.add_alert() = alert; + EXPECT_TRUE(initConfig(config)); + + UpdateStatus updateStatus = UPDATE_UNKNOWN; + EXPECT_TRUE(determineAlertUpdateStatus(alert, oldAlertTrackerMap, oldAnomalyTrackers, + /*replacedMetrics*/ {}, updateStatus)); + EXPECT_EQ(updateStatus, UPDATE_PRESERVE); +} + +TEST_F(ConfigUpdateTest, TestAlertMetricChanged) { + StatsdConfig config; + AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher(); + *config.add_atom_matcher() = whatMatcher; + + CountMetric metric = createCountMetric("VALUE1", whatMatcher.id(), nullopt, {}); + *config.add_count_metric() = metric; + + Alert alert = createAlert("Alert1", config.count_metric(0).id(), 1, 1); + *config.add_alert() = alert; + EXPECT_TRUE(initConfig(config)); + + UpdateStatus updateStatus = UPDATE_UNKNOWN; + EXPECT_TRUE(determineAlertUpdateStatus(alert, oldAlertTrackerMap, oldAnomalyTrackers, + /*replacedMetrics*/ {metric.id()}, updateStatus)); + EXPECT_EQ(updateStatus, UPDATE_REPLACE); +} + +TEST_F(ConfigUpdateTest, TestAlertDefinitionChanged) { + StatsdConfig config; + AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher(); + *config.add_atom_matcher() = whatMatcher; + + *config.add_count_metric() = createCountMetric("VALUE1", whatMatcher.id(), nullopt, {}); + + Alert alert = createAlert("Alert1", config.count_metric(0).id(), 1, 1); + *config.add_alert() = alert; + EXPECT_TRUE(initConfig(config)); + + alert.set_num_buckets(2); + + UpdateStatus updateStatus = UPDATE_UNKNOWN; + EXPECT_TRUE(determineAlertUpdateStatus(alert, oldAlertTrackerMap, oldAnomalyTrackers, + /*replacedMetrics*/ {}, updateStatus)); + EXPECT_EQ(updateStatus, UPDATE_REPLACE); +} + +TEST_F(ConfigUpdateTest, TestUpdateAlerts) { + StatsdConfig config; + // Add atom matchers/predicates/metrics. These are mostly needed for initStatsdConfig + *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher(); + *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher(); + *config.add_predicate() = CreateScreenIsOnPredicate(); + + CountMetric countMetric = createCountMetric("COUNT1", config.atom_matcher(0).id(), nullopt, {}); + int64_t countMetricId = countMetric.id(); + *config.add_count_metric() = countMetric; + + DurationMetric durationMetric = + createDurationMetric("DURATION1", config.predicate(0).id(), nullopt, {}); + int64_t durationMetricId = durationMetric.id(); + *config.add_duration_metric() = durationMetric; + + // Add alerts. + // Preserved. + Alert alert1 = createAlert("Alert1", durationMetricId, /*buckets*/ 1, /*triggerSum*/ 5000); + int64_t alert1Id = alert1.id(); + *config.add_alert() = alert1; + + // Replaced. + Alert alert2 = createAlert("Alert2", countMetricId, /*buckets*/ 1, /*triggerSum*/ 2); + int64_t alert2Id = alert2.id(); + *config.add_alert() = alert2; + + // Replaced. + Alert alert3 = createAlert("Alert3", durationMetricId, /*buckets*/ 3, /*triggerSum*/ 5000); + int64_t alert3Id = alert3.id(); + *config.add_alert() = alert3; + + // Add Subscriptions. + Subscription subscription1 = createSubscription("S1", Subscription::ALERT, alert1Id); + *config.add_subscription() = subscription1; + Subscription subscription2 = createSubscription("S2", Subscription::ALERT, alert1Id); + *config.add_subscription() = subscription2; + Subscription subscription3 = createSubscription("S3", Subscription::ALERT, alert2Id); + *config.add_subscription() = subscription3; + + EXPECT_TRUE(initConfig(config)); + + // Add a duration tracker to the duration metric to ensure durationTrackers are updated + // with the proper anomalyTrackers. + unique_ptr<LogEvent> event = CreateScreenStateChangedEvent( + timeBaseNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_ON); + oldMetricProducers[1]->onMatchedLogEvent(0, *event.get()); + + // Change the count metric. Causes alert2 to be replaced. + config.mutable_count_metric(0)->set_bucket(ONE_DAY); + // Change num buckets on alert3, causing replacement. + alert3.set_num_buckets(5); + + // New alert. + Alert alert4 = createAlert("Alert4", durationMetricId, /*buckets*/ 3, /*triggerSum*/ 10000); + int64_t alert4Id = alert4.id(); + + // Move subscription2 to be on alert2 and make a new subscription. + subscription2.set_rule_id(alert2Id); + Subscription subscription4 = createSubscription("S4", Subscription::ALERT, alert2Id); + + // Create the new config. Modify the old one to avoid adding the matchers/predicates. + // Add alerts in different order so the map is changed. + config.clear_alert(); + *config.add_alert() = alert4; + const int alert4Index = 0; + *config.add_alert() = alert3; + const int alert3Index = 1; + *config.add_alert() = alert1; + const int alert1Index = 2; + *config.add_alert() = alert2; + const int alert2Index = 3; + + // Subscription3 is removed. + config.clear_subscription(); + *config.add_subscription() = subscription4; + *config.add_subscription() = subscription2; + *config.add_subscription() = subscription1; + + // Output data structures from update metrics. Don't care about the outputs besides + // replacedMetrics, but need to do this so that the metrics clear their anomaly trackers. + unordered_map<int64_t, int> newMetricProducerMap; + vector<sp<MetricProducer>> newMetricProducers; + unordered_map<int, vector<int>> conditionToMetricMap; + unordered_map<int, vector<int>> trackerToMetricMap; + set<int64_t> noReportMetricIds; + unordered_map<int, vector<int>> activationAtomTrackerToMetricMap; + unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap; + vector<int> metricsWithActivation; + set<int64_t> replacedMetrics; + EXPECT_TRUE(updateMetrics( + key, config, /*timeBaseNs=*/123, /*currentTimeNs=*/12345, new StatsPullerManager(), + oldAtomMatchingTrackerMap, oldAtomMatchingTrackerMap, /*replacedMatchers*/ {}, + oldAtomMatchingTrackers, oldConditionTrackerMap, /*replacedConditions=*/{}, + oldConditionTrackers, {ConditionState::kUnknown}, /*stateAtomIdMap*/ {}, + /*allStateGroupMaps=*/{}, + /*replacedStates=*/{}, oldMetricProducerMap, oldMetricProducers, newMetricProducerMap, + newMetricProducers, conditionToMetricMap, trackerToMetricMap, noReportMetricIds, + activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, + metricsWithActivation, replacedMetrics)); + + EXPECT_EQ(replacedMetrics, set<int64_t>({countMetricId})); + + unordered_map<int64_t, int> newAlertTrackerMap; + vector<sp<AnomalyTracker>> newAnomalyTrackers; + EXPECT_TRUE(updateAlerts(config, newMetricProducerMap, replacedMetrics, oldAlertTrackerMap, + oldAnomalyTrackers, anomalyAlarmMonitor, newMetricProducers, + newAlertTrackerMap, newAnomalyTrackers)); + + unordered_map<int64_t, int> expectedAlertMap = { + {alert1Id, alert1Index}, + {alert2Id, alert2Index}, + {alert3Id, alert3Index}, + {alert4Id, alert4Index}, + }; + EXPECT_THAT(newAlertTrackerMap, ContainerEq(expectedAlertMap)); + + // Make sure preserved alerts are the same. + ASSERT_EQ(newAnomalyTrackers.size(), 4); + EXPECT_EQ(oldAnomalyTrackers[oldAlertTrackerMap.at(alert1Id)], + newAnomalyTrackers[newAlertTrackerMap.at(alert1Id)]); + + // Make sure replaced alerts are different. + EXPECT_NE(oldAnomalyTrackers[oldAlertTrackerMap.at(alert2Id)], + newAnomalyTrackers[newAlertTrackerMap.at(alert2Id)]); + EXPECT_NE(oldAnomalyTrackers[oldAlertTrackerMap.at(alert3Id)], + newAnomalyTrackers[newAlertTrackerMap.at(alert3Id)]); + + // Verify the alerts have the correct anomaly trackers. + ASSERT_EQ(newMetricProducers.size(), 2); + EXPECT_THAT(newMetricProducers[0]->mAnomalyTrackers, + UnorderedElementsAre(newAnomalyTrackers[alert2Index])); + // For durationMetric, make sure the duration trackers get the updated anomalyTrackers. + DurationMetricProducer* durationProducer = + static_cast<DurationMetricProducer*>(newMetricProducers[1].get()); + EXPECT_THAT( + durationProducer->mAnomalyTrackers, + UnorderedElementsAre(newAnomalyTrackers[alert1Index], newAnomalyTrackers[alert3Index], + newAnomalyTrackers[alert4Index])); + ASSERT_EQ(durationProducer->mCurrentSlicedDurationTrackerMap.size(), 1); + for (const auto& durationTrackerIt : durationProducer->mCurrentSlicedDurationTrackerMap) { + EXPECT_EQ(durationTrackerIt.second->mAnomalyTrackers, durationProducer->mAnomalyTrackers); + } + + // Verify alerts have the correct subscriptions. Use subscription id as proxy for equivalency. + vector<int64_t> alert1Subscriptions; + for (const Subscription& subscription : newAnomalyTrackers[alert1Index]->mSubscriptions) { + alert1Subscriptions.push_back(subscription.id()); + } + EXPECT_THAT(alert1Subscriptions, UnorderedElementsAre(subscription1.id())); + vector<int64_t> alert2Subscriptions; + for (const Subscription& subscription : newAnomalyTrackers[alert2Index]->mSubscriptions) { + alert2Subscriptions.push_back(subscription.id()); + } + EXPECT_THAT(alert2Subscriptions, UnorderedElementsAre(subscription2.id(), subscription4.id())); + EXPECT_THAT(newAnomalyTrackers[alert3Index]->mSubscriptions, IsEmpty()); + EXPECT_THAT(newAnomalyTrackers[alert4Index]->mSubscriptions, IsEmpty()); +} + +TEST_F(ConfigUpdateTest, TestUpdateAlarms) { + StatsdConfig config; + // Add alarms. + Alarm alarm1 = createAlarm("Alarm1", /*offset*/ 1 * MS_PER_SEC, /*period*/ 50 * MS_PER_SEC); + int64_t alarm1Id = alarm1.id(); + *config.add_alarm() = alarm1; + + Alarm alarm2 = createAlarm("Alarm2", /*offset*/ 1 * MS_PER_SEC, /*period*/ 2000 * MS_PER_SEC); + int64_t alarm2Id = alarm2.id(); + *config.add_alarm() = alarm2; + + Alarm alarm3 = createAlarm("Alarm3", /*offset*/ 10 * MS_PER_SEC, /*period*/ 5000 * MS_PER_SEC); + int64_t alarm3Id = alarm3.id(); + *config.add_alarm() = alarm3; + + // Add Subscriptions. + Subscription subscription1 = createSubscription("S1", Subscription::ALARM, alarm1Id); + *config.add_subscription() = subscription1; + Subscription subscription2 = createSubscription("S2", Subscription::ALARM, alarm1Id); + *config.add_subscription() = subscription2; + Subscription subscription3 = createSubscription("S3", Subscription::ALARM, alarm2Id); + *config.add_subscription() = subscription3; + + EXPECT_TRUE(initConfig(config)); + + ASSERT_EQ(oldAlarmTrackers.size(), 3); + // Config is created at statsd start time, so just add the offsets. + EXPECT_EQ(oldAlarmTrackers[0]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 1); + EXPECT_EQ(oldAlarmTrackers[1]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 1); + EXPECT_EQ(oldAlarmTrackers[2]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 10); + + // Change alarm2/alarm3. + config.mutable_alarm(1)->set_offset_millis(5 * MS_PER_SEC); + config.mutable_alarm(2)->set_period_millis(10000 * MS_PER_SEC); + + // Move subscription2 to be on alarm2 and make a new subscription. + config.mutable_subscription(1)->set_rule_id(alarm2Id); + Subscription subscription4 = createSubscription("S4", Subscription::ALARM, alarm1Id); + *config.add_subscription() = subscription4; + + // Update time is 2 seconds after the base time. + int64_t currentTimeNs = timeBaseNs + 2 * NS_PER_SEC; + vector<sp<AlarmTracker>> newAlarmTrackers; + EXPECT_TRUE(initAlarms(config, key, periodicAlarmMonitor, timeBaseNs, currentTimeNs, + newAlarmTrackers)); + + ASSERT_EQ(newAlarmTrackers.size(), 3); + // Config is updated 2 seconds after statsd start + // The offset has passed for alarm1, but not for alarms 2/3. + EXPECT_EQ(newAlarmTrackers[0]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 1 + 50); + EXPECT_EQ(newAlarmTrackers[1]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 5); + EXPECT_EQ(newAlarmTrackers[2]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 10); + + // Verify alarms have the correct subscriptions. Use subscription id as proxy for equivalency. + vector<int64_t> alarm1Subscriptions; + for (const Subscription& subscription : newAlarmTrackers[0]->mSubscriptions) { + alarm1Subscriptions.push_back(subscription.id()); + } + EXPECT_THAT(alarm1Subscriptions, UnorderedElementsAre(subscription1.id(), subscription4.id())); + vector<int64_t> alarm2Subscriptions; + for (const Subscription& subscription : newAlarmTrackers[1]->mSubscriptions) { + alarm2Subscriptions.push_back(subscription.id()); + } + EXPECT_THAT(alarm2Subscriptions, UnorderedElementsAre(subscription2.id(), subscription3.id())); + EXPECT_THAT(newAlarmTrackers[2]->mSubscriptions, IsEmpty()); + + // Verify the alarm monitor is updated accordingly once the old alarms are removed. + // Alarm2 fires the earliest. + oldAlarmTrackers.clear(); + EXPECT_EQ(periodicAlarmMonitor->getRegisteredAlarmTimeSec(), timeBaseNs / NS_PER_SEC + 5); + + // Do another update 60 seconds after config creation time, after the offsets of each alarm. + currentTimeNs = timeBaseNs + 60 * NS_PER_SEC; + newAlarmTrackers.clear(); + EXPECT_TRUE(initAlarms(config, key, periodicAlarmMonitor, timeBaseNs, currentTimeNs, + newAlarmTrackers)); + + ASSERT_EQ(newAlarmTrackers.size(), 3); + // Config is updated one minute after statsd start. + // Two periods have passed for alarm 1, one has passed for alarms2/3. + EXPECT_EQ(newAlarmTrackers[0]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 1 + 2 * 50); + EXPECT_EQ(newAlarmTrackers[1]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 5 + 2000); + EXPECT_EQ(newAlarmTrackers[2]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 10 + 10000); +} + } // namespace statsd } // namespace os } // namespace android diff --git a/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp b/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp index 0d0a8960043e..9e2350b33018 100644 --- a/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp +++ b/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp @@ -27,6 +27,7 @@ #include "src/condition/ConditionTracker.h" #include "src/matchers/AtomMatchingTracker.h" #include "src/metrics/CountMetricProducer.h" +#include "src/metrics/DurationMetricProducer.h" #include "src/metrics/GaugeMetricProducer.h" #include "src/metrics/MetricProducer.h" #include "src/metrics/ValueMetricProducer.h" @@ -793,6 +794,93 @@ TEST(MetricsManagerTest, TestCreateConditionTrackerCombination) { EXPECT_FALSE(tracker->IsSimpleCondition()); } +TEST(MetricsManagerTest, TestCreateAnomalyTrackerInvalidMetric) { + Alert alert; + alert.set_id(123); + alert.set_metric_id(1); + alert.set_trigger_if_sum_gt(1); + alert.set_num_buckets(1); + + sp<AlarmMonitor> anomalyAlarmMonitor; + vector<sp<MetricProducer>> metricProducers; + // Pass in empty metric producers, causing an error. + EXPECT_EQ(createAnomalyTracker(alert, anomalyAlarmMonitor, {}, metricProducers), nullopt); +} + +TEST(MetricsManagerTest, TestCreateAnomalyTrackerNoThreshold) { + int64_t metricId = 1; + Alert alert; + alert.set_id(123); + alert.set_metric_id(metricId); + alert.set_num_buckets(1); + + CountMetric metric; + metric.set_id(metricId); + metric.set_bucket(ONE_MINUTE); + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + vector<sp<MetricProducer>> metricProducers({new CountMetricProducer( + kConfigKey, metric, 0, {ConditionState::kUnknown}, wizard, 0x0123456789, 0, 0)}); + sp<AlarmMonitor> anomalyAlarmMonitor; + EXPECT_EQ(createAnomalyTracker(alert, anomalyAlarmMonitor, {{1, 0}}, metricProducers), nullopt); +} + +TEST(MetricsManagerTest, TestCreateAnomalyTrackerMissingBuckets) { + int64_t metricId = 1; + Alert alert; + alert.set_id(123); + alert.set_metric_id(metricId); + alert.set_trigger_if_sum_gt(1); + + CountMetric metric; + metric.set_id(metricId); + metric.set_bucket(ONE_MINUTE); + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + vector<sp<MetricProducer>> metricProducers({new CountMetricProducer( + kConfigKey, metric, 0, {ConditionState::kUnknown}, wizard, 0x0123456789, 0, 0)}); + sp<AlarmMonitor> anomalyAlarmMonitor; + EXPECT_EQ(createAnomalyTracker(alert, anomalyAlarmMonitor, {{1, 0}}, metricProducers), nullopt); +} + +TEST(MetricsManagerTest, TestCreateAnomalyTrackerGood) { + int64_t metricId = 1; + Alert alert; + alert.set_id(123); + alert.set_metric_id(metricId); + alert.set_trigger_if_sum_gt(1); + alert.set_num_buckets(1); + + CountMetric metric; + metric.set_id(metricId); + metric.set_bucket(ONE_MINUTE); + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + vector<sp<MetricProducer>> metricProducers({new CountMetricProducer( + kConfigKey, metric, 0, {ConditionState::kUnknown}, wizard, 0x0123456789, 0, 0)}); + sp<AlarmMonitor> anomalyAlarmMonitor; + EXPECT_NE(createAnomalyTracker(alert, anomalyAlarmMonitor, {{1, 0}}, metricProducers), nullopt); +} + +TEST(MetricsManagerTest, TestCreateAnomalyTrackerDurationTooLong) { + int64_t metricId = 1; + Alert alert; + alert.set_id(123); + alert.set_metric_id(metricId); + // Impossible for alert to fire since the time is bigger than bucketSize * numBuckets + alert.set_trigger_if_sum_gt(MillisToNano(TimeUnitToBucketSizeInMillis(ONE_MINUTE)) + 1); + alert.set_num_buckets(1); + + DurationMetric metric; + metric.set_id(metricId); + metric.set_bucket(ONE_MINUTE); + metric.set_aggregation_type(DurationMetric_AggregationType_SUM); + FieldMatcher dimensions; + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + vector<sp<MetricProducer>> metricProducers({new DurationMetricProducer( + kConfigKey, metric, -1 /*no condition*/, {}, 1 /* start index */, 2 /* stop index */, + 3 /* stop_all index */, false /*nesting*/, wizard, 0x0123456789, dimensions, 0, 0)}); + sp<AlarmMonitor> anomalyAlarmMonitor; + EXPECT_EQ(createAnomalyTracker(alert, anomalyAlarmMonitor, {{1, 0}}, metricProducers), nullopt); +} + } // namespace statsd } // namespace os } // namespace android diff --git a/core/api/current.txt b/core/api/current.txt index 16a5f5e82f21..05b57af1dccd 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -11718,10 +11718,9 @@ package android.content.pm { method public long getFirstInstallTime(); method public android.graphics.drawable.Drawable getIcon(int); method public CharSequence getLabel(); + method public float getLoadingProgress(); method public String getName(); - method public float getProgress(); method public android.os.UserHandle getUser(); - method public boolean isLoading(); method public boolean isStartable(); } @@ -11762,7 +11761,7 @@ package android.content.pm { ctor public LauncherApps.Callback(); method public abstract void onPackageAdded(String, android.os.UserHandle); method public abstract void onPackageChanged(String, android.os.UserHandle); - method public void onPackageProgressChanged(@NonNull String, @NonNull android.os.UserHandle, float); + method public void onPackageLoadingProgressChanged(@NonNull String, @NonNull android.os.UserHandle, float); method public abstract void onPackageRemoved(String, android.os.UserHandle); method public abstract void onPackagesAvailable(String[], android.os.UserHandle, boolean); method public void onPackagesSuspended(String[], android.os.UserHandle); diff --git a/core/api/system-current.txt b/core/api/system-current.txt index daa5414f3f72..18fdc0f4f705 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -5665,7 +5665,7 @@ package android.media.tv.tuner.frontend { method @NonNull public android.media.tv.tuner.frontend.AtscFrontendSettings.Builder setModulation(int); } - public class DtmbFrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities { + public final class DtmbFrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities { method public int getBandwidthCapability(); method public int getCodeRateCapability(); method public int getGuardIntervalCapability(); @@ -5674,7 +5674,7 @@ package android.media.tv.tuner.frontend { method public int getTransmissionModeCapability(); } - public class DtmbFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings { + public final class DtmbFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings { method @NonNull public static android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder builder(); method public int getBandwidth(); method public int getCodeRate(); diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java index 45e9c49c5322..43b7722c0864 100644 --- a/core/java/android/app/TaskInfo.java +++ b/core/java/android/app/TaskInfo.java @@ -16,6 +16,8 @@ package android.app; +import static android.app.ActivityTaskManager.INVALID_TASK_ID; + import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; @@ -204,6 +206,13 @@ public class TaskInfo { */ public ArrayList<IBinder> launchCookies = new ArrayList<>(); + /** + * The identifier of the parent task that is created by organizer, otherwise + * {@link ActivityTaskManager#INVALID_TASK_ID}. + * @hide + */ + public int parentTaskId; + TaskInfo() { // Do nothing } @@ -253,6 +262,12 @@ public class TaskInfo { launchCookies.add(cookie); } + /** @hide */ + @TestApi + public boolean hasParentTask() { + return parentTaskId != INVALID_TASK_ID; + } + /** * Reads the TaskInfo from a parcel. */ @@ -283,6 +298,7 @@ public class TaskInfo { source.readBinderList(launchCookies); letterboxActivityBounds = source.readTypedObject(Rect.CREATOR); positionInParent = source.readTypedObject(Point.CREATOR); + parentTaskId = source.readInt(); } /** @@ -316,6 +332,7 @@ public class TaskInfo { dest.writeBinderList(launchCookies); dest.writeTypedObject(letterboxActivityBounds, flags); dest.writeTypedObject(positionInParent, flags); + dest.writeInt(parentTaskId); } @Override @@ -338,6 +355,7 @@ public class TaskInfo { + " launchCookies" + launchCookies + " letterboxActivityBounds=" + letterboxActivityBounds + " positionInParent=" + positionInParent + + " parentTaskId: " + parentTaskId + "}"; } } diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java index c854abac291e..587e883edaf2 100644 --- a/core/java/android/app/backup/FullBackup.java +++ b/core/java/android/app/backup/FullBackup.java @@ -20,7 +20,6 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.XmlResourceParser; -import android.os.Build; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.storage.StorageManager; @@ -92,7 +91,7 @@ public class FullBackup { /** * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage static public native int backupToTar(String packageName, String domain, String linkdomain, String rootpath, String path, FullBackupDataOutput output); diff --git a/core/java/android/app/backup/OWNERS b/core/java/android/app/backup/OWNERS index 9c21e8fe5e45..7e7710b4d550 100644 --- a/core/java/android/app/backup/OWNERS +++ b/core/java/android/app/backup/OWNERS @@ -1,9 +1,4 @@ -alsutton@google.com -anniemeng@google.com -brufino@google.com -bryanmawhinney@google.com -ctate@google.com -jorlow@google.com -nathch@google.com -rthakohov@google.com +# Bug component: 656484 + +include platform/frameworks/base/services/backup:/OWNERS diff --git a/core/java/android/content/pm/IOnAppsChangedListener.aidl b/core/java/android/content/pm/IOnAppsChangedListener.aidl index f24ed80983f8..830cbe0e0dd0 100644 --- a/core/java/android/content/pm/IOnAppsChangedListener.aidl +++ b/core/java/android/content/pm/IOnAppsChangedListener.aidl @@ -33,5 +33,5 @@ oneway interface IOnAppsChangedListener { in Bundle launcherExtras); void onPackagesUnsuspended(in UserHandle user, in String[] packageNames); void onShortcutChanged(in UserHandle user, String packageName, in ParceledListSlice shortcuts); - void onPackageProgressChanged(in UserHandle user, String packageName, float progress); + void onPackageLoadingProgressChanged(in UserHandle user, String packageName, float progress); } diff --git a/core/java/android/content/pm/LauncherActivityInfo.java b/core/java/android/content/pm/LauncherActivityInfo.java index ead80d022542..fd96e85db3de 100644 --- a/core/java/android/content/pm/LauncherActivityInfo.java +++ b/core/java/android/content/pm/LauncherActivityInfo.java @@ -91,16 +91,9 @@ public class LauncherActivityInfo { } /** - * @return whether the package is still loading. + * @return Package loading progress, range between [0, 1]. */ - public boolean isLoading() { - return mInternal.getIncrementalStatesInfo().isLoading(); - } - - /** - * @return Package loading progress - */ - public float getProgress() { + public float getLoadingProgress() { return mInternal.getIncrementalStatesInfo().getProgress(); } diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java index 2909d66d72ff..c964b4b9bb53 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -17,7 +17,6 @@ package android.content.pm; import static android.Manifest.permission; -import static android.app.PendingIntent.FLAG_IMMUTABLE; import android.annotation.CallbackExecutor; import android.annotation.IntDef; @@ -333,7 +332,7 @@ public class LauncherApps { * @param user The UserHandle of the profile that generated the change. * @param progress The new progress value, between [0, 1]. */ - public void onPackageProgressChanged(@NonNull String packageName, + public void onPackageLoadingProgressChanged(@NonNull String packageName, @NonNull UserHandle user, float progress) {} } @@ -1702,15 +1701,15 @@ public class LauncherApps { } } - public void onPackageProgressChanged(UserHandle user, String packageName, + public void onPackageLoadingProgressChanged(UserHandle user, String packageName, float progress) { if (DEBUG) { - Log.d(TAG, "onPackageProgressChanged " + user.getIdentifier() + "," + Log.d(TAG, "onPackageLoadingProgressChanged " + user.getIdentifier() + "," + packageName + "," + progress); } synchronized (LauncherApps.this) { for (CallbackMessageHandler callback : mCallbacks) { - callback.postOnPackageProgressChanged(user, packageName, progress); + callback.postOnPackageLoadingProgressChanged(user, packageName, progress); } } } @@ -1777,7 +1776,7 @@ public class LauncherApps { mCallback.onShortcutsChanged(info.packageName, info.shortcuts, info.user); break; case MSG_LOADING_PROGRESS_CHANGED: - mCallback.onPackageProgressChanged(info.packageName, info.user, + mCallback.onPackageLoadingProgressChanged(info.packageName, info.user, info.mLoadingProgress); break; } @@ -1847,7 +1846,7 @@ public class LauncherApps { obtainMessage(MSG_SHORTCUT_CHANGED, info).sendToTarget(); } - public void postOnPackageProgressChanged(UserHandle user, String packageName, + public void postOnPackageLoadingProgressChanged(UserHandle user, String packageName, float progress) { CallbackInfo info = new CallbackInfo(); info.packageName = packageName; diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java index e65d7b5965d5..9f322fbad51d 100644 --- a/core/java/android/hardware/face/FaceManager.java +++ b/core/java/android/hardware/face/FaceManager.java @@ -419,6 +419,8 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan * * @see com.android.server.locksettings.LockSettingsService * + * TODO(b/171335732): should take userId + * * @hide */ @RequiresPermission(MANAGE_BIOMETRIC) @@ -426,7 +428,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan if (mService != null) { try { mGenerateChallengeCallback = callback; - mService.generateChallenge(mToken, sensorId, mServiceReceiver, + mService.generateChallenge(mToken, sensorId, 0 /* userId */, mServiceReceiver, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -470,13 +472,16 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan /** * Invalidates the current challenge. * + * TODO(b/171335732): should take userId and challenge + * * @hide */ @RequiresPermission(MANAGE_BIOMETRIC) public void revokeChallenge(int sensorId) { if (mService != null) { try { - mService.revokeChallenge(mToken, sensorId, mContext.getOpPackageName()); + mService.revokeChallenge(mToken, sensorId, 0 /* userId */, + mContext.getOpPackageName(), 0 /* challenge */); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl index b85b6f7d8174..490c95bfe1bb 100644 --- a/core/java/android/hardware/face/IFaceService.aidl +++ b/core/java/android/hardware/face/IFaceService.aidl @@ -32,7 +32,7 @@ interface IFaceService { List<FaceSensorPropertiesInternal> getSensorPropertiesInternal(String opPackageName); // Authenticate the given sessionId with a face - void authenticate(IBinder token, long operationId, int userid, IFaceServiceReceiver receiver, + void authenticate(IBinder token, long operationId, int userId, IFaceServiceReceiver receiver, String opPackageName); // Uses the face hardware to detect for the presence of a face, without giving details @@ -83,10 +83,10 @@ interface IFaceService { boolean isHardwareDetected(String opPackageName); // Get a pre-enrollment authentication token - void generateChallenge(IBinder token, int sensorId, IFaceServiceReceiver receiver, String opPackageName); + void generateChallenge(IBinder token, int sensorId, int userId, IFaceServiceReceiver receiver, String opPackageName); // Finish an enrollment sequence and invalidate the authentication token - void revokeChallenge(IBinder token, int sensorId, String opPackageName); + void revokeChallenge(IBinder token, int sensorId, int userId, String opPackageName, long challenge); // Determine if a user has at least one enrolled face boolean hasEnrolledFaces(int userId, String opPackageName); diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index d2c74e963689..4afe4b3d126b 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -766,6 +766,26 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing } /** + * Checks if the specified user has enrollments in any of the specified sensors. + * @hide + */ + @RequiresPermission(USE_BIOMETRIC_INTERNAL) + public boolean hasEnrolledTemplatesForAnySensor(int userId, + @NonNull List<FingerprintSensorPropertiesInternal> sensors) { + if (mService == null) { + Slog.w(TAG, "hasEnrolledTemplatesForAnySensor: no fingerprint service"); + return false; + } + + try { + return mService.hasEnrolledTemplatesForAnySensor(userId, sensors, + mContext.getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) @@ -778,7 +798,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing try { mService.setUdfpsOverlayController(controller); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + throw e.rethrowFromSystemServer(); } } @@ -795,7 +815,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing try { mService.onPointerDown(sensorId, x, y, minor, major); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + throw e.rethrowFromSystemServer(); } } @@ -812,7 +832,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing try { mService.onPointerUp(sensorId); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + throw e.rethrowFromSystemServer(); } } @@ -885,9 +905,8 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing } return mService.getSensorPropertiesInternal(mContext.getOpPackageName()); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + throw e.rethrowFromSystemServer(); } - return new ArrayList<>(); } /** diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl index 547de9d3c86a..5b14ef796616 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl @@ -100,6 +100,9 @@ interface IFingerprintService { // Determine if a user has at least one enrolled fingerprint boolean hasEnrolledFingerprints(int userId, String opPackageName); + // Determine if a user has at least one enrolled fingerprint in any of the specified sensors + boolean hasEnrolledTemplatesForAnySensor(int userId, in List<FingerprintSensorPropertiesInternal> sensors, String opPackageName); + // Return the LockoutTracker status for the specified user int getLockoutModeForUser(int userId); diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java index bb2357e24617..3d1755e9b017 100644 --- a/core/java/android/inputmethodservice/IInputMethodWrapper.java +++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java @@ -213,8 +213,7 @@ class IInputMethodWrapper extends IInputMethod.Stub ic, info, moreArgs.argi1 == 1 /* restarting */, - startInputToken, - moreArgs.argi2 == 1 /* shouldPreRenderIme */); + startInputToken); args.recycle(); moreArgs.recycle(); return; @@ -340,14 +339,13 @@ class IInputMethodWrapper extends IInputMethod.Stub @Override public void startInput(IBinder startInputToken, IInputContext inputContext, @InputConnectionInspector.MissingMethodFlags final int missingMethods, - EditorInfo attribute, boolean restarting, boolean shouldPreRenderIme) { + EditorInfo attribute, boolean restarting) { if (mCancellationGroup == null) { Log.e(TAG, "startInput must be called after bindInput."); mCancellationGroup = new CancellationGroup(); } SomeArgs args = SomeArgs.obtain(); args.argi1 = restarting ? 1 : 0; - args.argi2 = shouldPreRenderIme ? 1 : 0; args.argi3 = missingMethods; mCaller.executeOrSendMessage(mCaller.obtainMessageOOOOO(DO_START_INPUT, startInputToken, inputContext, attribute, mCancellationGroup, args)); diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index d290465816b6..32a8c0af0c01 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -19,7 +19,6 @@ package android.inputmethodservice; import static android.graphics.Color.TRANSPARENT; import static android.inputmethodservice.InputMethodServiceProto.CANDIDATES_VIEW_STARTED; import static android.inputmethodservice.InputMethodServiceProto.CANDIDATES_VISIBILITY; -import static android.inputmethodservice.InputMethodServiceProto.CAN_PRE_RENDER; import static android.inputmethodservice.InputMethodServiceProto.CONFIGURATION; import static android.inputmethodservice.InputMethodServiceProto.DECOR_VIEW_VISIBLE; import static android.inputmethodservice.InputMethodServiceProto.DECOR_VIEW_WAS_VISIBLE; @@ -33,7 +32,6 @@ import static android.inputmethodservice.InputMethodServiceProto.INPUT_VIEW_STAR import static android.inputmethodservice.InputMethodServiceProto.IN_SHOW_WINDOW; import static android.inputmethodservice.InputMethodServiceProto.IS_FULLSCREEN; import static android.inputmethodservice.InputMethodServiceProto.IS_INPUT_VIEW_SHOWN; -import static android.inputmethodservice.InputMethodServiceProto.IS_PRE_RENDERED; import static android.inputmethodservice.InputMethodServiceProto.InsetsProto.CONTENT_TOP_INSETS; import static android.inputmethodservice.InputMethodServiceProto.InsetsProto.TOUCHABLE_INSETS; import static android.inputmethodservice.InputMethodServiceProto.InsetsProto.TOUCHABLE_REGION; @@ -421,10 +419,6 @@ public class InputMethodService extends AbstractInputMethodService { boolean mDecorViewVisible; boolean mDecorViewWasVisible; boolean mInShowWindow; - // True if pre-rendering of IME views/window is supported. - boolean mCanPreRender; - // If IME is pre-rendered. - boolean mIsPreRendered; // IME window visibility. // Use (mDecorViewVisible && mWindowVisible) to check if IME is visible to the user. boolean mWindowVisible; @@ -672,10 +666,8 @@ public class InputMethodService extends AbstractInputMethodService { @Override public final void dispatchStartInputWithToken(@Nullable InputConnection inputConnection, @NonNull EditorInfo editorInfo, boolean restarting, - @NonNull IBinder startInputToken, boolean shouldPreRenderIme) { + @NonNull IBinder startInputToken) { mPrivOps.reportStartInput(startInputToken); - mCanPreRender = shouldPreRenderIme; - if (DEBUG) Log.v(TAG, "Will Pre-render IME: " + mCanPreRender); if (restarting) { restartInput(inputConnection, editorInfo); @@ -712,22 +704,12 @@ public class InputMethodService extends AbstractInputMethodService { + " Use requestHideSelf(int) itself"); return; } - final boolean wasVisible = mIsPreRendered - ? mDecorViewVisible && mWindowVisible : isInputViewShown(); + final boolean wasVisible = isInputViewShown(); applyVisibilityInInsetsConsumerIfNecessary(false /* setVisible */); - if (mIsPreRendered) { - if (DEBUG) { - Log.v(TAG, "Making IME window invisible"); - } - setImeWindowStatus(IME_ACTIVE | IME_INVISIBLE, mBackDisposition); - onPreRenderedWindowVisibilityChanged(false /* setVisible */); - } else { - mShowInputFlags = 0; - mShowInputRequested = false; - doHideWindow(); - } - final boolean isVisible = mIsPreRendered - ? mDecorViewVisible && mWindowVisible : isInputViewShown(); + mShowInputFlags = 0; + mShowInputRequested = false; + doHideWindow(); + final boolean isVisible = isInputViewShown(); final boolean visibilityChanged = isVisible != wasVisible; if (resultReceiver != null) { resultReceiver.send(visibilityChanged @@ -766,23 +748,15 @@ public class InputMethodService extends AbstractInputMethodService { + " Use requestShowSelf(int) itself"); return; } - final boolean wasVisible = mIsPreRendered - ? mDecorViewVisible && mWindowVisible : isInputViewShown(); + final boolean wasVisible = isInputViewShown(); if (dispatchOnShowInputRequested(flags, false)) { - if (mIsPreRendered) { - if (DEBUG) { - Log.v(TAG, "Making IME window visible"); - } - onPreRenderedWindowVisibilityChanged(true /* setVisible */); - } else { - showWindow(true); - } + + showWindow(true); applyVisibilityInInsetsConsumerIfNecessary(true /* setVisible */); } // If user uses hard keyboard, IME button should always be shown. setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition); - final boolean isVisible = mIsPreRendered - ? mDecorViewVisible && mWindowVisible : isInputViewShown(); + final boolean isVisible = isInputViewShown(); final boolean visibilityChanged = isVisible != wasVisible; if (resultReceiver != null) { resultReceiver.send(visibilityChanged @@ -1798,7 +1772,7 @@ public class InputMethodService extends AbstractInputMethodService { * applied by {@link #updateInputViewShown()}. */ public boolean isInputViewShown() { - return mCanPreRender ? mWindowVisible : mIsInputViewShown && mDecorViewVisible; + return mDecorViewVisible; } /** @@ -2151,10 +2125,9 @@ public class InputMethodService extends AbstractInputMethodService { mDecorViewWasVisible = mDecorViewVisible; mInShowWindow = true; - boolean isPreRenderedAndInvisible = mIsPreRendered && !mWindowVisible; final int previousImeWindowStatus = (mDecorViewVisible ? IME_ACTIVE : 0) | (isInputViewShown() - ? (isPreRenderedAndInvisible ? IME_INVISIBLE : IME_VISIBLE) : 0); + ? (!mWindowVisible ? IME_INVISIBLE : IME_VISIBLE) : 0); startViews(prepareWindow(showInput)); final int nextImeWindowStatus = mapToImeWindowStatus(); if (previousImeWindowStatus != nextImeWindowStatus) { @@ -2163,14 +2136,7 @@ public class InputMethodService extends AbstractInputMethodService { // compute visibility onWindowShown(); - mIsPreRendered = mCanPreRender; - if (mIsPreRendered) { - onPreRenderedWindowVisibilityChanged(true /* setVisible */); - } else { - // Pre-rendering not supported. - if (DEBUG) Log.d(TAG, "No pre-rendering supported"); - mWindowVisible = true; - } + mWindowVisible = true; // request draw for the IME surface. // When IME is not pre-rendered, this will actually show the IME. @@ -2178,22 +2144,10 @@ public class InputMethodService extends AbstractInputMethodService { if (DEBUG) Log.v(TAG, "showWindow: draw decorView!"); mWindow.show(); } - maybeNotifyPreRendered(); mDecorViewWasVisible = true; mInShowWindow = false; } - /** - * Notify {@link android.view.ImeInsetsSourceConsumer} if IME has been pre-rendered - * for current EditorInfo, when pre-rendering is enabled. - */ - private void maybeNotifyPreRendered() { - if (!mCanPreRender || !mIsPreRendered) { - return; - } - mPrivOps.reportPreRendered(getCurrentInputEditorInfo()); - } - private boolean prepareWindow(boolean showInput) { boolean doShowInput = false; @@ -2237,16 +2191,6 @@ public class InputMethodService extends AbstractInputMethodService { if (doShowInput) startExtractingText(false); } - private void onPreRenderedWindowVisibilityChanged(boolean setVisible) { - mWindowVisible = setVisible; - mShowInputFlags = setVisible ? mShowInputFlags : 0; - mShowInputRequested = setVisible; - mDecorViewVisible = setVisible; - if (setVisible) { - onWindowShown(); - } - } - /** * Applies the IME visibility in {@link android.view.ImeInsetsSourceConsumer}. * @@ -2277,7 +2221,6 @@ public class InputMethodService extends AbstractInputMethodService { public void hideWindow() { if (DEBUG) Log.v(TAG, "CALL: hideWindow"); - mIsPreRendered = false; mWindowVisible = false; finishViews(false /* finishingInput */); if (mDecorViewVisible) { @@ -2384,32 +2327,6 @@ public class InputMethodService extends AbstractInputMethodService { mCandidatesViewStarted = true; onStartCandidatesView(mInputEditorInfo, restarting); } - } else if (mCanPreRender && mInputEditorInfo != null && mStartedInputConnection != null) { - // Pre-render IME views and window when real EditorInfo is available. - // pre-render IME window and keep it invisible. - if (DEBUG) Log.v(TAG, "Pre-Render IME for " + mInputEditorInfo.fieldName); - if (mInShowWindow) { - Log.w(TAG, "Re-entrance in to showWindow"); - return; - } - - mDecorViewWasVisible = mDecorViewVisible; - mInShowWindow = true; - startViews(prepareWindow(true /* showInput */)); - - // compute visibility - mIsPreRendered = true; - onPreRenderedWindowVisibilityChanged(false /* setVisible */); - - // request draw for the IME surface. - // When IME is not pre-rendered, this will actually show the IME. - if (DEBUG) Log.v(TAG, "showWindow: draw decorView!"); - mWindow.show(); - maybeNotifyPreRendered(); - mDecorViewWasVisible = true; - mInShowWindow = false; - } else { - mIsPreRendered = false; } } @@ -3309,9 +3226,7 @@ public class InputMethodService extends AbstractInputMethodService { private int mapToImeWindowStatus() { return IME_ACTIVE - | (isInputViewShown() - ? (mCanPreRender ? (mWindowVisible ? IME_VISIBLE : IME_INVISIBLE) - : IME_VISIBLE) : 0); + | (isInputViewShown() ? IME_VISIBLE : 0); } private boolean isAutomotive() { @@ -3349,8 +3264,6 @@ public class InputMethodService extends AbstractInputMethodService { p.println(" mShowInputRequested=" + mShowInputRequested + " mLastShowInputRequested=" + mLastShowInputRequested - + " mCanPreRender=" + mCanPreRender - + " mIsPreRendered=" + mIsPreRendered + " mShowInputFlags=0x" + Integer.toHexString(mShowInputFlags)); p.println(" mCandidatesVisibility=" + mCandidatesVisibility + " mFullscreenApplied=" + mFullscreenApplied @@ -3401,8 +3314,6 @@ public class InputMethodService extends AbstractInputMethodService { } proto.write(SHOW_INPUT_REQUESTED, mShowInputRequested); proto.write(LAST_SHOW_INPUT_REQUESTED, mLastShowInputRequested); - proto.write(CAN_PRE_RENDER, mCanPreRender); - proto.write(IS_PRE_RENDERED, mIsPreRendered); proto.write(SHOW_INPUT_FLAGS, mShowInputFlags); proto.write(CANDIDATES_VISIBILITY, mCandidatesVisibility); proto.write(FULLSCREEN_APPLIED, mFullscreenApplied); diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 780c4fa66d26..cc3d92da7352 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -9758,6 +9758,14 @@ public final class Settings { "render_shadows_in_compositor"; /** + * If true, submit buffers using blast in ViewRootImpl. + * (0 = false, 1 = true) + * @hide + */ + public static final String DEVELOPMENT_USE_BLAST_ADAPTER_VR = + "use_blast_adapter_vr"; + + /** * If true, submit buffers using blast in SurfaceView. * (0 = false, 1 = true) * @hide diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java index e4ba87c14626..f08756a015b2 100644 --- a/core/java/android/security/keymaster/KeymasterDefs.java +++ b/core/java/android/security/keymaster/KeymasterDefs.java @@ -218,6 +218,7 @@ public final class KeymasterDefs { public static final int KM_ERROR_MISSING_MIN_MAC_LENGTH = -58; public static final int KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH = -59; public static final int KM_ERROR_CANNOT_ATTEST_IDS = -66; + public static final int KM_ERROR_HARDWARE_TYPE_UNAVAILABLE = -68; public static final int KM_ERROR_DEVICE_LOCKED = -72; public static final int KM_ERROR_UNIMPLEMENTED = -100; public static final int KM_ERROR_VERSION_MISMATCH = -101; @@ -265,6 +266,8 @@ public final class KeymasterDefs { sErrorCodeToString.put(KM_ERROR_INVALID_MAC_LENGTH, "Invalid MAC or authentication tag length"); sErrorCodeToString.put(KM_ERROR_CANNOT_ATTEST_IDS, "Unable to attest device ids"); + sErrorCodeToString.put(KM_ERROR_HARDWARE_TYPE_UNAVAILABLE, "Requested security level " + + "(likely Strongbox) is not available."); sErrorCodeToString.put(KM_ERROR_DEVICE_LOCKED, "Device locked"); sErrorCodeToString.put(KM_ERROR_UNIMPLEMENTED, "Not implemented"); sErrorCodeToString.put(KM_ERROR_UNKNOWN_ERROR, "Unknown error"); diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java index dd1a19458e1d..5780d4f69f9e 100644 --- a/core/java/android/view/ImeInsetsSourceConsumer.java +++ b/core/java/android/view/ImeInsetsSourceConsumer.java @@ -16,7 +16,6 @@ package android.view; -import static android.view.ImeInsetsSourceConsumerProto.FOCUSED_EDITOR; import static android.view.ImeInsetsSourceConsumerProto.INSETS_SOURCE_CONSUMER; import static android.view.ImeInsetsSourceConsumerProto.IS_REQUESTED_VISIBLE_AWAITING_CONTROL; import static android.view.InsetsController.AnimationType; @@ -25,16 +24,10 @@ import static android.view.InsetsState.ITYPE_IME; import android.annotation.Nullable; import android.inputmethodservice.InputMethodService; import android.os.IBinder; -import android.os.Parcel; -import android.text.TextUtils; import android.util.proto.ProtoOutputStream; import android.view.SurfaceControl.Transaction; -import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; -import com.android.internal.annotations.VisibleForTesting; - -import java.util.Arrays; import java.util.function.Supplier; /** @@ -42,13 +35,6 @@ import java.util.function.Supplier; * @hide */ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { - private EditorInfo mFocusedEditor; - private EditorInfo mPreRenderedEditor; - /** - * Determines if IME would be shown next time IME is pre-rendered for currently focused - * editor {@link #mFocusedEditor} if {@link #isServedEditorRendered} is {@code true}. - */ - private boolean mShowOnNextImeRender; /** * Tracks whether we have an outstanding request from the IME to show, but weren't able to @@ -62,23 +48,6 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { super(ITYPE_IME, state, transactionSupplier, controller); } - public void onPreRendered(EditorInfo info) { - mPreRenderedEditor = info; - if (mShowOnNextImeRender) { - mShowOnNextImeRender = false; - if (isServedEditorRendered()) { - applyImeVisibility(true /* setVisible */); - } - } - } - - public void onServedEditorChanged(EditorInfo info) { - if (isFallbackOrEmptyEditor(info)) { - mShowOnNextImeRender = false; - } - mFocusedEditor = info; - } - public void applyImeVisibility(boolean setVisible) { mController.applyImeVisibility(setVisible); } @@ -170,73 +139,10 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { } } - private boolean isFallbackOrEmptyEditor(EditorInfo info) { - // TODO(b/123044812): Handle fallback input gracefully in IME Insets API - return info == null || (info.fieldId <= 0 && info.inputType <= 0); - } - - private boolean isServedEditorRendered() { - if (mFocusedEditor == null || mPreRenderedEditor == null - || isFallbackOrEmptyEditor(mFocusedEditor) - || isFallbackOrEmptyEditor(mPreRenderedEditor)) { - // No view is focused or ready. - return false; - } - return areEditorsSimilar(mFocusedEditor, mPreRenderedEditor); - } - - @VisibleForTesting - public static boolean areEditorsSimilar(EditorInfo info1, EditorInfo info2) { - // We don't need to compare EditorInfo.fieldId (View#id) since that shouldn't change - // IME views. - boolean areOptionsSimilar = - info1.imeOptions == info2.imeOptions - && info1.inputType == info2.inputType - && TextUtils.equals(info1.packageName, info2.packageName); - areOptionsSimilar &= info1.privateImeOptions != null - ? info1.privateImeOptions.equals(info2.privateImeOptions) : true; - - if (!areOptionsSimilar) { - return false; - } - - // compare bundle extras. - if ((info1.extras == null && info2.extras == null) || info1.extras == info2.extras) { - return true; - } - if ((info1.extras == null && info2.extras != null) - || (info1.extras == null && info2.extras != null)) { - return false; - } - if (info1.extras.hashCode() == info2.extras.hashCode() - || info1.extras.equals(info1)) { - return true; - } - if (info1.extras.size() != info2.extras.size()) { - return false; - } - if (info1.extras.toString().equals(info2.extras.toString())) { - return true; - } - - // Compare bytes - Parcel parcel1 = Parcel.obtain(); - info1.extras.writeToParcel(parcel1, 0); - parcel1.setDataPosition(0); - Parcel parcel2 = Parcel.obtain(); - info2.extras.writeToParcel(parcel2, 0); - parcel2.setDataPosition(0); - - return Arrays.equals(parcel1.createByteArray(), parcel2.createByteArray()); - } - @Override public void dumpDebug(ProtoOutputStream proto, long fieldId) { final long token = proto.start(fieldId); super.dumpDebug(proto, INSETS_SOURCE_CONSUMER); - if (mFocusedEditor != null) { - mFocusedEditor.dumpDebug(proto, FOCUSED_EDITOR); - } proto.write(IS_REQUESTED_VISIBLE_AWAITING_CONTROL, mIsRequestedVisibleAwaitingControl); proto.end(token); } diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 9ea4c93b75c7..d37edaa633a5 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -135,6 +135,8 @@ public final class SurfaceControl implements Parcelable { int blurRadius); private static native void nativeSetLayerStack(long transactionObj, long nativeObject, int layerStack); + private static native void nativeSetBlurRegions(long transactionObj, long nativeObj, + float[][] regions, int length); private static native boolean nativeClearContentFrameStats(long nativeObject); private static native boolean nativeGetContentFrameStats(long nativeObject, WindowContentFrameStats outStats); @@ -2954,6 +2956,21 @@ public final class SurfaceControl implements Parcelable { } /** + * Specify what regions should be blurred on the {@link SurfaceControl}. + * + * @param sc SurfaceControl. + * @param regions List of regions that will have blurs. + * @return itself. + * @see BlurRegion#toFloatArray() + * @hide + */ + public Transaction setBlurRegions(SurfaceControl sc, float[][] regions) { + checkPreconditions(sc); + nativeSetBlurRegions(mNativeObject, sc.mNativeObject, regions, regions.length); + return this; + } + + /** * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.O) @@ -3482,4 +3499,64 @@ public final class SurfaceControl implements Parcelable { public static Transaction getGlobalTransaction() { return sGlobalTransaction; } + + /** + * Wrapper for sending blur data to SurfaceFlinger. + * @hide + */ + public static final class BlurRegion { + public int blurRadius; + public float cornerRadiusTL; + public float cornerRadiusTR; + public float cornerRadiusBL; + public float cornerRadiusBR; + public float alpha = 1; + public boolean visible = true; + public final Rect rect = new Rect(); + + private final float[] mFloatArray = new float[10]; + + public BlurRegion() { + } + + public BlurRegion(BlurRegion other) { + rect.set(other.rect); + blurRadius = other.blurRadius; + alpha = other.alpha; + cornerRadiusTL = other.cornerRadiusTL; + cornerRadiusTR = other.cornerRadiusTR; + cornerRadiusBL = other.cornerRadiusBL; + cornerRadiusBR = other.cornerRadiusBR; + } + + /** + * Serializes this class into a float array that's more JNI friendly. + */ + public float[] toFloatArray() { + mFloatArray[0] = blurRadius; + mFloatArray[1] = alpha; + mFloatArray[2] = rect.left; + mFloatArray[3] = rect.top; + mFloatArray[4] = rect.right; + mFloatArray[5] = rect.bottom; + mFloatArray[6] = cornerRadiusTL; + mFloatArray[7] = cornerRadiusTR; + mFloatArray[8] = cornerRadiusBL; + mFloatArray[9] = cornerRadiusBR; + return mFloatArray; + } + + @Override + public String toString() { + return "BlurRegion{" + + "blurRadius=" + blurRadius + + ", corners={" + cornerRadiusTL + + "," + cornerRadiusTR + + "," + cornerRadiusBL + + "," + cornerRadiusBR + + "}, alpha=" + alpha + + ", rect=" + rect + + "}"; + } + } } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 14ba699933f0..0e8cd546a2ae 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -187,6 +187,7 @@ import android.window.ClientWindowFrames; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.graphics.drawable.BackgroundBlurDrawable; import com.android.internal.inputmethod.InputMethodDebug; import com.android.internal.os.IResultReceiver; import com.android.internal.os.SomeArgs; @@ -654,6 +655,9 @@ public final class ViewRootImpl implements ViewParent, private ScrollCaptureConnection mScrollCaptureConnection; + private final BackgroundBlurDrawable.Aggregator mBlurRegionAggregator = + new BackgroundBlurDrawable.Aggregator(this); + /** * @return {@link ImeFocusController} for this instance. */ @@ -3819,6 +3823,8 @@ public final class ViewRootImpl implements ViewParent, private HardwareRenderer.FrameCompleteCallback createFrameCompleteCallback(Handler handler, boolean reportNextDraw, ArrayList<Runnable> commitCallbacks) { return frameNr -> { + mBlurRegionAggregator.dispatchBlurTransactionIfNeeded(frameNr); + // Use a new transaction here since mRtBLASTSyncTransaction can only be accessed by // the render thread and mSurfaceChangedTransaction can only be accessed by the UI // thread. The temporary transaction is used so mRtBLASTSyncTransaction can be merged @@ -3849,7 +3855,8 @@ public final class ViewRootImpl implements ViewParent, .captureFrameCommitCallbacks(); final boolean needFrameCompleteCallback = mNextDrawUseBLASTSyncTransaction || mReportNextDraw - || (commitCallbacks != null && commitCallbacks.size() > 0); + || (commitCallbacks != null && commitCallbacks.size() > 0) + || mBlurRegionAggregator.hasRegions(); if (needFrameCompleteCallback) { mAttachInfo.mThreadedRenderer.setFrameCompleteCallback( createFrameCompleteCallback(mAttachInfo.mHandler, mReportNextDraw, @@ -9915,6 +9922,36 @@ public final class ViewRootImpl implements ViewParent, } } + /** + * Sends a list of blur regions to SurfaceFlinger, tagged with a frame. + * + * @param regionCopy List of regions + * @param frameNumber Frame where it should be applied (or current when using BLAST) + */ + public void dispatchBlurRegions(float[][] regionCopy, long frameNumber) { + final SurfaceControl surfaceControl = getSurfaceControl(); + if (!surfaceControl.isValid()) { + return; + } + if (useBLAST()) { + synchronized (getBlastTransactionLock()) { + getBLASTSyncTransaction().setBlurRegions(surfaceControl, regionCopy); + } + } else { + SurfaceControl.Transaction transaction = new SurfaceControl.Transaction(); + transaction.setBlurRegions(surfaceControl, regionCopy); + transaction.deferTransactionUntil(surfaceControl, getSurfaceControl(), frameNumber); + transaction.apply(); + } + } + + /** + * Creates a background blur drawable for the backing {@link Surface}. + */ + public BackgroundBlurDrawable createBackgroundBlurDrawable() { + return mBlurRegionAggregator.createBackgroundBlurDrawable(mContext); + } + SurfaceControl.Transaction getBLASTSyncTransaction() { return mRtBLASTSyncTransaction; } diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java index f44ab3ac2ed1..de4554b9e624 100644 --- a/core/java/android/view/inputmethod/InputMethod.java +++ b/core/java/android/view/inputmethod/InputMethod.java @@ -243,7 +243,7 @@ public interface InputMethod { @MainThread default void dispatchStartInputWithToken(@Nullable InputConnection inputConnection, @NonNull EditorInfo editorInfo, boolean restarting, - @NonNull IBinder startInputToken, boolean shouldPreRenderIme) { + @NonNull IBinder startInputToken) { if (restarting) { restartInput(inputConnection, editorInfo); } else { diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 1931174d4bb8..6243c63531eb 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -489,7 +489,6 @@ public final class InputMethodManager { static final int MSG_TIMEOUT_INPUT_EVENT = 6; static final int MSG_FLUSH_INPUT_EVENT = 7; static final int MSG_REPORT_FULLSCREEN_MODE = 10; - static final int MSG_REPORT_PRE_RENDERED = 15; static final int MSG_APPLY_IME_VISIBILITY = 20; static final int MSG_UPDATE_ACTIVITY_VIEW_TO_SCREEN_MATRIX = 30; @@ -584,17 +583,6 @@ public final class InputMethodManager { mServedConnecting = true; servedView = getServedViewLocked(); } - if (servedView != null && servedView.getHandler() != null) { - // Make sure View checks should be on the UI thread. - servedView.getHandler().post(() -> { - if (!servedView.onCheckIsTextEditor()) { - // servedView has changed and it's not editable. - synchronized (mH) { - maybeCallServedViewChangedLocked(null); - } - } - }); - } return startInputInner(startInputReason, focusedView != null ? focusedView.getWindowToken() : null, startInputFlags, softInputMode, windowFlags); @@ -919,15 +907,6 @@ public final class InputMethodManager { } return; } - case MSG_REPORT_PRE_RENDERED: { - synchronized (mH) { - if (mImeInsetsConsumer != null) { - mImeInsetsConsumer.onPreRendered((EditorInfo) msg.obj); - } - } - return; - - } case MSG_APPLY_IME_VISIBILITY: { synchronized (mH) { if (mImeInsetsConsumer != null) { @@ -1100,12 +1079,6 @@ public final class InputMethodManager { } @Override - public void reportPreRendered(EditorInfo info) { - mH.obtainMessage(MSG_REPORT_PRE_RENDERED, 0, 0, info) - .sendToTarget(); - } - - @Override public void applyImeVisibility(boolean setVisible) { mH.obtainMessage(MSG_APPLY_IME_VISIBILITY, setVisible ? 1 : 0, 0) .sendToTarget(); @@ -1981,7 +1954,7 @@ public final class InputMethodManager { // Hook 'em up and let 'er rip. mCurrentTextBoxAttribute = tba; - maybeCallServedViewChangedLocked(tba); + mServedConnecting = false; if (mServedInputConnectionWrapper != null) { mServedInputConnectionWrapper.deactivate(); @@ -3141,12 +3114,6 @@ public final class InputMethodManager { } } - private void maybeCallServedViewChangedLocked(EditorInfo tba) { - if (mImeInsetsConsumer != null) { - mImeInsetsConsumer.onServedEditorChanged(tba); - } - } - /** * <p>This is used for CTS test only. Do not use this method outside of CTS package.<p/> * @return the ID of this display which this {@link InputMethodManager} resides diff --git a/core/java/com/android/internal/BrightnessSynchronizer.java b/core/java/com/android/internal/BrightnessSynchronizer.java index c98477e8c343..15463cb34157 100644 --- a/core/java/com/android/internal/BrightnessSynchronizer.java +++ b/core/java/com/android/internal/BrightnessSynchronizer.java @@ -22,6 +22,7 @@ import android.content.Context; import android.database.ContentObserver; import android.net.Uri; import android.os.Handler; +import android.os.Looper; import android.os.Message; import android.os.PowerManager; import android.os.UserHandle; @@ -55,7 +56,7 @@ public class BrightnessSynchronizer { private final Queue<Object> mWriteHistory = new LinkedList<>(); - private final Handler mHandler = new Handler() { + private final Handler mHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { @@ -72,7 +73,6 @@ public class BrightnessSynchronizer { } }; - public BrightnessSynchronizer(Context context) { final BrightnessSyncObserver mBrightnessSyncObserver; mContext = context; diff --git a/core/java/com/android/internal/app/ChooserFlags.java b/core/java/com/android/internal/app/ChooserFlags.java index 3e26679e28a4..1a93f1bc947f 100644 --- a/core/java/com/android/internal/app/ChooserFlags.java +++ b/core/java/com/android/internal/app/ChooserFlags.java @@ -33,7 +33,7 @@ public class ChooserFlags { */ public static final boolean USE_SERVICE_TARGETS_FOR_DIRECT_TARGETS = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.SHARE_USE_SERVICE_TARGETS, true); + SystemUiDeviceConfigFlags.SHARE_USE_SERVICE_TARGETS, false); /** * Whether to use {@link AppPredictionManager} to query for direct share targets (as opposed to diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java index a2af4d6cf456..777534e72d73 100644 --- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java +++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java @@ -430,6 +430,11 @@ public final class SystemUiDeviceConfigFlags { public static final String USE_BACK_GESTURE_ML_MODEL = "use_back_gesture_ml_model"; /** + * (string) The name of the ML model for Back Gesture. + */ + public static final String BACK_GESTURE_ML_MODEL_NAME = "back_gesture_ml_model_name"; + + /** * (float) Threshold for Back Gesture ML model prediction. */ public static final String BACK_GESTURE_ML_MODEL_THRESHOLD = "back_gesture_ml_model_threshold"; diff --git a/core/java/com/android/internal/graphics/drawable/BackgroundBlurDrawable.java b/core/java/com/android/internal/graphics/drawable/BackgroundBlurDrawable.java new file mode 100644 index 000000000000..6ea9e665c009 --- /dev/null +++ b/core/java/com/android/internal/graphics/drawable/BackgroundBlurDrawable.java @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.graphics.drawable; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; +import android.graphics.RenderNode; +import android.graphics.drawable.Drawable; +import android.util.ArrayMap; +import android.util.Log; +import android.view.SurfaceControl; +import android.view.ViewRootImpl; + +import com.android.internal.R; + +/** + * A drawable that keeps track of a blur region, pokes a hole under it, and propagates its state + * to SurfaceFlinger. + */ +public final class BackgroundBlurDrawable extends Drawable { + + private static final String TAG = BackgroundBlurDrawable.class.getSimpleName(); + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + private final Aggregator mAggregator; + private final RenderNode mRenderNode; + private final Paint mPaint = new Paint(); + private final Path mRectPath = new Path(); + private final float[] mTmpRadii = new float[8]; + private final SurfaceControl.BlurRegion mBlurRegion = new SurfaceControl.BlurRegion(); + + // This will be called from a thread pool. + private final RenderNode.PositionUpdateListener mPositionUpdateListener = + new RenderNode.PositionUpdateListener() { + @Override + public void positionChanged(long frameNumber, int left, int top, int right, + int bottom) { + synchronized (mAggregator) { + mBlurRegion.rect.set(left, top, right, bottom); + mAggregator.onBlurRegionUpdated(BackgroundBlurDrawable.this, mBlurRegion); + } + } + + @Override + public void positionLost(long frameNumber) { + synchronized (mAggregator) { + mBlurRegion.rect.setEmpty(); + mAggregator.onBlurRegionUpdated(BackgroundBlurDrawable.this, mBlurRegion); + } + } + }; + + private BackgroundBlurDrawable(Aggregator aggregator) { + mAggregator = aggregator; + mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); + mRenderNode = new RenderNode("BackgroundBlurDrawable"); + mRenderNode.addPositionUpdateListener(mPositionUpdateListener); + } + + @Override + public void draw(@NonNull Canvas canvas) { + if (mRectPath.isEmpty() || !isVisible() || getAlpha() == 0) { + return; + } + canvas.drawPath(mRectPath, mPaint); + canvas.drawRenderNode(mRenderNode); + } + + @Override + public boolean setVisible(boolean visible, boolean restart) { + boolean changed = super.setVisible(visible, restart); + if (changed) { + mBlurRegion.visible = visible; + } + return changed; + } + + @Override + public void setAlpha(int alpha) { + mBlurRegion.alpha = alpha / 255f; + invalidateSelf(); + } + + /** + * Blur radius in pixels. + */ + public void setBlurRadius(int blurRadius) { + mBlurRegion.blurRadius = blurRadius; + invalidateSelf(); + } + + /** + * Sets the corner radius, in degrees. + */ + public void setCornerRadius(float cornerRadius) { + setCornerRadius(cornerRadius, cornerRadius, cornerRadius, cornerRadius); + } + + /** + * Sets the corner radius in degrees. + * @param cornerRadiusTL top left radius. + * @param cornerRadiusTR top right radius. + * @param cornerRadiusBL bottom left radius. + * @param cornerRadiusBR bottom right radius. + */ + public void setCornerRadius(float cornerRadiusTL, float cornerRadiusTR, float cornerRadiusBL, + float cornerRadiusBR) { + synchronized (mAggregator) { + mBlurRegion.cornerRadiusTL = cornerRadiusTL; + mBlurRegion.cornerRadiusTR = cornerRadiusTR; + mBlurRegion.cornerRadiusBL = cornerRadiusBL; + mBlurRegion.cornerRadiusBR = cornerRadiusBR; + } + updatePath(); + invalidateSelf(); + } + + @Override + public void setBounds(int left, int top, int right, int bottom) { + super.setBounds(left, top, right, bottom); + mRenderNode.setPosition(left, top, right, bottom); + updatePath(); + } + + private void updatePath() { + synchronized (mAggregator) { + mTmpRadii[0] = mTmpRadii[1] = mBlurRegion.cornerRadiusTL; + mTmpRadii[2] = mTmpRadii[3] = mBlurRegion.cornerRadiusTR; + mTmpRadii[4] = mTmpRadii[5] = mBlurRegion.cornerRadiusBL; + mTmpRadii[6] = mTmpRadii[7] = mBlurRegion.cornerRadiusBR; + } + mRectPath.reset(); + if (getAlpha() == 0 || !isVisible()) { + return; + } + Rect bounds = getBounds(); + mRectPath.addRoundRect(bounds.left, bounds.top, bounds.right, bounds.bottom, mTmpRadii, + Path.Direction.CW); + } + + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { + throw new IllegalArgumentException("not implemented"); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + + /** + * Responsible for keeping track of all blur regions of a {@link ViewRootImpl} and posting a + * message when it's time to propagate them. + */ + public static final class Aggregator { + + private final ArrayMap<BackgroundBlurDrawable, SurfaceControl.BlurRegion> mBlurRegions = + new ArrayMap<>(); + private final ViewRootImpl mViewRoot; + private float[][] mTmpBlurRegionsArray; + private boolean mNeedsUpdate; + + public Aggregator(ViewRootImpl viewRoot) { + mViewRoot = viewRoot; + } + + /** + * Creates a blur region with default radius. + */ + public BackgroundBlurDrawable createBackgroundBlurDrawable(Context context) { + BackgroundBlurDrawable drawable = new BackgroundBlurDrawable(this); + drawable.setBlurRadius(context.getResources().getDimensionPixelSize( + R.dimen.default_background_blur_radius)); + return drawable; + } + + /** + * Called from RenderThread only, already locked. + * @param drawable + * @param blurRegion + */ + void onBlurRegionUpdated(BackgroundBlurDrawable drawable, + SurfaceControl.BlurRegion blurRegion) { + if (blurRegion.rect.isEmpty() || blurRegion.alpha == 0 || blurRegion.blurRadius == 0 + || !blurRegion.visible) { + mBlurRegions.remove(drawable); + mNeedsUpdate = true; + if (DEBUG) { + Log.d(TAG, "Remove " + blurRegion); + } + } else { + mBlurRegions.put(drawable, blurRegion); + mNeedsUpdate = true; + if (DEBUG) { + Log.d(TAG, "Update " + blurRegion); + } + } + } + + /** + * If there are any blur regions visible on the screen at the moment. + */ + public boolean hasRegions() { + return mBlurRegions.size() > 0; + } + + /** + * Dispatch blur updates, if there were any. + * @param frameNumber Frame where the update should happen. + */ + public void dispatchBlurTransactionIfNeeded(long frameNumber) { + synchronized (this) { + if (!mNeedsUpdate) { + return; + } + mNeedsUpdate = false; + + if (mTmpBlurRegionsArray == null + || mTmpBlurRegionsArray.length != mBlurRegions.size()) { + mTmpBlurRegionsArray = new float[mBlurRegions.size()][]; + } + if (DEBUG) { + Log.d(TAG, "onBlurRegionUpdated will dispatch " + mTmpBlurRegionsArray.length + + " regions for frame " + frameNumber); + } + for (int i = 0; i < mTmpBlurRegionsArray.length; i++) { + mTmpBlurRegionsArray[i] = mBlurRegions.valueAt(i).toFloatArray(); + } + + mViewRoot.dispatchBlurRegions(mTmpBlurRegionsArray, frameNumber); + } + } + } +} diff --git a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl index 9a226860831a..f0e26cf4bbcf 100644 --- a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl +++ b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl @@ -17,7 +17,6 @@ package com.android.internal.inputmethod; import android.net.Uri; -import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodSubtype; import com.android.internal.inputmethod.IInputContentUriToken; @@ -40,6 +39,5 @@ interface IInputMethodPrivilegedOperations { boolean switchToNextInputMethod(boolean onlyCurrentIme); boolean shouldOfferSwitchingToNextInputMethod(); void notifyUserAction(); - void reportPreRendered(in EditorInfo info); void applyImeVisibility(IBinder showOrHideInputToken, boolean setVisible); } diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java index 9b1299ebe54c..d6730e8b0bdb 100644 --- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java +++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java @@ -24,7 +24,6 @@ import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import android.view.View; -import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodSubtype; import com.android.internal.annotations.GuardedBy; @@ -351,24 +350,6 @@ public final class InputMethodPrivilegedOperations { } /** - * Calls {@link IInputMethodPrivilegedOperations#reportPreRendered(info)}. - * - * @param info {@link EditorInfo} of the currently rendered {@link TextView}. - */ - @AnyThread - public void reportPreRendered(EditorInfo info) { - final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull(); - if (ops == null) { - return; - } - try { - ops.reportPreRendered(info); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** * Calls {@link IInputMethodPrivilegedOperations#applyImeVisibility(IBinder, boolean)}. * * @param showOrHideInputToken placeholder token that maps to window requesting diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl index 40e4f4d6ad12..c33637353984 100644 --- a/core/java/com/android/internal/view/IInputMethod.aidl +++ b/core/java/com/android/internal/view/IInputMethod.aidl @@ -45,7 +45,7 @@ oneway interface IInputMethod { void unbindInput(); void startInput(in IBinder startInputToken, in IInputContext inputContext, int missingMethods, - in EditorInfo attribute, boolean restarting, boolean preRenderImeViews); + in EditorInfo attribute, boolean restarting); void createSession(in InputChannel channel, IInputSessionCallback callback); diff --git a/core/java/com/android/internal/view/IInputMethodClient.aidl b/core/java/com/android/internal/view/IInputMethodClient.aidl index c9443b002133..1145f5183206 100644 --- a/core/java/com/android/internal/view/IInputMethodClient.aidl +++ b/core/java/com/android/internal/view/IInputMethodClient.aidl @@ -16,8 +16,6 @@ package com.android.internal.view; -import android.view.inputmethod.EditorInfo; - import com.android.internal.view.InputBindResult; /** @@ -30,7 +28,6 @@ oneway interface IInputMethodClient { void setActive(boolean active, boolean fullscreen); void scheduleStartInputIfNecessary(boolean fullscreen); void reportFullscreenMode(boolean fullscreen); - void reportPreRendered(in EditorInfo info); void applyImeVisibility(boolean setVisible); void updateActivityViewToScreenMatrix(int bindSequence, in float[] matrixValues); void setImeTraceEnabled(boolean enabled); diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp index ce8b59941a5a..832c0665488e 100644 --- a/core/jni/android_view_MotionEvent.cpp +++ b/core/jni/android_view_MotionEvent.cpp @@ -256,11 +256,13 @@ static jfloatArray obtainPackedAxisValuesArray(JNIEnv* env, uint32_t minSize, } static void pointerCoordsFromNative(JNIEnv* env, const PointerCoords* rawPointerCoords, - float xOffset, float yOffset, jobject outPointerCoordsObj) { - env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.x, - rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_X) + xOffset); - env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.y, - rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_Y) + yOffset); + ui::Transform transform, jobject outPointerCoordsObj) { + float rawX = rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_X); + float rawY = rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_Y); + vec2 transformed = transform.transform(rawX, rawY); + + env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.x, transformed.x); + env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.y, transformed.y); env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.pressure, rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.size, @@ -433,8 +435,7 @@ static void android_view_MotionEvent_nativeGetPointerCoords(JNIEnv* env, jclass } rawPointerCoords = event->getHistoricalRawPointerCoords(pointerIndex, historyPos); } - pointerCoordsFromNative(env, rawPointerCoords, event->getXOffset(), event->getYOffset(), - outPointerCoordsObj); + pointerCoordsFromNative(env, rawPointerCoords, event->getTransform(), outPointerCoordsObj); } static void android_view_MotionEvent_nativeGetPointerProperties(JNIEnv* env, jclass clazz, diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 17ced9f78f25..f1ec85a8570f 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -40,6 +40,7 @@ #include <private/gui/ComposerService.h> #include <stdio.h> #include <system/graphics.h> +#include <ui/BlurRegion.h> #include <ui/ConfigStoreTypes.h> #include <ui/DeviceProductInfo.h> #include <ui/DisplayConfig.h> @@ -522,6 +523,43 @@ static void nativeSetGeometry(JNIEnv* env, jclass clazz, jlong transactionObj, j transaction->setGeometry(ctrl, source, dst, orientation); } +static void nativeSetBlurRegions(JNIEnv* env, jclass clazz, jlong transactionObj, + jlong nativeObject, jobjectArray regions, jint regionsLength) { + auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj); + SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject); + + std::vector<BlurRegion> blurRegionVector; + const int size = regionsLength; + float region[10]; + for (int i = 0; i < size; i++) { + jfloatArray regionArray = (jfloatArray)env->GetObjectArrayElement(regions, i); + env->GetFloatArrayRegion(regionArray, 0, 10, region); + float blurRadius = region[0]; + float alpha = region[1]; + float left = region[2]; + float top = region[3]; + float right = region[4]; + float bottom = region[5]; + float cornerRadiusTL = region[6]; + float cornerRadiusTR = region[7]; + float cornerRadiusBL = region[8]; + float cornerRadiusBR = region[9]; + + blurRegionVector.push_back(BlurRegion{.blurRadius = static_cast<uint32_t>(blurRadius), + .cornerRadiusTL = cornerRadiusTL, + .cornerRadiusTR = cornerRadiusTR, + .cornerRadiusBL = cornerRadiusBL, + .cornerRadiusBR = cornerRadiusBR, + .alpha = alpha, + .left = static_cast<int>(left), + .top = static_cast<int>(top), + .right = static_cast<int>(right), + .bottom = static_cast<int>(bottom)}); + } + + transaction->setBlurRegions(ctrl, blurRegionVector); +} + static void nativeSetSize(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject, jint w, jint h) { auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj); @@ -1626,6 +1664,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeSetBackgroundBlurRadius }, {"nativeSetLayerStack", "(JJI)V", (void*)nativeSetLayerStack }, + {"nativeSetBlurRegions", "(JJ[[FI)V", + (void*)nativeSetBlurRegions }, {"nativeSetShadowRadius", "(JJF)V", (void*)nativeSetShadowRadius }, {"nativeSetFrameRate", "(JJFI)V", diff --git a/core/proto/android/inputmethodservice/inputmethodservice.proto b/core/proto/android/inputmethodservice/inputmethodservice.proto index 3b4ebb5d73e7..e5d171361695 100644 --- a/core/proto/android/inputmethodservice/inputmethodservice.proto +++ b/core/proto/android/inputmethodservice/inputmethodservice.proto @@ -39,8 +39,8 @@ message InputMethodServiceProto { optional .android.view.inputmethod.EditorInfoProto input_editor_info = 13; optional bool show_input_requested = 14; optional bool last_show_input_requested = 15; - optional bool can_pre_render = 16; - optional bool is_pre_rendered = 17; + reserved 16; // can_pre_render + reserved 17; // is_pre_rendered optional int32 show_input_flags = 18; optional int32 candidates_visibility = 19; optional bool fullscreen_applied = 20; diff --git a/core/proto/android/view/imeinsetssourceconsumer.proto b/core/proto/android/view/imeinsetssourceconsumer.proto index 5bee81bdc7cd..1b9aff989cc8 100644 --- a/core/proto/android/view/imeinsetssourceconsumer.proto +++ b/core/proto/android/view/imeinsetssourceconsumer.proto @@ -28,6 +28,6 @@ option java_multiple_files = true; */ message ImeInsetsSourceConsumerProto { optional InsetsSourceConsumerProto insets_source_consumer = 1; - optional .android.view.inputmethod.EditorInfoProto focused_editor = 2; + reserved 2; // focused_editor = 2 optional bool is_requested_visible_awaiting_control = 3; }
\ No newline at end of file diff --git a/core/res/res/layout/notification_material_action_list.xml b/core/res/res/layout/notification_material_action_list.xml index ffb9603529c2..bf66e69b52d3 100644 --- a/core/res/res/layout/notification_material_action_list.xml +++ b/core/res/res/layout/notification_material_action_list.xml @@ -44,6 +44,14 @@ </com.android.internal.widget.NotificationActionListLayout> <ImageView + android:id="@+id/snooze_button" + android:layout_width="48dp" + android:layout_height="48dp" + android:layout_gravity="center_vertical|end" + android:visibility="gone" + android:scaleType="centerInside" + /> + <ImageView android:id="@+id/bubble_button" android:layout_width="48dp" android:layout_height="48dp" diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index d0fceb094355..393f229b75bb 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"DESACTIVADO"</string> <string name="checked" msgid="9179896827054513119">"seleccionado"</string> <string name="not_checked" msgid="7972320087569023342">"no seleccionado"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"seleccionado"</string> + <string name="not_selected" msgid="410652016565864475">"no seleccionado"</string> <string name="whichApplication" msgid="5432266899591255759">"Completar acción utilizando"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Completar acción con %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Completar acción"</string> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index a3b8f64bf57b..f7f6214cc2b2 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -940,7 +940,7 @@ <string name="double_tap_toast" msgid="7065519579174882778">"ટિપ: ઝૂમ વધારવા અને ઘટાડવા માટે બે વાર ટેપ કરો."</string> <string name="autofill_this_form" msgid="3187132440451621492">"સ્વતઃભરણ"</string> <string name="setup_autofill" msgid="5431369130866618567">"સ્વતઃભરણ સેટ કરો"</string> - <string name="autofill_window_title" msgid="4379134104008111961">"<xliff:g id="SERVICENAME">%1$s</xliff:g> સાથે આપમેળે ભરો"</string> + <string name="autofill_window_title" msgid="4379134104008111961">"<xliff:g id="SERVICENAME">%1$s</xliff:g> સાથે ઑટોમૅટિક રીતે ભરો"</string> <string name="autofill_address_name_separator" msgid="8190155636149596125">" "</string> <string name="autofill_address_summary_name_format" msgid="3402882515222673691">"$1$2$3"</string> <string name="autofill_address_summary_separator" msgid="760522655085707045">", "</string> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index 82a27a85a264..53c92af2da3f 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -1798,7 +1798,7 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"ធ្វើបច្ចុប្បន្នភាពដោយអ្នកគ្រប់គ្រងរបស់អ្នក"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"លុបដោយអ្នកគ្រប់គ្រងរបស់អ្នក"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"យល់ព្រម"</string> - <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"ដើម្បីបង្កើនកម្រិតថាមពលថ្ម កម្មវិធីសន្សំថ្ម៖\n\n• បើករចនាប័ទ្មងងឹត\n• បិទ ឬដាក់កំហិតលើសកម្មភាពផ្ទៃខាងក្រោយ ឥទ្ធិពលជារូបភាពមួយចំនួន និងមុខងារផ្សេងទៀតដូចជា “Ok Google” ជាដើម\n\n"<annotation id="url">"ស្វែងយល់បន្ថែម"</annotation></string> + <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"ដើម្បីបង្កើនកម្រិតថាមពលថ្ម មុខងារសន្សំថ្ម៖\n\n• បើករចនាប័ទ្មងងឹត\n• បិទ ឬដាក់កំហិតលើសកម្មភាពផ្ទៃខាងក្រោយ ឥទ្ធិពលជារូបភាពមួយចំនួន និងមុខងារផ្សេងទៀតដូចជា “Hey Google” ជាដើម\n\n"<annotation id="url">"ស្វែងយល់បន្ថែម"</annotation></string> <string name="battery_saver_description" msgid="6794188153647295212">"ដើម្បីបង្កើនកម្រិតថាមពលថ្ម មុខងារសន្សំថ្ម៖\n\n• បើករចនាប័ទ្មងងឹត\n• បិទ ឬដាក់កំហិតលើសកម្មភាពផ្ទៃខាងក្រោយ ឥទ្ធិពលរូបភាពមួយចំនួន និងមុខងារផ្សេងទៀតដូចជា “Ok Google” ជាដើម"</string> <string name="data_saver_description" msgid="4995164271550590517">"ដើម្បីជួយកាត់បន្ថយការប្រើប្រាស់ទិន្នន័យ កម្មវិធីសន្សំសំចៃទិន្នន័យរារាំងកម្មវិធីមួយចំនួនមិនឲ្យបញ្ជូន ឬទទួលទិន្នន័យនៅផ្ទៃខាងក្រោយទេ។ កម្មវិធីដែលអ្នកកំពុងប្រើនាពេលបច្ចុប្បន្នអាចចូលប្រើប្រាស់ទិន្នន័យបាន ប៉ុន្តែអាចនឹងមិនញឹកញាប់ដូចមុនទេ។ ឧទាហរណ៍ រូបភាពមិនបង្ហាញទេ លុះត្រាតែអ្នកប៉ះរូបភាពទាំងនោះ។"</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"បើកកម្មវិធីសន្សំសំចៃទិន្នន័យ?"</string> @@ -2007,9 +2007,9 @@ <string name="notification_feedback_indicator" msgid="663476517711323016">"ផ្ដល់មតិកែលម្អ"</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ការជូនដំណឹងព័ត៌មានរបស់មុខងារទម្លាប់"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"ថ្មអាចនឹងអស់ មុនពេលសាកថ្មធម្មតា"</string> - <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"បានបើកដំណើរការកម្មវិធីសន្សំថ្ម ដើម្បីបង្កើនកម្រិតថាមពលថ្ម"</string> + <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"បានបើកដំណើរការមុខងារសន្សំថ្ម ដើម្បីបង្កើនកម្រិតថាមពលថ្ម"</string> <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"មុខងារសន្សំថ្ម"</string> - <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"កម្មវិធីសន្សំថ្មត្រូវបានបិទ"</string> + <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"មុខងារសន្សំថ្មត្រូវបានបិទ"</string> <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"ទូរសព្ទមានកម្រិតថ្មគ្រប់គ្រាន់។ មុខងារផ្សេងៗមិនត្រូវបានរឹតបន្តឹងទៀតទេ។"</string> <string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"ថេប្លេតមានកម្រិតថ្មគ្រប់គ្រាន់។ មុខងារផ្សេងៗមិនត្រូវបានរឹតបន្តឹងទៀតទេ។"</string> <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"ឧបករណ៍មានកម្រិតថ្មគ្រប់គ្រាន់។ មុខងារផ្សេងៗមិនត្រូវបានរឹតបន្តឹងទៀតទេ។"</string> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index db5603c8a624..e39d46dfb6f7 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"बंद"</string> <string name="checked" msgid="9179896827054513119">"तपासले"</string> <string name="not_checked" msgid="7972320087569023342">"तपासले नाही"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"निवडला"</string> + <string name="not_selected" msgid="410652016565864475">"निवडला नाही"</string> <string name="whichApplication" msgid="5432266899591255759">"याचा वापर करून क्रिया पूर्ण करा"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s वापरून क्रिया पूर्ण करा"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"क्रिया पूर्ण झाली"</string> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index b5fd7b245555..915e158f3267 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -1129,10 +1129,8 @@ <string name="capital_off" msgid="7443704171014626777">"बन्द"</string> <string name="checked" msgid="9179896827054513119">"जाँच गरिएको"</string> <string name="not_checked" msgid="7972320087569023342">"जाँच गरिएको छैन"</string> - <!-- no translation found for selected (6614607926197755875) --> - <skip /> - <!-- no translation found for not_selected (410652016565864475) --> - <skip /> + <string name="selected" msgid="6614607926197755875">"चयन गरियो"</string> + <string name="not_selected" msgid="410652016565864475">"चयन गरिएन"</string> <string name="whichApplication" msgid="5432266899591255759">"प्रयोग गरेर कारबाही पुरा गर्नुहोस्"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"निम्न एपको प्रयोग गरी कारबाही पुरा गर्नुहोस्: %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"पूर्ण कारबाही"</string> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 7eff3d7bcb06..544be54eb785 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -858,6 +858,7 @@ <dimen name="waterfall_display_right_edge_size">0px</dimen> <dimen name="waterfall_display_bottom_edge_size">0px</dimen> + <dimen name="default_background_blur_radius">100dp</dimen> <!-- The maximum height of a thumbnail in a ThumbnailTemplate. The image will be reduced to that height in case they are bigger. --> <dimen name="controls_thumbnail_image_max_height">140dp</dimen> <!-- The maximum width of a thumbnail in a ThumbnailTemplate. The image will be reduced to that width in case they are bigger.--> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index e4a4e20ee0bb..a294c9d1e537 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3553,6 +3553,7 @@ <java-symbol type="id" name="clip_to_padding_tag" /> <java-symbol type="id" name="clip_children_tag" /> <java-symbol type="id" name="bubble_button" /> + <java-symbol type="id" name="snooze_button" /> <java-symbol type="dimen" name="bubble_visible_padding_end" /> <java-symbol type="dimen" name="bubble_gone_padding_end" /> <java-symbol type="dimen" name="text_size_body_2_material" /> @@ -4078,6 +4079,7 @@ <java-symbol type="integer" name="config_defaultBinderHeavyHitterAutoSamplerBatchSize" /> <java-symbol type="dimen" name="config_defaultBinderHeavyHitterAutoSamplerThreshold" /> + <java-symbol type="dimen" name="default_background_blur_radius" /> <java-symbol type="array" name="config_keep_warming_services" /> <java-symbol type="string" name="config_display_features" /> <java-symbol type="array" name="config_internalFoldedPhysicalDisplayIds" /> diff --git a/core/tests/coretests/src/android/app/appsearch/external/app/AppSearchEmailTest.java b/core/tests/coretests/src/android/app/appsearch/external/app/AppSearchEmailTest.java index ac2d4b5c5f7d..2f2bef8bc5cc 100644 --- a/core/tests/coretests/src/android/app/appsearch/external/app/AppSearchEmailTest.java +++ b/core/tests/coretests/src/android/app/appsearch/external/app/AppSearchEmailTest.java @@ -30,7 +30,7 @@ public class AppSearchEmailTest { // Score and Property are mixed into the middle to make sure DocumentBuilder's // methods can be interleaved with EmailBuilder's methods. .setScore(1) - .setProperty("propertyKey", "propertyValue1", "propertyValue2") + .setPropertyString("propertyKey", "propertyValue1", "propertyValue2") .setSubject("subject") .setBody("EmailBody") .build(); diff --git a/core/tests/coretests/src/android/app/appsearch/external/app/GenericDocumentTest.java b/core/tests/coretests/src/android/app/appsearch/external/app/GenericDocumentTest.java index 1f2c12bca028..9c29943dbef4 100644 --- a/core/tests/coretests/src/android/app/appsearch/external/app/GenericDocumentTest.java +++ b/core/tests/coretests/src/android/app/appsearch/external/app/GenericDocumentTest.java @@ -39,22 +39,22 @@ public class GenericDocumentTest { GenericDocument document1 = new GenericDocument.Builder("uri1", "schemaType1") .setCreationTimestampMillis(5L) .setTtlMillis(1L) - .setProperty("longKey1", 1L, 2L, 3L) - .setProperty("doubleKey1", 1.0, 2.0, 3.0) - .setProperty("booleanKey1", true, false, true) - .setProperty("stringKey1", "test-value1", "test-value2", "test-value3") - .setProperty("byteKey1", sByteArray1, sByteArray2) - .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2) + .setPropertyLong("longKey1", 1L, 2L, 3L) + .setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0) + .setPropertyBoolean("booleanKey1", true, false, true) + .setPropertyString("stringKey1", "test-value1", "test-value2", "test-value3") + .setPropertyBytes("byteKey1", sByteArray1, sByteArray2) + .setPropertyDocument("documentKey1", sDocumentProperties1, sDocumentProperties2) .build(); GenericDocument document2 = new GenericDocument.Builder("uri1", "schemaType1") .setCreationTimestampMillis(5L) .setTtlMillis(1L) - .setProperty("longKey1", 1L, 2L, 3L) - .setProperty("doubleKey1", 1.0, 2.0, 3.0) - .setProperty("booleanKey1", true, false, true) - .setProperty("stringKey1", "test-value1", "test-value2", "test-value3") - .setProperty("byteKey1", sByteArray1, sByteArray2) - .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2) + .setPropertyLong("longKey1", 1L, 2L, 3L) + .setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0) + .setPropertyBoolean("booleanKey1", true, false, true) + .setPropertyString("stringKey1", "test-value1", "test-value2", "test-value3") + .setPropertyBytes("byteKey1", sByteArray1, sByteArray2) + .setPropertyDocument("documentKey1", sDocumentProperties1, sDocumentProperties2) .build(); assertThat(document1).isEqualTo(document2); assertThat(document1.hashCode()).isEqualTo(document2.hashCode()); @@ -64,23 +64,23 @@ public class GenericDocumentTest { public void testDocumentEquals_DifferentOrder() { GenericDocument document1 = new GenericDocument.Builder("uri1", "schemaType1") .setCreationTimestampMillis(5L) - .setProperty("longKey1", 1L, 2L, 3L) - .setProperty("byteKey1", sByteArray1, sByteArray2) - .setProperty("doubleKey1", 1.0, 2.0, 3.0) - .setProperty("booleanKey1", true, false, true) - .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2) - .setProperty("stringKey1", "test-value1", "test-value2", "test-value3") + .setPropertyLong("longKey1", 1L, 2L, 3L) + .setPropertyBytes("byteKey1", sByteArray1, sByteArray2) + .setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0) + .setPropertyBoolean("booleanKey1", true, false, true) + .setPropertyDocument("documentKey1", sDocumentProperties1, sDocumentProperties2) + .setPropertyString("stringKey1", "test-value1", "test-value2", "test-value3") .build(); // Create second document with same parameter but different order. GenericDocument document2 = new GenericDocument.Builder("uri1", "schemaType1") .setCreationTimestampMillis(5L) - .setProperty("booleanKey1", true, false, true) - .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2) - .setProperty("stringKey1", "test-value1", "test-value2", "test-value3") - .setProperty("doubleKey1", 1.0, 2.0, 3.0) - .setProperty("byteKey1", sByteArray1, sByteArray2) - .setProperty("longKey1", 1L, 2L, 3L) + .setPropertyBoolean("booleanKey1", true, false, true) + .setPropertyDocument("documentKey1", sDocumentProperties1, sDocumentProperties2) + .setPropertyString("stringKey1", "test-value1", "test-value2", "test-value3") + .setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0) + .setPropertyBytes("byteKey1", sByteArray1, sByteArray2) + .setPropertyLong("longKey1", 1L, 2L, 3L) .build(); assertThat(document1).isEqualTo(document2); assertThat(document1.hashCode()).isEqualTo(document2.hashCode()); @@ -90,13 +90,13 @@ public class GenericDocumentTest { public void testDocumentEquals_Failure() { GenericDocument document1 = new GenericDocument.Builder("uri1", "schemaType1") .setCreationTimestampMillis(5L) - .setProperty("longKey1", 1L, 2L, 3L) + .setPropertyLong("longKey1", 1L, 2L, 3L) .build(); // Create second document with same order but different value. GenericDocument document2 = new GenericDocument.Builder("uri1", "schemaType1") .setCreationTimestampMillis(5L) - .setProperty("longKey1", 1L, 2L, 4L) // Different + .setPropertyLong("longKey1", 1L, 2L, 4L) // Different .build(); assertThat(document1).isNotEqualTo(document2); assertThat(document1.hashCode()).isNotEqualTo(document2.hashCode()); @@ -106,13 +106,13 @@ public class GenericDocumentTest { public void testDocumentEquals_Failure_RepeatedFieldOrder() { GenericDocument document1 = new GenericDocument.Builder("uri1", "schemaType1") .setCreationTimestampMillis(5L) - .setProperty("booleanKey1", true, false, true) + .setPropertyBoolean("booleanKey1", true, false, true) .build(); // Create second document with same order but different value. GenericDocument document2 = new GenericDocument.Builder("uri1", "schemaType1") .setCreationTimestampMillis(5L) - .setProperty("booleanKey1", true, true, false) // Different + .setPropertyBoolean("booleanKey1", true, true, false) // Different .build(); assertThat(document1).isNotEqualTo(document2); assertThat(document1.hashCode()).isNotEqualTo(document2.hashCode()); @@ -124,12 +124,12 @@ public class GenericDocumentTest { .setCreationTimestampMillis(5L) .setScore(1) .setTtlMillis(1L) - .setProperty("longKey1", 1L) - .setProperty("doubleKey1", 1.0) - .setProperty("booleanKey1", true) - .setProperty("stringKey1", "test-value1") - .setProperty("byteKey1", sByteArray1) - .setProperty("documentKey1", sDocumentProperties1) + .setPropertyLong("longKey1", 1L) + .setPropertyDouble("doubleKey1", 1.0) + .setPropertyBoolean("booleanKey1", true) + .setPropertyString("stringKey1", "test-value1") + .setPropertyBytes("byteKey1", sByteArray1) + .setPropertyDocument("documentKey1", sDocumentProperties1) .build(); assertThat(document.getUri()).isEqualTo("uri1"); assertThat(document.getTtlMillis()).isEqualTo(1L); @@ -149,12 +149,12 @@ public class GenericDocumentTest { public void testDocumentGetArrayValues() { GenericDocument document = new GenericDocument.Builder("uri1", "schemaType1") .setCreationTimestampMillis(5L) - .setProperty("longKey1", 1L, 2L, 3L) - .setProperty("doubleKey1", 1.0, 2.0, 3.0) - .setProperty("booleanKey1", true, false, true) - .setProperty("stringKey1", "test-value1", "test-value2", "test-value3") - .setProperty("byteKey1", sByteArray1, sByteArray2) - .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2) + .setPropertyLong("longKey1", 1L, 2L, 3L) + .setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0) + .setPropertyBoolean("booleanKey1", true, false, true) + .setPropertyString("stringKey1", "test-value1", "test-value2", "test-value3") + .setPropertyBytes("byteKey1", sByteArray1, sByteArray2) + .setPropertyDocument("documentKey1", sDocumentProperties1, sDocumentProperties2) .build(); assertThat(document.getUri()).isEqualTo("uri1"); @@ -176,12 +176,12 @@ public class GenericDocumentTest { public void testDocument_ToString() throws Exception { GenericDocument document = new GenericDocument.Builder("uri1", "schemaType1") .setCreationTimestampMillis(5L) - .setProperty("longKey1", 1L, 2L, 3L) - .setProperty("doubleKey1", 1.0, 2.0, 3.0) - .setProperty("booleanKey1", true, false, true) - .setProperty("stringKey1", "String1", "String2", "String3") - .setProperty("byteKey1", sByteArray1, sByteArray2) - .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2) + .setPropertyLong("longKey1", 1L, 2L, 3L) + .setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0) + .setPropertyBoolean("booleanKey1", true, false, true) + .setPropertyString("stringKey1", "String1", "String2", "String3") + .setPropertyBytes("byteKey1", sByteArray1, sByteArray2) + .setPropertyDocument("documentKey1", sDocumentProperties1, sDocumentProperties2) .build(); String exceptedString = "{ key: 'creationTimestampMillis' value: 5 } " + "{ key: 'namespace' value: } " @@ -219,9 +219,9 @@ public class GenericDocumentTest { public void testDocumentGetValues_DifferentTypes() { GenericDocument document = new GenericDocument.Builder("uri1", "schemaType1") .setScore(1) - .setProperty("longKey1", 1L) - .setProperty("booleanKey1", true, false, true) - .setProperty("stringKey1", "test-value1", "test-value2", "test-value3") + .setPropertyLong("longKey1", 1L) + .setPropertyBoolean("booleanKey1", true, false, true) + .setPropertyString("stringKey1", "test-value1", "test-value2", "test-value3") .build(); // Get a value for a key that doesn't exist @@ -246,6 +246,7 @@ public class GenericDocumentTest { public void testDocumentInvalid() { GenericDocument.Builder builder = new GenericDocument.Builder("uri1", "schemaType1"); expectThrows( - IllegalArgumentException.class, () -> builder.setProperty("test", new boolean[]{})); + IllegalArgumentException.class, + () -> builder.setPropertyBoolean("test", new boolean[]{})); } } diff --git a/core/tests/coretests/src/android/app/appsearch/external/app/SearchSpecTest.java b/core/tests/coretests/src/android/app/appsearch/external/app/SearchSpecTest.java new file mode 100644 index 000000000000..d4635fdda052 --- /dev/null +++ b/core/tests/coretests/src/android/app/appsearch/external/app/SearchSpecTest.java @@ -0,0 +1,92 @@ +/* + * 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 android.app.appsearch; + +import static com.google.common.truth.Truth.assertThat; + +import static org.testng.Assert.expectThrows; + +import android.os.Bundle; + +import org.junit.Test; + +public class SearchSpecTest { + @Test + public void buildSearchSpecWithoutTermMatchType() { + expectThrows(RuntimeException.class, () -> new SearchSpec.Builder() + .addSchema("testSchemaType") + .build()); + } + + @Test + public void testBuildSearchSpec() { + SearchSpec searchSpec = new SearchSpec.Builder() + .setTermMatch(SearchSpec.TERM_MATCH_PREFIX) + .addNamespace("namespace1", "namespace2") + .addSchema("schemaTypes1", "schemaTypes2") + .setSnippetCount(5) + .setSnippetCountPerProperty(10) + .setMaxSnippetSize(15) + .setNumPerPage(42) + .setOrder(SearchSpec.ORDER_ASCENDING) + .setRankingStrategy(SearchSpec.RANKING_STRATEGY_DOCUMENT_SCORE) + .build(); + + assertThat(searchSpec.getTermMatch()).isEqualTo(SearchSpec.TERM_MATCH_PREFIX); + assertThat(searchSpec.getNamespaces()) + .containsExactly("namespace1", "namespace2").inOrder(); + assertThat(searchSpec.getSchemas()) + .containsExactly("schemaTypes1", "schemaTypes2").inOrder(); + assertThat(searchSpec.getSnippetCount()).isEqualTo(5); + assertThat(searchSpec.getSnippetCountPerProperty()).isEqualTo(10); + assertThat(searchSpec.getMaxSnippetSize()).isEqualTo(15); + assertThat(searchSpec.getNumPerPage()).isEqualTo(42); + assertThat(searchSpec.getOrder()).isEqualTo(SearchSpec.ORDER_ASCENDING); + assertThat(searchSpec.getRankingStrategy()) + .isEqualTo(SearchSpec.RANKING_STRATEGY_DOCUMENT_SCORE); + } + + @Test + public void testGetBundle() { + SearchSpec searchSpec = new SearchSpec.Builder() + .setTermMatch(SearchSpec.TERM_MATCH_PREFIX) + .addNamespace("namespace1", "namespace2") + .addSchema("schemaTypes1", "schemaTypes2") + .setSnippetCount(5) + .setSnippetCountPerProperty(10) + .setMaxSnippetSize(15) + .setNumPerPage(42) + .setOrder(SearchSpec.ORDER_ASCENDING) + .setRankingStrategy(SearchSpec.RANKING_STRATEGY_DOCUMENT_SCORE) + .build(); + + Bundle bundle = searchSpec.getBundle(); + assertThat(bundle.getInt(SearchSpec.TERM_MATCH_TYPE_FIELD)) + .isEqualTo(SearchSpec.TERM_MATCH_PREFIX); + assertThat(bundle.getStringArrayList(SearchSpec.NAMESPACE_FIELD)).containsExactly( + "namespace1", "namespace2"); + assertThat(bundle.getStringArrayList(SearchSpec.SCHEMA_TYPE_FIELD)).containsExactly( + "schemaTypes1", "schemaTypes2"); + assertThat(bundle.getInt(SearchSpec.SNIPPET_COUNT_FIELD)).isEqualTo(5); + assertThat(bundle.getInt(SearchSpec.SNIPPET_COUNT_PER_PROPERTY_FIELD)).isEqualTo(10); + assertThat(bundle.getInt(SearchSpec.MAX_SNIPPET_FIELD)).isEqualTo(15); + assertThat(bundle.getInt(SearchSpec.NUM_PER_PAGE_FIELD)).isEqualTo(42); + assertThat(bundle.getInt(SearchSpec.ORDER_FIELD)).isEqualTo(SearchSpec.ORDER_ASCENDING); + assertThat(bundle.getInt(SearchSpec.RANKING_STRATEGY_FIELD)) + .isEqualTo(SearchSpec.RANKING_STRATEGY_DOCUMENT_SCORE); + } +} diff --git a/core/tests/coretests/src/android/app/appsearch/external/app/customer/CustomerDocumentTest.java b/core/tests/coretests/src/android/app/appsearch/external/app/customer/CustomerDocumentTest.java index 2c7c35feface..d56d0c3c5c8e 100644 --- a/core/tests/coretests/src/android/app/appsearch/external/app/customer/CustomerDocumentTest.java +++ b/core/tests/coretests/src/android/app/appsearch/external/app/customer/CustomerDocumentTest.java @@ -46,12 +46,12 @@ public class CustomerDocumentTest { CustomerDocument customerDocument = new CustomerDocument.Builder("uri1") .setScore(1) .setCreationTimestampMillis(0) - .setProperty("longKey1", 1L, 2L, 3L) - .setProperty("doubleKey1", 1.0, 2.0, 3.0) - .setProperty("booleanKey1", true, false, true) - .setProperty("stringKey1", "test-value1", "test-value2", "test-value3") - .setProperty("byteKey1", sByteArray1, sByteArray2) - .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2) + .setPropertyLong("longKey1", 1L, 2L, 3L) + .setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0) + .setPropertyBoolean("booleanKey1", true, false, true) + .setPropertyString("stringKey1", "test-value1", "test-value2", "test-value3") + .setPropertyBytes("byteKey1", sByteArray1, sByteArray2) + .setPropertyDocument("documentKey1", sDocumentProperties1, sDocumentProperties2) .build(); assertThat(customerDocument.getUri()).isEqualTo("uri1"); diff --git a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java index a5b7c6156109..db838e81eb28 100644 --- a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java +++ b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java @@ -17,7 +17,6 @@ package android.view; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; -import static android.view.ImeInsetsSourceConsumer.areEditorsSimilar; import static android.view.InsetsState.ITYPE_IME; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; @@ -33,11 +32,9 @@ import android.content.Context; import android.graphics.Insets; import android.graphics.Point; import android.graphics.Rect; -import android.os.Bundle; import android.platform.test.annotations.Presubmit; import android.view.WindowManager.BadTokenException; import android.view.WindowManager.LayoutParams; -import android.view.inputmethod.EditorInfo; import android.widget.TextView; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -50,8 +47,6 @@ import org.junit.runner.RunWith; import org.mockito.Mockito; import org.mockito.Spy; -import java.util.ArrayList; - /** * Test {@link InsetsSourceConsumer} with IME type. * @@ -133,50 +128,4 @@ public class ImeInsetsSourceConsumerTest { eq(WindowInsets.Type.ime()), eq(false) /* show */, eq(true) /* fromIme */); }); } - - @Test - public void testAreEditorsSimilar() { - EditorInfo info1 = new EditorInfo(); - info1.privateImeOptions = "dummy"; - EditorInfo info2 = new EditorInfo(); - - assertFalse(areEditorsSimilar(info1, info2)); - - info1.privateImeOptions = null; - assertTrue(areEditorsSimilar(info1, info2)); - - info1.inputType = info2.inputType = 3; - info1.imeOptions = info2.imeOptions = 0x4; - info1.packageName = info2.packageName = "dummy.package"; - assertTrue(areEditorsSimilar(info1, info2)); - - Bundle extras1 = new Bundle(); - extras1.putByteArray("key1", "value1".getBytes()); - extras1.putChar("key2", 'c'); - Bundle extras2 = new Bundle(); - extras2.putByteArray("key1", "value1".getBytes()); - extras2.putChar("key2", 'c'); - info1.extras = extras1; - info2.extras = extras2; - assertTrue(areEditorsSimilar(info1, info2)); - - Bundle extraBundle = new Bundle(); - ArrayList<Integer> list = new ArrayList<>(); - list.add(2); - list.add(5); - extraBundle.putByteArray("key1", "value1".getBytes()); - extraBundle.putChar("key2", 'c'); - extraBundle.putIntegerArrayList("key3", list); - - extras1.putAll(extraBundle); - extras2.putAll(extraBundle); - assertTrue(areEditorsSimilar(info1, info2)); - - extras2.putChar("key2", 'd'); - assertFalse(areEditorsSimilar(info1, info2)); - - extras2.putChar("key2", 'c'); - extras2.putInt("key4", 1); - assertFalse(areEditorsSimilar(info1, info2)); - } } diff --git a/core/tests/coretests/src/android/widget/TextViewOnReceiveContentCallbackTest.java b/core/tests/coretests/src/android/widget/TextViewOnReceiveContentTest.java index ef659af6c570..8efd3b4f0135 100644 --- a/core/tests/coretests/src/android/widget/TextViewOnReceiveContentCallbackTest.java +++ b/core/tests/coretests/src/android/widget/TextViewOnReceiveContentTest.java @@ -63,12 +63,12 @@ import org.mockito.Mockito; /** * Tests for {@link TextViewOnReceiveContentCallback}. Most of the test cases are in the CTS test - * {@link android.widget.cts.TextViewOnReceiveContentCallbackTest}. This class tests some internal + * {@link android.widget.cts.TextViewOnReceiveContentTest}. This class tests some internal * implementation details, e.g. fallback to the keyboard image API. */ @MediumTest @RunWith(AndroidJUnit4.class) -public class TextViewOnReceiveContentCallbackTest { +public class TextViewOnReceiveContentTest { private static final Uri SAMPLE_CONTENT_URI = Uri.parse("content://com.example/path"); @Rule diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java index 8f5982cd4528..7abcfdc98bc6 100644 --- a/keystore/java/android/security/Credentials.java +++ b/keystore/java/android/security/Credentials.java @@ -49,18 +49,38 @@ public class Credentials { public static final String INSTALL_AS_USER_ACTION = "android.credentials.INSTALL_AS_USER"; - /** Key prefix for CA certificates. */ + /** + * Key prefix for CA certificates. + * + * @deprecated Keystore no longer supports unstructured blobs. Public certificates are + * stored in typed slots associated with a given alias. + */ + @Deprecated public static final String CA_CERTIFICATE = "CACERT_"; - /** Key prefix for user certificates. */ + /** + * Key prefix for user certificates. + * + * @deprecated Keystore no longer supports unstructured blobs. Public certificates are + * stored in typed slots associated with a given alias. + */ + @Deprecated public static final String USER_CERTIFICATE = "USRCERT_"; - /** Key prefix for user private and secret keys. */ + /** + * Key prefix for user private and secret keys. + * + * @deprecated Keystore no longer uses alias prefixes to discriminate between entry types. + */ + @Deprecated public static final String USER_PRIVATE_KEY = "USRPKEY_"; - /** Key prefix for user secret keys. - * @deprecated use {@code USER_PRIVATE_KEY} for this category instead. + /** + * Key prefix for user secret keys. + * + * @deprecated use {@code USER_PRIVATE_KEY} for this category instead. */ + @Deprecated public static final String USER_SECRET_KEY = "USRSKEY_"; /** Key prefix for VPN. */ @@ -72,7 +92,13 @@ public class Credentials { /** Key prefix for WIFI. */ public static final String WIFI = "WIFI_"; - /** Key prefix for App Source certificates. */ + /** + * Key prefix for App Source certificates. + * + * @deprecated This was intended for FS-verity but never used. FS-verity is not + * going to use this constant moving forward. + */ + @Deprecated public static final String APP_SOURCE_CERTIFICATE = "FSV_"; /** Key containing suffix of lockdown VPN profile. */ @@ -150,6 +176,7 @@ public class Credentials { pw.close(); return bao.toByteArray(); } + /** * Convert objects from PEM format, which is used for * CA_CERTIFICATE and USER_CERTIFICATE entries. @@ -167,7 +194,8 @@ public class Credentials { PemObject o; while ((o = pr.readPemObject()) != null) { if (o.getType().equals("CERTIFICATE")) { - Certificate c = cf.generateCertificate(new ByteArrayInputStream(o.getContent())); + Certificate c = cf.generateCertificate( + new ByteArrayInputStream(o.getContent())); result.add((X509Certificate) c); } else { throw new IllegalArgumentException("Unknown type " + o.getType()); diff --git a/keystore/java/android/security/KeyPairGeneratorSpec.java b/keystore/java/android/security/KeyPairGeneratorSpec.java index d5b34c432e79..1c1c2eeee794 100644 --- a/keystore/java/android/security/KeyPairGeneratorSpec.java +++ b/keystore/java/android/security/KeyPairGeneratorSpec.java @@ -16,9 +16,9 @@ package android.security; -import android.app.KeyguardManager; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.KeyguardManager; import android.content.Context; import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyProperties; @@ -78,8 +78,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { private final Date mEndDate; - private final int mFlags; - /** * Parameter specification for the "{@code AndroidKeyPairGenerator}" * instance of the {@link java.security.KeyPairGenerator} API. The @@ -144,7 +142,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { mSerialNumber = serialNumber; mStartDate = startDate; mEndDate = endDate; - mFlags = flags; } /** @@ -229,7 +226,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * @hide */ public int getFlags() { - return mFlags; + return 0; } /** @@ -243,9 +240,15 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * screen after boot. * * @see KeyguardManager#isDeviceSecure() + * + * @deprecated Encryption at rest is on by default. If extra binding to the lockscreen screen + * credential is desired use + * {@link KeyGenParameterSpec.Builder#setUserAuthenticationRequired(boolean)}. + * This flag will be ignored from Android S. */ + @Deprecated public boolean isEncryptionRequired() { - return (mFlags & KeyStore.FLAG_ENCRYPTED) != 0; + return false; } /** @@ -292,8 +295,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { private Date mEndDate; - private int mFlags; - /** * Creates a new instance of the {@code Builder} with the given * {@code context}. The {@code context} passed in may be used to pop up @@ -431,10 +432,15 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * secure lock screen after boot. * * @see KeyguardManager#isDeviceSecure() + * + * @deprecated Data at rest encryption is enabled by default. If extra binding to the + * lockscreen credential is desired, use + * {@link KeyGenParameterSpec.Builder#setUserAuthenticationRequired(boolean)}. + * This flag will be ignored from Android S. */ @NonNull + @Deprecated public Builder setEncryptionRequired() { - mFlags |= KeyStore.FLAG_ENCRYPTED; return this; } @@ -455,7 +461,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { mSerialNumber, mStartDate, mEndDate, - mFlags); + 0); } } } diff --git a/keystore/java/android/security/KeyStoreParameter.java b/keystore/java/android/security/KeyStoreParameter.java index 66c87ed2ec1e..51d29b13ce80 100644 --- a/keystore/java/android/security/KeyStoreParameter.java +++ b/keystore/java/android/security/KeyStoreParameter.java @@ -48,18 +48,16 @@ import java.security.KeyStore.ProtectionParameter; */ @Deprecated public final class KeyStoreParameter implements ProtectionParameter { - private final int mFlags; private KeyStoreParameter( int flags) { - mFlags = flags; } /** * @hide */ public int getFlags() { - return mFlags; + return 0; } /** @@ -74,9 +72,16 @@ public final class KeyStoreParameter implements ProtectionParameter { * screen after boot. * * @see KeyguardManager#isDeviceSecure() + * + * @deprecated Data at rest encryption is enabled by default. If extra binding to the + * lockscreen credential is desired, use + * {@link android.security.keystore.KeyGenParameterSpec + * .Builder#setUserAuthenticationRequired(boolean)}. + * This flag will be ignored from Android S. */ + @Deprecated public boolean isEncryptionRequired() { - return (mFlags & KeyStore.FLAG_ENCRYPTED) != 0; + return false; } /** @@ -100,7 +105,6 @@ public final class KeyStoreParameter implements ProtectionParameter { */ @Deprecated public final static class Builder { - private int mFlags; /** * Creates a new instance of the {@code Builder} with the given @@ -126,14 +130,15 @@ public final class KeyStoreParameter implements ProtectionParameter { * the user unlocks the secure lock screen after boot. * * @see KeyguardManager#isDeviceSecure() + * + * @deprecated Data at rest encryption is enabled by default. If extra binding to the + * lockscreen credential is desired, use + * {@link android.security.keystore.KeyGenParameterSpec + * .Builder#setUserAuthenticationRequired(boolean)}. + * This flag will be ignored from Android S. */ @NonNull public Builder setEncryptionRequired(boolean required) { - if (required) { - mFlags |= KeyStore.FLAG_ENCRYPTED; - } else { - mFlags &= ~KeyStore.FLAG_ENCRYPTED; - } return this; } @@ -145,8 +150,7 @@ public final class KeyStoreParameter implements ProtectionParameter { */ @NonNull public KeyStoreParameter build() { - return new KeyStoreParameter( - mFlags); + return new KeyStoreParameter(0 /* flags */); } } } diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index 1d85e9fceac9..b87a642a8dc7 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -57,6 +57,9 @@ <dimen name="pip_resize_handle_margin">4dp</dimen> <dimen name="pip_resize_handle_padding">0dp</dimen> + <!-- PIP stash offset size, which is the width of visible PIP region when stashed. --> + <dimen name="pip_stash_offset">32dp</dimen> + <dimen name="dismiss_target_x_size">24dp</dimen> <dimen name="floating_dismiss_bottom_margin">50dp</dimen> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java index d4ff275d426d..51ddb17daa00 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java @@ -335,6 +335,12 @@ public class ShellTaskOrganizer extends TaskOrganizer { listener = mTaskListeners.get(taskId); if (listener != null) return listener; + // Next priority goes to the listener listening to its parent. + if (runningTaskInfo.hasParentTask()) { + listener = mTaskListeners.get(runningTaskInfo.parentTaskId); + if (listener != null) return listener; + } + // Next we try type specific listeners. final int taskListenerType = taskInfoToTaskListenerType(runningTaskInfo); return mTaskListeners.get(taskListenerType); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java index d0ab31dd72c8..fc523aef9d16 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java @@ -37,6 +37,7 @@ public final class PipBoundsState { private final @NonNull Rect mBounds = new Rect(); private float mAspectRatio; + private boolean mIsStashed; private PipReentryState mPipReentryState; private ComponentName mLastPipComponentName; private final DisplayInfo mDisplayInfo = new DisplayInfo(); @@ -54,6 +55,20 @@ public final class PipBoundsState { return new Rect(mBounds); } + /** + * Dictate where PiP currently should be stashed or not. + */ + public void setStashed(boolean isStashed) { + mIsStashed = isStashed; + } + + /** + * Whether PiP is stashed or not. + */ + public boolean isStashed() { + return mIsStashed; + } + public void setAspectRatio(float aspectRatio) { mAspectRatio = aspectRatio; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java index 9240b3f41ff4..9247c683a082 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java @@ -33,6 +33,7 @@ import androidx.dynamicanimation.animation.AnimationHandler; import androidx.dynamicanimation.animation.AnimationHandler.FrameCallbackScheduler; import androidx.dynamicanimation.animation.SpringForce; +import com.android.wm.shell.R; import com.android.wm.shell.animation.FloatProperties; import com.android.wm.shell.animation.PhysicsAnimator; import com.android.wm.shell.common.FloatingContentCoordinator; @@ -60,7 +61,6 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, private static final int EXPAND_STACK_TO_MENU_DURATION = 250; private static final int LEAVE_PIP_DURATION = 300; private static final int SHIFT_DURATION = 300; - private static final float STASH_RATIO = 0.25f; /** Friction to use for PIP when it moves via physics fling animations. */ private static final float DEFAULT_FRICTION = 2f; @@ -94,6 +94,8 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, /** The destination bounds to which PIP is animating. */ private final Rect mAnimatingToBounds = new Rect(); + private int mStashOffset = 0; + /** Coordinator instance for resolving conflicts with other floating content. */ private FloatingContentCoordinator mFloatingContentCoordinator; @@ -189,6 +191,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, mPipTaskOrganizer.registerPipTransitionCallback(mPipTransitionCallback); mTemporaryBoundsPhysicsAnimator.setCustomAnimationHandler( mSfAnimationHandlerThreadLocal.get()); + reloadResources(); mResizePipUpdateListener = (target, values) -> { if (!mTemporaryBounds.isEmpty()) { @@ -198,6 +201,11 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, }; } + void reloadResources() { + mStashOffset = mContext.getResources() + .getDimensionPixelSize(R.dimen.pip_stash_offset); + } + @NonNull @Override public Rect getFloatingBoundsOnScreen() { @@ -414,9 +422,10 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, FloatProperties.RECT_Y, velocityY, mFlingConfigY, mSpringConfig) .withEndActions(endAction); - final float offset = ((float) getBounds().width()) * (1.0f - STASH_RATIO); - final float leftEdge = isStash ? mMovementBounds.left - offset : mMovementBounds.left; - final float rightEdge = isStash ? mMovementBounds.right + offset : mMovementBounds.right; + final float leftEdge = isStash ? mStashOffset - mPipBoundsState.getBounds().width() + : mMovementBounds.left; + final float rightEdge = isStash ? mPipBoundsState.getDisplayBounds().right - mStashOffset + : mMovementBounds.right; final float xEndValue = velocityX < 0 ? leftEdge : rightEdge; final float estimatedFlingYEndValue = @@ -524,9 +533,9 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, DEFAULT_FRICTION, mMovementBounds.left, mMovementBounds.right); mFlingConfigY = new PhysicsAnimator.FlingConfig( DEFAULT_FRICTION, mMovementBounds.top, mMovementBounds.bottom); - final float offset = ((float) getBounds().width()) * (1.0f - STASH_RATIO); mStashConfigX = new PhysicsAnimator.FlingConfig( - DEFAULT_FRICTION, mMovementBounds.left - offset, mMovementBounds.right + offset); + DEFAULT_FRICTION, mStashOffset - mPipBoundsState.getBounds().width(), + mPipBoundsState.getDisplayBounds().right - mStashOffset); } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java index ef3875597aa2..f3d8c7b0f598 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java @@ -47,6 +47,7 @@ import androidx.annotation.VisibleForTesting; import com.android.internal.policy.TaskResizingAlgorithm; import com.android.wm.shell.R; import com.android.wm.shell.pip.PipBoundsHandler; +import com.android.wm.shell.pip.PipBoundsState; import com.android.wm.shell.pip.PipTaskOrganizer; import com.android.wm.shell.pip.PipUiEventLogger; @@ -67,6 +68,7 @@ public class PipResizeGestureHandler { private final Context mContext; private final PipBoundsHandler mPipBoundsHandler; private final PipMotionHelper mMotionHelper; + private final PipBoundsState mPipBoundsState; private final int mDisplayId; private final Executor mMainExecutor; private final ScaleGestureDetector mScaleGestureDetector; @@ -107,13 +109,15 @@ public class PipResizeGestureHandler { private int mCtrlType; public PipResizeGestureHandler(Context context, PipBoundsHandler pipBoundsHandler, - PipMotionHelper motionHelper, PipTaskOrganizer pipTaskOrganizer, - Function<Rect, Rect> movementBoundsSupplier, Runnable updateMovementBoundsRunnable, - PipUiEventLogger pipUiEventLogger, PipMenuActivityController menuActivityController) { + PipBoundsState pipBoundsState, PipMotionHelper motionHelper, + PipTaskOrganizer pipTaskOrganizer, Function<Rect, Rect> movementBoundsSupplier, + Runnable updateMovementBoundsRunnable, PipUiEventLogger pipUiEventLogger, + PipMenuActivityController menuActivityController) { mContext = context; mDisplayId = context.getDisplayId(); mMainExecutor = context.getMainExecutor(); mPipBoundsHandler = pipBoundsHandler; + mPipBoundsState = pipBoundsState; mMotionHelper = motionHelper; mPipTaskOrganizer = pipTaskOrganizer; mMovementBoundsSupplier = movementBoundsSupplier; @@ -263,6 +267,11 @@ public class PipResizeGestureHandler { } private void onInputEvent(InputEvent ev) { + // Don't allow resize when PiP is stashed. + if (mPipBoundsState.isStashed()) { + return; + } + if (ev instanceof MotionEvent) { if (mUsingPinchToZoom) { mScaleGestureDetector.onTouchEvent((MotionEvent) ev); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java index e95e4a07ed92..d820e772d490 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java @@ -179,8 +179,8 @@ public class PipTouchHandler { mMotionHelper = new PipMotionHelper(mContext, pipBoundsState, pipTaskOrganizer, mMenuController, mPipBoundsHandler.getSnapAlgorithm(), floatingContentCoordinator); mPipResizeGestureHandler = - new PipResizeGestureHandler(context, pipBoundsHandler, mMotionHelper, - pipTaskOrganizer, this::getMovementBounds, + new PipResizeGestureHandler(context, pipBoundsHandler, pipBoundsState, + mMotionHelper, pipTaskOrganizer, this::getMovementBounds, this::updateMovementBounds, pipUiEventLogger, menuController); mPipDismissTargetHandler = new PipDismissTargetHandler(context, pipUiEventLogger, mMotionHelper, mHandler); @@ -221,6 +221,7 @@ public class PipTouchHandler { R.dimen.pip_expanded_shortest_edge_size); mImeOffset = res.getDimensionPixelSize(R.dimen.pip_ime_offset); mPipDismissTargetHandler.updateMagneticTargetSize(); + mMotionHelper.reloadResources(); } private boolean shouldShowResizeHandle() { @@ -463,7 +464,7 @@ public class PipTouchHandler { } MotionEvent ev = (MotionEvent) inputEvent; - if (mPipResizeGestureHandler.willStartResizeGesture(ev)) { + if (!mPipBoundsState.isStashed() && mPipResizeGestureHandler.willStartResizeGesture(ev)) { // Initialize the touch state for the gesture, but immediately reset to invalidate the // gesture mTouchState.onTouchEvent(ev); @@ -553,6 +554,8 @@ public class PipTouchHandler { } } + shouldDeliverToMenu |= !mPipBoundsState.isStashed(); + // Deliver the event to PipMenuActivity to handle button click if the menu has shown. if (shouldDeliverToMenu) { final MotionEvent cloneEvent = MotionEvent.obtain(ev); @@ -715,7 +718,7 @@ public class PipTouchHandler { // If the menu is still visible then just poke the menu // so that it will timeout after the user stops touching it - if (mMenuState != MENU_STATE_NONE) { + if (mMenuState != MENU_STATE_NONE && !mPipBoundsState.isStashed()) { mMenuController.pokeMenu(); } } @@ -727,6 +730,7 @@ public class PipTouchHandler { } if (touchState.startedDragging()) { + mPipBoundsState.setStashed(false); mSavedSnapFraction = -1f; mPipDismissTargetHandler.showDismissTargetMaybe(); } @@ -785,12 +789,13 @@ public class PipTouchHandler { if (mEnableStash && (animatingBounds.right > mPipBoundsState.getDisplayBounds().right || animatingBounds.left < mPipBoundsState.getDisplayBounds().left)) { + mPipBoundsState.setStashed(true); mMotionHelper.stashToEdge(vel.x, vel.y, this::flingEndAction /* endAction */); } else { mMotionHelper.flingToSnapTarget(vel.x, vel.y, this::flingEndAction /* endAction */); } - } else if (mTouchState.isDoubleTap()) { + } else if (mTouchState.isDoubleTap() && !mPipBoundsState.isStashed()) { // If using pinch to zoom, double-tap functions as resizing between max/min size if (mPipResizeGestureHandler.isUsingPinchToZoom()) { final boolean toExpand = @@ -809,7 +814,7 @@ public class PipTouchHandler { setTouchEnabled(false); mMotionHelper.expandLeavePip(); } - } else if (mMenuState != MENU_STATE_FULL) { + } else if (mMenuState != MENU_STATE_FULL && !mPipBoundsState.isStashed()) { if (!mTouchState.isWaitingForDoubleTap()) { // User has stalled long enough for this not to be a drag or a double tap, just // expand the menu 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 69d428a3ae1f..8b616e8fd1ee 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 @@ -117,7 +117,7 @@ public class SplitScreenController implements SplitScreen, mTransactionPool = transactionPool; mWindowManagerProxy = new WindowManagerProxy(syncQueue, shellTaskOrganizer); mTaskOrganizer = shellTaskOrganizer; - mSplits = new SplitScreenTaskListener(this, shellTaskOrganizer); + mSplits = new SplitScreenTaskListener(this, shellTaskOrganizer, syncQueue); mImePositionProcessor = new DividerImeController(mSplits, mTransactionPool, mHandler, shellTaskOrganizer); mRotationController = diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskListener.java index 191a317452e3..f709fed78b44 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskListener.java @@ -27,8 +27,10 @@ import static com.android.wm.shell.ShellTaskOrganizer.getWindowingMode; import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG; import android.app.ActivityManager.RunningTaskInfo; +import android.graphics.Point; import android.graphics.Rect; import android.util.Log; +import android.util.SparseArray; import android.view.SurfaceControl; import android.view.SurfaceSession; @@ -36,6 +38,8 @@ import androidx.annotation.NonNull; import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.ShellTaskOrganizer; +import com.android.wm.shell.Transitions; +import com.android.wm.shell.common.SyncTransactionQueue; import java.io.PrintWriter; @@ -44,6 +48,8 @@ class SplitScreenTaskListener implements ShellTaskOrganizer.TaskListener { private static final boolean DEBUG = SplitScreenController.DEBUG; private final ShellTaskOrganizer mTaskOrganizer; + private final SyncTransactionQueue mSyncQueue; + private final SparseArray<SurfaceControl> mLeashByTaskId = new SparseArray<>(); RunningTaskInfo mPrimary; RunningTaskInfo mSecondary; @@ -58,9 +64,11 @@ class SplitScreenTaskListener implements ShellTaskOrganizer.TaskListener { final SurfaceSession mSurfaceSession = new SurfaceSession(); SplitScreenTaskListener(SplitScreenController splitScreenController, - ShellTaskOrganizer shellTaskOrganizer) { + ShellTaskOrganizer shellTaskOrganizer, + SyncTransactionQueue syncQueue) { mSplitScreenController = splitScreenController; mTaskOrganizer = shellTaskOrganizer; + mSyncQueue = syncQueue; } void init() { @@ -93,6 +101,11 @@ class SplitScreenTaskListener implements ShellTaskOrganizer.TaskListener { @Override public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) { synchronized (this) { + if (taskInfo.hasParentTask()) { + handleChildTaskAppeared(taskInfo, leash); + return; + } + final int winMode = getWindowingMode(taskInfo); if (winMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { ProtoLog.v(WM_SHELL_TASK_ORG, @@ -139,6 +152,11 @@ class SplitScreenTaskListener implements ShellTaskOrganizer.TaskListener { @Override public void onTaskVanished(RunningTaskInfo taskInfo) { synchronized (this) { + if (taskInfo.hasParentTask()) { + mLeashByTaskId.remove(taskInfo.taskId); + return; + } + final boolean isPrimaryTask = mPrimary != null && taskInfo.token.equals(mPrimary.token); final boolean isSecondaryTask = mSecondary != null @@ -165,7 +183,41 @@ class SplitScreenTaskListener implements ShellTaskOrganizer.TaskListener { if (taskInfo.displayId != DEFAULT_DISPLAY) { return; } - mSplitScreenController.post(() -> handleTaskInfoChanged(taskInfo)); + synchronized (this) { + if (taskInfo.hasParentTask()) { + handleChildTaskChanged(taskInfo); + return; + } + + mSplitScreenController.post(() -> handleTaskInfoChanged(taskInfo)); + } + } + + private void handleChildTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) { + mLeashByTaskId.put(taskInfo.taskId, leash); + updateChildTaskSurface(taskInfo, leash, true /* firstAppeared */); + } + + private void handleChildTaskChanged(RunningTaskInfo taskInfo) { + final SurfaceControl leash = mLeashByTaskId.get(taskInfo.taskId); + updateChildTaskSurface(taskInfo, leash, false /* firstAppeared */); + } + + private void updateChildTaskSurface( + RunningTaskInfo taskInfo, SurfaceControl leash, boolean firstAppeared) { + final Rect taskBounds = taskInfo.getConfiguration().windowConfiguration.getBounds(); + final Point taskPositionInParent = taskInfo.positionInParent; + final Rect corp = new Rect(taskBounds); + corp.offset(-taskBounds.left, -taskBounds.top); + mSyncQueue.runInSync(t -> { + t.setWindowCrop(leash, corp); + t.setPosition(leash, taskPositionInParent.x, taskPositionInParent.y); + if (firstAppeared && !Transitions.ENABLE_SHELL_TRANSITIONS) { + t.setAlpha(leash, 1f); + t.setMatrix(leash, 1, 0, 0, 1); + t.show(leash); + } + }); } /** diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java index 35a2293cbf13..e4155a257cee 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java @@ -248,6 +248,20 @@ public class ShellTaskOrganizerTests { } @Test + public void testGetParentTaskListener() { + RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_MULTI_WINDOW); + TrackingTaskListener mwListener = new TrackingTaskListener(); + mOrganizer.onTaskAppeared(task1, null); + mOrganizer.addListenerForTaskId(mwListener, task1.taskId); + RunningTaskInfo task2 = createTaskInfo(1, WINDOWING_MODE_MULTI_WINDOW); + task2.parentTaskId = task1.taskId; + + mOrganizer.onTaskAppeared(task2, null); + + assertTrue(mwListener.appeared.contains(task2)); + } + + @Test public void testTaskInfoToTaskListenerType_whenLetterboxBoundsPassed_returnsLetterboxType() { RunningTaskInfo taskInfo = createTaskInfo( /* taskId */ 1, diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java index 79b861136b64..610bffe13eae 100644 --- a/media/java/android/media/Image.java +++ b/media/java/android/media/Image.java @@ -17,6 +17,7 @@ package android.media; import android.annotation.Nullable; +import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Rect; import android.hardware.HardwareBuffer; @@ -58,6 +59,7 @@ public abstract class Image implements AutoCloseable { * @hide */ @UnsupportedAppUsage + @TestApi protected Image() { } @@ -387,6 +389,7 @@ public abstract class Image implements AutoCloseable { * @hide */ @UnsupportedAppUsage + @TestApi protected Plane() { } diff --git a/media/java/android/media/tv/tuner/frontend/DtmbFrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/DtmbFrontendCapabilities.java index 9fc3a234876b..dd386b01003a 100644 --- a/media/java/android/media/tv/tuner/frontend/DtmbFrontendCapabilities.java +++ b/media/java/android/media/tv/tuner/frontend/DtmbFrontendCapabilities.java @@ -25,7 +25,7 @@ import android.annotation.SystemApi; * @hide */ @SystemApi -public class DtmbFrontendCapabilities extends FrontendCapabilities { +public final class DtmbFrontendCapabilities extends FrontendCapabilities { private final int mModulationCap; private final int mTransmissionModeCap; private final int mGuardIntervalCap; diff --git a/media/java/android/media/tv/tuner/frontend/DtmbFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DtmbFrontendSettings.java index 2c3fe6a2583c..d85e60d31f7c 100644 --- a/media/java/android/media/tv/tuner/frontend/DtmbFrontendSettings.java +++ b/media/java/android/media/tv/tuner/frontend/DtmbFrontendSettings.java @@ -34,7 +34,7 @@ import java.lang.annotation.RetentionPolicy; * @hide */ @SystemApi -public class DtmbFrontendSettings extends FrontendSettings { +public final class DtmbFrontendSettings extends FrontendSettings { /** @hide */ @IntDef(flag = true, diff --git a/packages/CompanionDeviceManager/res/layout/buttons.xml b/packages/CompanionDeviceManager/res/layout/buttons.xml index 7de0035d0cc9..b190a7f675ca 100644 --- a/packages/CompanionDeviceManager/res/layout/buttons.xml +++ b/packages/CompanionDeviceManager/res/layout/buttons.xml @@ -30,13 +30,13 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@android:string/cancel" - style="@android:style/Widget.Material.Light.Button.Borderless.Colored" + style="@android:style/Widget.Material.Button.Borderless.Colored" /> <Button android:id="@+id/button_pair" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@android:string/ok" - style="@android:style/Widget.Material.Light.Button.Borderless.Colored" + style="@android:style/Widget.Material.Button.Borderless.Colored" /> </LinearLayout>
\ No newline at end of file diff --git a/packages/CompanionDeviceManager/res/layout/device_chooser.xml b/packages/CompanionDeviceManager/res/layout/device_chooser.xml index 88de33f89442..db014aef6e8b 100644 --- a/packages/CompanionDeviceManager/res/layout/device_chooser.xml +++ b/packages/CompanionDeviceManager/res/layout/device_chooser.xml @@ -29,7 +29,7 @@ android:layout_height="match_parent" android:layout_below="@+id/title" android:layout_above="@+id/buttons" - style="@android:style/Widget.Material.Light.ListView" + style="@android:style/Widget.Material.ListView" /> <include layout="@layout/buttons" /> diff --git a/packages/CompanionDeviceManager/res/layout/title.xml b/packages/CompanionDeviceManager/res/layout/title.xml index dfa71e243815..0a44fbb34a9c 100644 --- a/packages/CompanionDeviceManager/res/layout/title.xml +++ b/packages/CompanionDeviceManager/res/layout/title.xml @@ -20,6 +20,5 @@ android:id="@+id/title" android:layout_width="match_parent" android:layout_height="wrap_content" - android:textColor="@android:color/black" style="@*android:style/TextAppearance.Widget.Toolbar.Title" />
\ No newline at end of file diff --git a/packages/CompanionDeviceManager/res/values/themes.xml b/packages/CompanionDeviceManager/res/values/themes.xml index e3fc67c50d75..667293471580 100644 --- a/packages/CompanionDeviceManager/res/values/themes.xml +++ b/packages/CompanionDeviceManager/res/values/themes.xml @@ -21,6 +21,7 @@ <item name="*android:windowFixedHeightMajor">100%</item> <item name="*android:windowFixedHeightMinor">100%</item> <item name="android:windowBackground">@android:color/transparent</item> + <item name="android:forceDarkAllowed">true</item> </style> </resources> diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java index f108e06951ef..c5876af268a9 100644 --- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java +++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java @@ -49,6 +49,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.net.wifi.WifiManager; @@ -58,6 +59,8 @@ import android.os.Parcelable; import android.os.RemoteException; import android.text.TextUtils; import android.util.Log; +import android.util.SparseArray; +import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; @@ -317,6 +320,8 @@ public class DeviceDiscoveryService extends Service { private Drawable BLUETOOTH_ICON = icon(android.R.drawable.stat_sys_data_bluetooth); private Drawable WIFI_ICON = icon(com.android.internal.R.drawable.ic_wifi_signal_3); + private SparseArray<Integer> mColors = new SparseArray(); + private Drawable icon(int drawableRes) { Drawable icon = getResources().getDrawable(drawableRes, null); icon.setTint(Color.DKGRAY); @@ -343,24 +348,36 @@ public class DeviceDiscoveryService extends Service { textView.setText(device.getDisplayName()); textView.setBackgroundColor( device.equals(mSelectedDevice) - ? Color.GRAY + ? getColor(android.R.attr.colorControlHighlight) : Color.TRANSPARENT); textView.setCompoundDrawablesWithIntrinsicBounds( device.device instanceof android.net.wifi.ScanResult ? WIFI_ICON : BLUETOOTH_ICON, null, null, null); + textView.getCompoundDrawables()[0].setTint(getColor(android.R.attr.colorForeground)); } - //TODO move to a layout file private TextView newView() { final TextView textView = new TextView(DeviceDiscoveryService.this); - textView.setTextColor(Color.BLACK); + textView.setTextColor(getColor(android.R.attr.colorForeground)); final int padding = DeviceChooserActivity.getPadding(getResources()); textView.setPadding(padding, padding, padding, padding); textView.setCompoundDrawablePadding(padding); return textView; } + + private int getColor(int colorAttr) { + if (mColors.contains(colorAttr)) { + return mColors.get(colorAttr); + } + TypedValue typedValue = new TypedValue(); + TypedArray a = obtainStyledAttributes(typedValue.data, new int[] { colorAttr }); + int result = a.getColor(0, 0); + a.recycle(); + mColors.put(colorAttr, result); + return result; + } } /** diff --git a/packages/DynamicSystemInstallationService/res/values-af/strings.xml b/packages/DynamicSystemInstallationService/res/values-af/strings.xml index 1829d342e9c5..1b300358adb1 100644 --- a/packages/DynamicSystemInstallationService/res/values-af/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-af/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Herbegin"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Het dinamiese stelsel weggegooi"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Kan nie dinamiese stelsel herbegin of laai nie"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-am/strings.xml b/packages/DynamicSystemInstallationService/res/values-am/strings.xml index 7fcc40de38d2..a8a7b00dd03e 100644 --- a/packages/DynamicSystemInstallationService/res/values-am/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-am/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"ዳግም ጀምር"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"የተጣለ ተለዋዋጭ ሥርዓት"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"ዳግም ማስጀመር አይቻልም ወይም ተለዋዋጭ ሥርዓትን ይስቀሉ"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-ar/strings.xml b/packages/DynamicSystemInstallationService/res/values-ar/strings.xml index be705c37ef1d..44a6503eec08 100644 --- a/packages/DynamicSystemInstallationService/res/values-ar/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-ar/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"إعادة التشغيل"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"تم تجاهل النظام الديناميكي."</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"لا يمكن إعادة التشغيل أو تحميل النظام الديناميكي."</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-as/strings.xml b/packages/DynamicSystemInstallationService/res/values-as/strings.xml index 14eead9f9753..e93ad9bec77c 100644 --- a/packages/DynamicSystemInstallationService/res/values-as/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-as/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"ৰিষ্টাৰ্ট কৰক"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"বাতিল কৰা ডায়নামিক ছিষ্টেম"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"ডায়নামিক ছিষ্টেম ৰিষ্টার্ট অথবা ল\'ড কৰিব নোৱাৰি"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-az/strings.xml b/packages/DynamicSystemInstallationService/res/values-az/strings.xml index d1f0a4b78ebb..ad3d3e7b1d28 100644 --- a/packages/DynamicSystemInstallationService/res/values-az/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-az/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Yenidən başladın"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dinamik sistemdən imtina edildi"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Dinamik sistemi yenidən başlatmaq və ya yükləmək mümkün deyil"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-b+sr+Latn/strings.xml b/packages/DynamicSystemInstallationService/res/values-b+sr+Latn/strings.xml index ea23a28bc9e5..01070479cd53 100644 --- a/packages/DynamicSystemInstallationService/res/values-b+sr+Latn/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-b+sr+Latn/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Restartuj"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dinamični sistem je odbačen"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Restartovanje ili učitavanje dinamičnog sistema nije uspelo"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-be/strings.xml b/packages/DynamicSystemInstallationService/res/values-be/strings.xml index 7eef297be292..5a52f735aee1 100644 --- a/packages/DynamicSystemInstallationService/res/values-be/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-be/strings.xml @@ -5,7 +5,7 @@ <string name="notification_install_completed" msgid="6252047868415172643">"Дынамічная сістэма гатовая. Каб пачаць выкарыстоўваць яе, перазапусціце прыладу."</string> <string name="notification_install_inprogress" msgid="7383334330065065017">"Ідзе ўсталёўка"</string> <string name="notification_install_failed" msgid="4066039210317521404">"Збой усталёўкі"</string> - <string name="notification_image_validation_failed" msgid="2720357826403917016">"Збой пры праверцы відарыса. Усталёўка спынена."</string> + <string name="notification_image_validation_failed" msgid="2720357826403917016">"Збой пры праверцы вобраза дыска. Усталёўка спынена."</string> <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Цяпер запушчана дынамічная сістэма. Перазапусціце, каб скарыстаць арыгінальную версію Android."</string> <string name="notification_action_cancel" msgid="5929299408545961077">"Скасаваць"</string> <string name="notification_action_discard" msgid="1817481003134947493">"Адхіліць"</string> @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Перазапусціць"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Дынамічная сістэма адхілена"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Не ўдалося перазапусціць або загрузіць дынамічную сістэму"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-bg/strings.xml b/packages/DynamicSystemInstallationService/res/values-bg/strings.xml index 9176676c0618..194bf2dd5a58 100644 --- a/packages/DynamicSystemInstallationService/res/values-bg/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-bg/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Рестартиране"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Динамичната система е отхвърлена"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Динамичната система не може да се рестартира или зареди"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-bn/strings.xml b/packages/DynamicSystemInstallationService/res/values-bn/strings.xml index 38ef64935fb4..43886b348888 100644 --- a/packages/DynamicSystemInstallationService/res/values-bn/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-bn/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"রিস্টার্ট করুন"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"ডায়নামিক সিস্টেম বাতিল করা হয়েছে"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"ডায়নামিক সিস্টেম রিস্টার্ট বা লোড করা যাচ্ছে না"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-bs/strings.xml b/packages/DynamicSystemInstallationService/res/values-bs/strings.xml index 84ba540bb822..342230b25f9d 100644 --- a/packages/DynamicSystemInstallationService/res/values-bs/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-bs/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Ponovo pokreni"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dinamični sistem je odbačen"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Nije moguće ponovo pokrenuti ili učitati dinamični sistem"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-ca/strings.xml b/packages/DynamicSystemInstallationService/res/values-ca/strings.xml index 787e4960513b..e9e4d3573f58 100644 --- a/packages/DynamicSystemInstallationService/res/values-ca/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-ca/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Reinicia"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"S\'ha descartat el sistema dinàmic"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"No es pot reiniciar ni carregar el sistema dinàmic"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-cs/strings.xml b/packages/DynamicSystemInstallationService/res/values-cs/strings.xml index 3dfb23f7d2ff..6ae71c6c438b 100644 --- a/packages/DynamicSystemInstallationService/res/values-cs/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-cs/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Restartovat"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Zahodit dynamický systém"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Dynamický systém nelze znovu spustit nebo načíst"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-da/strings.xml b/packages/DynamicSystemInstallationService/res/values-da/strings.xml index 20005e739205..10b798c2ce29 100644 --- a/packages/DynamicSystemInstallationService/res/values-da/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-da/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Genstart"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Det dynamiske system blev slettet"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Det dynamiske system kan ikke genstartes eller indlæses"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-de/strings.xml b/packages/DynamicSystemInstallationService/res/values-de/strings.xml index 3f000eaea251..82459b2f368d 100644 --- a/packages/DynamicSystemInstallationService/res/values-de/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-de/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Neu starten"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dynamisches System verworfen"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Neustart und Laden des dynamischen Systems nicht möglich"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-el/strings.xml b/packages/DynamicSystemInstallationService/res/values-el/strings.xml index 4d830dde12e5..ef029063f544 100644 --- a/packages/DynamicSystemInstallationService/res/values-el/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-el/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Επανεκκίνηση"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Οι δυναμικές συστήματος απορρίφθηκαν."</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Δεν είναι δυνατή η επανεκκίνηση ή η φόρτωση δυναμικών συστήματος"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-en-rAU/strings.xml b/packages/DynamicSystemInstallationService/res/values-en-rAU/strings.xml index d72863128257..6f3f88763597 100644 --- a/packages/DynamicSystemInstallationService/res/values-en-rAU/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-en-rAU/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Restart"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Discarded dynamic system"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Can’t restart or load dynamic system"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-en-rCA/strings.xml b/packages/DynamicSystemInstallationService/res/values-en-rCA/strings.xml index d72863128257..6f3f88763597 100644 --- a/packages/DynamicSystemInstallationService/res/values-en-rCA/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-en-rCA/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Restart"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Discarded dynamic system"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Can’t restart or load dynamic system"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-en-rGB/strings.xml b/packages/DynamicSystemInstallationService/res/values-en-rGB/strings.xml index d72863128257..6f3f88763597 100644 --- a/packages/DynamicSystemInstallationService/res/values-en-rGB/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-en-rGB/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Restart"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Discarded dynamic system"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Can’t restart or load dynamic system"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-en-rIN/strings.xml b/packages/DynamicSystemInstallationService/res/values-en-rIN/strings.xml index d72863128257..6f3f88763597 100644 --- a/packages/DynamicSystemInstallationService/res/values-en-rIN/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-en-rIN/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Restart"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Discarded dynamic system"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Can’t restart or load dynamic system"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-en-rXC/strings.xml b/packages/DynamicSystemInstallationService/res/values-en-rXC/strings.xml index 6ac376322ceb..2e83672f1927 100644 --- a/packages/DynamicSystemInstallationService/res/values-en-rXC/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-en-rXC/strings.xml @@ -13,4 +13,5 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Restart"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Discarded dynamic system"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Can’t restart or load dynamic system"</string> + <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Failed to disable dynamic system"</string> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-es-rUS/strings.xml b/packages/DynamicSystemInstallationService/res/values-es-rUS/strings.xml index 9ec819656495..aeb65be46f27 100644 --- a/packages/DynamicSystemInstallationService/res/values-es-rUS/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-es-rUS/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Reiniciar"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Se descartó el sistema dinámico"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"No se puede reiniciar o cargar el sistema dinámico"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-es/strings.xml b/packages/DynamicSystemInstallationService/res/values-es/strings.xml index cd9db07168a2..0c3ae5381453 100644 --- a/packages/DynamicSystemInstallationService/res/values-es/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-es/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Reiniciar"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Se ha descartado el sistema dinámico"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"No se ha podido reiniciar o cargar el sistema dinámico"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-et/strings.xml b/packages/DynamicSystemInstallationService/res/values-et/strings.xml index 64968b60ac6f..ab20a04493ef 100644 --- a/packages/DynamicSystemInstallationService/res/values-et/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-et/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Taaskäivita"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dünaamilisest süsteemist loobuti"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Dünaamilist süsteemi ei saa taaskäivitada ega laadida"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-eu/strings.xml b/packages/DynamicSystemInstallationService/res/values-eu/strings.xml index 7c4a67d4e6c2..18637786ebea 100644 --- a/packages/DynamicSystemInstallationService/res/values-eu/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-eu/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Berrabiarazi"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Baztertu da sistema dinamikoa"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Ezin da berrabiarazi edo kargatu sistema dinamikoa"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-fa/strings.xml b/packages/DynamicSystemInstallationService/res/values-fa/strings.xml index 7533e71cb26c..5b0b21891a09 100644 --- a/packages/DynamicSystemInstallationService/res/values-fa/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-fa/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"بازراهاندازی"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"از سیستم پویا صرفنظر شد"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"نمیتوان سیستم پویا را بازراهاندازی یا بار کرد"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-fi/strings.xml b/packages/DynamicSystemInstallationService/res/values-fi/strings.xml index 948c3336cea8..b4315e7a22ef 100644 --- a/packages/DynamicSystemInstallationService/res/values-fi/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-fi/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Käynn. uudelleen"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dynaaminen järjestelmä hylätty"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Dynaamista järjestelmää ei voi käynnistää uudelleen tai ladata"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-fr-rCA/strings.xml b/packages/DynamicSystemInstallationService/res/values-fr-rCA/strings.xml index 6e2f235bcb76..973efef68a47 100644 --- a/packages/DynamicSystemInstallationService/res/values-fr-rCA/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-fr-rCA/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Redémarrer"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Système dynamique supprimé"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Impossible de redémarrer ou de charger le système dynamique"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-fr/strings.xml b/packages/DynamicSystemInstallationService/res/values-fr/strings.xml index 67f799731c6d..5422e8e4ec5b 100644 --- a/packages/DynamicSystemInstallationService/res/values-fr/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-fr/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Redémarrer"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Système dynamique supprimé"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Impossible de redémarrer ou de charger le système dynamique"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-gl/strings.xml b/packages/DynamicSystemInstallationService/res/values-gl/strings.xml index 8ea6d1c6c3b6..e24f495a425f 100644 --- a/packages/DynamicSystemInstallationService/res/values-gl/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-gl/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Reiniciar"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Descartouse o sistema dinámico"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Non se puido reiniciar nin cargar o sistema dinámico"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-gu/strings.xml b/packages/DynamicSystemInstallationService/res/values-gu/strings.xml index aec18049fdb0..6c2e67336c21 100644 --- a/packages/DynamicSystemInstallationService/res/values-gu/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-gu/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"ફરી શરૂ કરો"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"ડાઇનૅમિક સિસ્ટમ કાઢી નાખવામાં આવી"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"ડાઇનૅમિક સિસ્ટમને ફરી શરૂ અથવા લોડ કરી શકાતી નથી"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-hi/strings.xml b/packages/DynamicSystemInstallationService/res/values-hi/strings.xml index efedbe8e7ee6..13dc9e8a3984 100644 --- a/packages/DynamicSystemInstallationService/res/values-hi/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-hi/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"रीस्टार्ट करें"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"डाइनैमिक सिस्टम खारिज किया गया"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"डाइनैमिक सिस्टम रीस्टार्ट या लोड नहीं हो सका"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-hr/strings.xml b/packages/DynamicSystemInstallationService/res/values-hr/strings.xml index 50ceaa16f764..3318d2040196 100644 --- a/packages/DynamicSystemInstallationService/res/values-hr/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-hr/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Pokreni"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Odbačeni dinamični sustav"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Nije moguće ponovno pokretanje ili učitavanje dinamičnog sustava"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-hu/strings.xml b/packages/DynamicSystemInstallationService/res/values-hu/strings.xml index 94afa3b927b3..208ab3bdd260 100644 --- a/packages/DynamicSystemInstallationService/res/values-hu/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-hu/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Újraindítás"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Elvetett dinamikus rendszer"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Nem lehet újraindítani vagy betölteni a dinamikus rendszert"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-hy/strings.xml b/packages/DynamicSystemInstallationService/res/values-hy/strings.xml index b0cd740d3e8d..4dcc72e38121 100644 --- a/packages/DynamicSystemInstallationService/res/values-hy/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-hy/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Վերագործարկել"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Դինամիկ համակարգի գործարկումը չեղարկվեց"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Չհաջողվեց վերագործարկել կամ բեռնել դինամիկ համակարգը"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-in/strings.xml b/packages/DynamicSystemInstallationService/res/values-in/strings.xml index 44b4aeec8b78..2fa4f113341a 100644 --- a/packages/DynamicSystemInstallationService/res/values-in/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-in/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Mulai ulang"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dynamic System dihapus"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Tidak dapat memulai ulang atau memuat Dynamic System"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-is/strings.xml b/packages/DynamicSystemInstallationService/res/values-is/strings.xml index 048d1bca5518..ef7484c1d6cc 100644 --- a/packages/DynamicSystemInstallationService/res/values-is/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-is/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Endurræsa"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Breytilegu kerfi fleygt"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Ekki tókst að endurræsa eða hlaða breytilegu kerfi"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-it/strings.xml b/packages/DynamicSystemInstallationService/res/values-it/strings.xml index f70b38178021..c8fa41b3c92c 100644 --- a/packages/DynamicSystemInstallationService/res/values-it/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-it/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Riavvia"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Sistema dinamico annullato"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Impossibile riavviare o caricare il sistema dinamico"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-iw/strings.xml b/packages/DynamicSystemInstallationService/res/values-iw/strings.xml index aff7c824ba1d..d9bf983d4d76 100644 --- a/packages/DynamicSystemInstallationService/res/values-iw/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-iw/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"הפעלה מחדש"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"המערכת הדינמית נסגרה"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"לא ניתן להפעיל מחדש או לטעון את המערכת הדינמית"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-ja/strings.xml b/packages/DynamicSystemInstallationService/res/values-ja/strings.xml index 46c093057a49..2082d91294da 100644 --- a/packages/DynamicSystemInstallationService/res/values-ja/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-ja/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"再起動"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"動的システムを破棄しました"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"動的システムの再起動や読み込みを行えません"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-ka/strings.xml b/packages/DynamicSystemInstallationService/res/values-ka/strings.xml index f841a59801e4..e57de2c1016a 100644 --- a/packages/DynamicSystemInstallationService/res/values-ka/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-ka/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"გადატვირთვა"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"გაუქმებული დინამიური სისტემა"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"დინამიური სისტემის გადატვირთვა ან ჩატვირთვა ვერ ხერხდება"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-kk/strings.xml b/packages/DynamicSystemInstallationService/res/values-kk/strings.xml index d367b614e528..da10e9c582c0 100644 --- a/packages/DynamicSystemInstallationService/res/values-kk/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-kk/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Қайта қосу"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Динамикалық жүйе өшірілді."</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Динамикалық жүйені қайта қосу не жүктеу мүмкін емес."</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-km/strings.xml b/packages/DynamicSystemInstallationService/res/values-km/strings.xml index 56a37164fa6e..7bb5980ca1d4 100644 --- a/packages/DynamicSystemInstallationService/res/values-km/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-km/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"ចាប់ផ្ដើមឡើងវិញ"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"បានលុបចោលប្រព័ន្ធឌីណាមិច"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"មិនអាចចាប់ផ្ដើមឡើងវិញ ឬផ្ទុកប្រព័ន្ធឌីណាមិចបានទេ"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-kn/strings.xml b/packages/DynamicSystemInstallationService/res/values-kn/strings.xml index b4063df9c10d..f41f2eff5cde 100644 --- a/packages/DynamicSystemInstallationService/res/values-kn/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-kn/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"ಮರುಪ್ರಾರಂಭಿಸಿ"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"ಡೈನಮಿಕ್ ಸಿಸ್ಟಂ ಅನ್ನು ತ್ಯಜಿಸಲಾಗಿದೆ"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"ಡೈನಾಮಿಕ್ ಸಿಸ್ಟಂ ಅನ್ನು ಮರುಪ್ರಾರಂಭಿಸಲು ಅಥವಾ ಲೋಡ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-ko/strings.xml b/packages/DynamicSystemInstallationService/res/values-ko/strings.xml index 24ac9245e22c..bca9e0725a6e 100644 --- a/packages/DynamicSystemInstallationService/res/values-ko/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-ko/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"다시 시작"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"동적 시스템 삭제됨"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"동적 시스템을 다시 시작하거나 로드할 수 없음"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-ky/strings.xml b/packages/DynamicSystemInstallationService/res/values-ky/strings.xml index a4387e7bf4a1..d2ad56a44897 100644 --- a/packages/DynamicSystemInstallationService/res/values-ky/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-ky/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Өчүрүп күйгүзүү"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Динамикалык система жоюлду"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Динамикалык система өчүрүлүп күйгүзүлбөй же жүктөлбөй жатат"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-lo/strings.xml b/packages/DynamicSystemInstallationService/res/values-lo/strings.xml index f17ca16bf777..a732aa414780 100644 --- a/packages/DynamicSystemInstallationService/res/values-lo/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-lo/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"ຣີສະຕາດ"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"ລະບົບໄດນາມິກທີ່ຍົກເລີກແລ້ວ"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"ບໍ່ສາມາດຣີສະຕາດ ຫຼື ໂຫຼດລະບົບໄດນາມິກໄດ້"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-lt/strings.xml b/packages/DynamicSystemInstallationService/res/values-lt/strings.xml index 8128eb7b0a72..b25c62a5f4ff 100644 --- a/packages/DynamicSystemInstallationService/res/values-lt/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-lt/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Pal. iš naujo"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dinaminė sistema atmesta"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Nepavyko paleisti iš naujo ar įkelti dinaminės sistemos"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-lv/strings.xml b/packages/DynamicSystemInstallationService/res/values-lv/strings.xml index cfe7a087e148..4ca6ace3f5b3 100644 --- a/packages/DynamicSystemInstallationService/res/values-lv/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-lv/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Restartēt"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dinamiskā sistēma tika atmesta"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Nevar restartēt vai ielādēt dinamisko sistēmu"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-mk/strings.xml b/packages/DynamicSystemInstallationService/res/values-mk/strings.xml index 21215aa77631..52a52a5ca10d 100644 --- a/packages/DynamicSystemInstallationService/res/values-mk/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-mk/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Рестартирај"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Отфрлен динамичен систем"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Не може да го рестартира или вчита динамичниот систем"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-ml/strings.xml b/packages/DynamicSystemInstallationService/res/values-ml/strings.xml index 951a0b95f7e4..25040694bbda 100644 --- a/packages/DynamicSystemInstallationService/res/values-ml/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-ml/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"റീസ്റ്റാർട്ട് ചെയ്യൂ"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"ഡെെനാമിക് സിസ്റ്റം നിരസിച്ചു"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"റീസ്റ്റാർട്ട് ചെയ്യാനോ ഡെെനാമിക് സിസ്റ്റം ലോഡ് ചെയ്യാനോ ആവില്ല"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-mn/strings.xml b/packages/DynamicSystemInstallationService/res/values-mn/strings.xml index d0965d021c65..fe93f65939b3 100644 --- a/packages/DynamicSystemInstallationService/res/values-mn/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-mn/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Дахин эхлүүлэх"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Динамик системийг устгасан"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Динамик системийг дахин эхлүүлэх эсвэл ачаалах боломжгүй байна"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-mr/strings.xml b/packages/DynamicSystemInstallationService/res/values-mr/strings.xml index 268e1d344620..5f27af01f635 100644 --- a/packages/DynamicSystemInstallationService/res/values-mr/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-mr/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"रीस्टार्ट करा"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"डायनॅमिक सिस्टम काढून टाकली"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"डायनॅमिक सिस्टम रीस्टार्ट किंवा लोड करू शकत नाही"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-ms/strings.xml b/packages/DynamicSystemInstallationService/res/values-ms/strings.xml index bba8b9724f0d..797152c937ed 100644 --- a/packages/DynamicSystemInstallationService/res/values-ms/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-ms/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Mulakan semula"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Sistem dinamik dibuang"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Tidak dapat memulakan semula atau memuatkan sistem dinamik"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-my/strings.xml b/packages/DynamicSystemInstallationService/res/values-my/strings.xml index b2488ece9ce3..3ee85b2136ee 100644 --- a/packages/DynamicSystemInstallationService/res/values-my/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-my/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"ပြန်စရန်"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"ပြောင်းလဲနိုင်သောစနစ်ကို ဖယ်လိုက်သည်"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"ပြန်စ၍ မရပါ (သို့) ပြောင်းလဲနိုင်သောစနစ် ဖွင့်၍မရပါ"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-nb/strings.xml b/packages/DynamicSystemInstallationService/res/values-nb/strings.xml index 36e3d6912e23..88087e542b0c 100644 --- a/packages/DynamicSystemInstallationService/res/values-nb/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-nb/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Start på nytt"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Det dynamiske systemet er forkastet"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Det dynamiske systemet kan ikke startes på nytt eller lastes inn"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-ne/strings.xml b/packages/DynamicSystemInstallationService/res/values-ne/strings.xml index ee9267852250..da98fee056e5 100644 --- a/packages/DynamicSystemInstallationService/res/values-ne/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-ne/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"रिस्टार्ट गर्नु…"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dynamic System खारेज गरियो"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"रिस्टार्ट गर्न वा Dynamic System लोड गर्न सकिएन"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-nl/strings.xml b/packages/DynamicSystemInstallationService/res/values-nl/strings.xml index 2b9fa414dcc5..5120c90eadc6 100644 --- a/packages/DynamicSystemInstallationService/res/values-nl/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-nl/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Herstarten"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dynamisch systeem niet opgeslagen"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Kan dynamisch systeem niet opnieuw opstarten of laden"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-or/strings.xml b/packages/DynamicSystemInstallationService/res/values-or/strings.xml index e0c847094844..878947e48579 100644 --- a/packages/DynamicSystemInstallationService/res/values-or/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-or/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"ରିଷ୍ଟାର୍ଟ କରନ୍ତୁ"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"ଡାଇନାମିକ୍ ସିଷ୍ଟମ୍ ଖାରଜ କରାଯାଇଛି"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"ଡାଇନାମିକ୍ ସିଷ୍ଟମ୍ ରିଷ୍ଟାର୍ଟ କିମ୍ବା ଲୋଡ୍ କରାଯାଇପାରିବ ନାହିଁ"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-pa/strings.xml b/packages/DynamicSystemInstallationService/res/values-pa/strings.xml index c5f7a3d38cdc..2695aaf39b25 100644 --- a/packages/DynamicSystemInstallationService/res/values-pa/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-pa/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"ਮੁੜ-ਸ਼ੁਰੂ ਕਰੋ"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"ਪਰਿਵਰਤਨਸ਼ੀਲ ਸਿਸਟਮ ਰੱਦ ਕੀਤਾ ਗਿਆ"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"ਪਰਿਵਰਤਨਸ਼ੀਲ ਸਿਸਟਮ ਮੁੜ-ਸ਼ੁਰੂ ਜਾਂ ਲੋਡ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-pl/strings.xml b/packages/DynamicSystemInstallationService/res/values-pl/strings.xml index bc7d5fe5b222..33592c86a090 100644 --- a/packages/DynamicSystemInstallationService/res/values-pl/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-pl/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Uruchom ponownie"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Usunięto system dynamiczny"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Nie można ponownie uruchomić lub wczytać systemu dynamicznego"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-pt-rBR/strings.xml b/packages/DynamicSystemInstallationService/res/values-pt-rBR/strings.xml index 31a9bb439235..43bd02135672 100644 --- a/packages/DynamicSystemInstallationService/res/values-pt-rBR/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-pt-rBR/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Reiniciar"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Sistema dinâmico descartado"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Não é possível reiniciar ou carregar o sistema dinâmico"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-pt-rPT/strings.xml b/packages/DynamicSystemInstallationService/res/values-pt-rPT/strings.xml index d917c6afec6e..dc29a659d24c 100644 --- a/packages/DynamicSystemInstallationService/res/values-pt-rPT/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-pt-rPT/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Reiniciar"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Sistema dinâmico rejeitado"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Não é possível reiniciar ou carregar o sistema dinâmico."</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-pt/strings.xml b/packages/DynamicSystemInstallationService/res/values-pt/strings.xml index 31a9bb439235..43bd02135672 100644 --- a/packages/DynamicSystemInstallationService/res/values-pt/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-pt/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Reiniciar"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Sistema dinâmico descartado"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Não é possível reiniciar ou carregar o sistema dinâmico"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-ro/strings.xml b/packages/DynamicSystemInstallationService/res/values-ro/strings.xml index c21131857830..c9d391a7fb88 100644 --- a/packages/DynamicSystemInstallationService/res/values-ro/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-ro/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Reporniți"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"S-a renunțat la sistemul dinamic"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Nu se poate reporni sau încărca sistemul dinamic"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-ru/strings.xml b/packages/DynamicSystemInstallationService/res/values-ru/strings.xml index bf94c99b8fb5..cba9a713f8fa 100644 --- a/packages/DynamicSystemInstallationService/res/values-ru/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-ru/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Перезапустить"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Динамическая система удалена."</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Не удается запустить или загрузить динамическую систему."</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-si/strings.xml b/packages/DynamicSystemInstallationService/res/values-si/strings.xml index e6a6ea2fe351..7aab6e9b0ada 100644 --- a/packages/DynamicSystemInstallationService/res/values-si/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-si/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"යළි අරඹන්න"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"ගතික පද්ධතිය ඉවත දමන ලදි"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"ගතික පද්ධතිය නැවත ආරම්භ කිරීමට හෝ පූරණය කිරීමට නොහැක"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-sk/strings.xml b/packages/DynamicSystemInstallationService/res/values-sk/strings.xml index 99390cf07c74..61c176fb8905 100644 --- a/packages/DynamicSystemInstallationService/res/values-sk/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-sk/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Reštartovať"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Zahodený dynamický systém"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Nie je možné reštartovať alebo načítať dynamický systém"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-sl/strings.xml b/packages/DynamicSystemInstallationService/res/values-sl/strings.xml index 3ffd741ea4f6..0be1248bcff1 100644 --- a/packages/DynamicSystemInstallationService/res/values-sl/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-sl/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Znova zaženi"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dinamični sistem je bil zavržen"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Dinamičnega sistema ni mogoče znova zagnati ali naložiti"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-sq/strings.xml b/packages/DynamicSystemInstallationService/res/values-sq/strings.xml index 704b512ad9ab..43a5f7bbc876 100644 --- a/packages/DynamicSystemInstallationService/res/values-sq/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-sq/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Rinis"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Sistemi dinamik u hoq"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Sistemi dinamik nuk mund të rinisej ose të ngarkohej"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-sr/strings.xml b/packages/DynamicSystemInstallationService/res/values-sr/strings.xml index 5e4540a5eff0..a5ba6565d1ea 100644 --- a/packages/DynamicSystemInstallationService/res/values-sr/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-sr/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Рестартуј"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Динамични систем је одбачен"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Рестартовање или учитавање динамичног система није успело"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-sv/strings.xml b/packages/DynamicSystemInstallationService/res/values-sv/strings.xml index 546ffddde639..99e6752c0bed 100644 --- a/packages/DynamicSystemInstallationService/res/values-sv/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-sv/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Starta om"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Det dynamiska systemet ignorerades"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Det gick inte att starta om eller läsa in det dynamiska systemet"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-sw/strings.xml b/packages/DynamicSystemInstallationService/res/values-sw/strings.xml index 53414d5f6b0a..8af9ad35a763 100644 --- a/packages/DynamicSystemInstallationService/res/values-sw/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-sw/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Zima kisha uwashe"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Umeondoa Dynamic System"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Imeshindwa kuzima na kuwasha au kupakia Dynamic System"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-ta/strings.xml b/packages/DynamicSystemInstallationService/res/values-ta/strings.xml index e0aaaf7458fc..bbe8c4e5e03e 100644 --- a/packages/DynamicSystemInstallationService/res/values-ta/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-ta/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"மீண்டும் தொடங்கு"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dynamic system நிராகரிக்கப்பட்டது"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Dynamic systemமை மீண்டும் தொடங்கவோ ஏற்றவோ முடியவில்லை"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-te/strings.xml b/packages/DynamicSystemInstallationService/res/values-te/strings.xml index d497630660e3..4a9433e7116e 100644 --- a/packages/DynamicSystemInstallationService/res/values-te/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-te/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"రీస్టార్ట్ చేయి"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"డైనమిక్ సిస్టమ్ విస్మరించబడింది"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"డైనమిక్ సిస్టమ్ను రీస్టార్ట్ చేయడం లేదా లోడ్ చేయడం సాధ్యపడలేదు"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-th/strings.xml b/packages/DynamicSystemInstallationService/res/values-th/strings.xml index 786324f57488..5b81a03c51e3 100644 --- a/packages/DynamicSystemInstallationService/res/values-th/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-th/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"รีสตาร์ท"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"ยกเลิกระบบแบบไดนามิกแล้ว"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"รีสตาร์ทหรือโหลดระบบแบบไดนามิกไม่ได้"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-tl/strings.xml b/packages/DynamicSystemInstallationService/res/values-tl/strings.xml index df39f7b1886a..d6c2f1508f75 100644 --- a/packages/DynamicSystemInstallationService/res/values-tl/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-tl/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"I-restart"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Na-discard ang dynamic system"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Hindi ma-restart o ma-load ang dynamic system"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-tr/strings.xml b/packages/DynamicSystemInstallationService/res/values-tr/strings.xml index 1446f9632456..a98526e0cdbe 100644 --- a/packages/DynamicSystemInstallationService/res/values-tr/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-tr/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Yeniden başlat"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dinamik sistem silindi"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Dinamik sistem yeniden başlatılamıyor veya yüklenemiyor"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-uk/strings.xml b/packages/DynamicSystemInstallationService/res/values-uk/strings.xml index 9a44d9764014..65267872b724 100644 --- a/packages/DynamicSystemInstallationService/res/values-uk/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-uk/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Перезапустити"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Динамічну систему видалено"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Не вдається перезапустити пристрій або завантажити динамічну систему"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-ur/strings.xml b/packages/DynamicSystemInstallationService/res/values-ur/strings.xml index 48dddbea3281..f5e2b744e5b2 100644 --- a/packages/DynamicSystemInstallationService/res/values-ur/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-ur/strings.xml @@ -5,7 +5,7 @@ <string name="notification_install_completed" msgid="6252047868415172643">"ڈائنیمک سسٹم تیار ہے۔ اس کا استعمال شروع کرنے کے لیے، اپنا آلہ ری سٹارٹ کریں۔"</string> <string name="notification_install_inprogress" msgid="7383334330065065017">"انسٹال جاری ہے"</string> <string name="notification_install_failed" msgid="4066039210317521404">"انسٹال ناکام ہو گیا"</string> - <string name="notification_image_validation_failed" msgid="2720357826403917016">"تصویر کی توثیق ناکام ہو گئی۔ انسٹالیشن منسوخ کریں-"</string> + <string name="notification_image_validation_failed" msgid="2720357826403917016">"ڈسک امیج کی توثیق ناکام ہو گئی۔ انسٹالیشن منسوخ کریں۔"</string> <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"فی الحال ہم ایک ڈائنیمک سسٹم چلا رہے ہیں۔ Android کا اصل ورژن استعمال کرنے کے لیے ری سٹارٹ کریں۔"</string> <string name="notification_action_cancel" msgid="5929299408545961077">"منسوخ کریں"</string> <string name="notification_action_discard" msgid="1817481003134947493">"مسترد کریں"</string> @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"ری سٹارٹ کریں"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"مسترد کردہ ڈائنیمک سسٹم"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"ڈائنیمک سسٹم کو ری سٹارٹ یا لوڈ نہیں کر سکتے"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-uz/strings.xml b/packages/DynamicSystemInstallationService/res/values-uz/strings.xml index 3f0227c1c383..3c347e2e87ba 100644 --- a/packages/DynamicSystemInstallationService/res/values-uz/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-uz/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Boshidan"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dinamik tizim bekor qilindi"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Dinamik tizim qayta ishga tushmadi yoki yuklanmadi"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-vi/strings.xml b/packages/DynamicSystemInstallationService/res/values-vi/strings.xml index 18c051c893f8..a93d29e383ca 100644 --- a/packages/DynamicSystemInstallationService/res/values-vi/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-vi/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Khởi động lại"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Đã hủy hệ thống động"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Không thể khởi động lại hoặc tải hệ thống động"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-zh-rCN/strings.xml b/packages/DynamicSystemInstallationService/res/values-zh-rCN/strings.xml index b41d4e2bf912..c27718ea8c76 100644 --- a/packages/DynamicSystemInstallationService/res/values-zh-rCN/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-zh-rCN/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"重启"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"已舍弃动态系统"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"无法重启或加载动态系统"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-zh-rHK/strings.xml b/packages/DynamicSystemInstallationService/res/values-zh-rHK/strings.xml index c830dae24e97..656c2af188c4 100644 --- a/packages/DynamicSystemInstallationService/res/values-zh-rHK/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-zh-rHK/strings.xml @@ -5,7 +5,7 @@ <string name="notification_install_completed" msgid="6252047868415172643">"動態系統已可供使用。如要開始使用,請重新啟動裝置。"</string> <string name="notification_install_inprogress" msgid="7383334330065065017">"安裝中"</string> <string name="notification_install_failed" msgid="4066039210317521404">"無法安裝"</string> - <string name="notification_image_validation_failed" msgid="2720357826403917016">"圖片驗證失敗,系統將取消安裝。"</string> + <string name="notification_image_validation_failed" msgid="2720357826403917016">"磁碟影像驗證失敗,系統將取消安裝。"</string> <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"系統目前正在執行動態系統。如要使用原本的 Android 版本,請重新啟動裝置。"</string> <string name="notification_action_cancel" msgid="5929299408545961077">"取消"</string> <string name="notification_action_discard" msgid="1817481003134947493">"捨棄"</string> @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"重新啟動"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"已捨棄動態系統"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"無法重新啟動或載入動態系統"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-zh-rTW/strings.xml b/packages/DynamicSystemInstallationService/res/values-zh-rTW/strings.xml index e43c0f2b08bb..a6f9b56e438c 100644 --- a/packages/DynamicSystemInstallationService/res/values-zh-rTW/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-zh-rTW/strings.xml @@ -5,7 +5,7 @@ <string name="notification_install_completed" msgid="6252047868415172643">"動態系統已可供使用。如要開始使用,請重新啟動裝置。"</string> <string name="notification_install_inprogress" msgid="7383334330065065017">"安裝中"</string> <string name="notification_install_failed" msgid="4066039210317521404">"無法安裝"</string> - <string name="notification_image_validation_failed" msgid="2720357826403917016">"圖片驗證失敗,系統將取消安裝作業。"</string> + <string name="notification_image_validation_failed" msgid="2720357826403917016">"映像檔驗證失敗,系統將取消安裝作業。"</string> <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"系統目前正在執行動態系統。如要使用原本的 Android 版本,請重新啟動裝置。"</string> <string name="notification_action_cancel" msgid="5929299408545961077">"取消"</string> <string name="notification_action_discard" msgid="1817481003134947493">"捨棄"</string> @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"重新啟動"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"已捨棄動態系統"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"無法重新啟動或載入動態系統"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/DynamicSystemInstallationService/res/values-zu/strings.xml b/packages/DynamicSystemInstallationService/res/values-zu/strings.xml index 4a48444cb9a0..0cf79ba51b45 100644 --- a/packages/DynamicSystemInstallationService/res/values-zu/strings.xml +++ b/packages/DynamicSystemInstallationService/res/values-zu/strings.xml @@ -13,4 +13,6 @@ <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Qala kabusha"</string> <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Kulahlwe uhlole olunhlobonhlobo"</string> <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Ayikwazi ukuqalisa kabusha noma ukulayisha uhlole olunhlobonhlobo"</string> + <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) --> + <skip /> </resources> diff --git a/packages/SettingsLib/HelpUtils/res/values-es/strings.xml b/packages/SettingsLib/HelpUtils/res/values-es/strings.xml index 97ff5efc6401..97e3559914a2 100644 --- a/packages/SettingsLib/HelpUtils/res/values-es/strings.xml +++ b/packages/SettingsLib/HelpUtils/res/values-es/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="help_feedback_label" msgid="7106780063063027882">"Ayuda y sugerencias"</string> + <string name="help_feedback_label" msgid="7106780063063027882">"Ayuda y comentarios"</string> </resources> diff --git a/packages/SettingsProvider/src/android/provider/settings/OWNERS b/packages/SettingsProvider/src/android/provider/settings/OWNERS index 541dd8787545..7e7710b4d550 100644 --- a/packages/SettingsProvider/src/android/provider/settings/OWNERS +++ b/packages/SettingsProvider/src/android/provider/settings/OWNERS @@ -1,5 +1,4 @@ -# Please reach out to Android B&R when making Settings backup changes -alsutton@google.com -nathch@google.com -rthakohov@google.com +# Bug component: 656484 + +include platform/frameworks/base/services/backup:/OWNERS diff --git a/packages/SettingsProvider/test/src/android/provider/OWNERS b/packages/SettingsProvider/test/src/android/provider/OWNERS index f3241ea9d1f9..7e7710b4d550 100644 --- a/packages/SettingsProvider/test/src/android/provider/OWNERS +++ b/packages/SettingsProvider/test/src/android/provider/OWNERS @@ -1,4 +1,4 @@ -per-file * = * +# Bug component: 656484 + +include platform/frameworks/base/services/backup:/OWNERS -# Please reach out to the Android B&R team for settings backup changes -per-file SettingsBackupTest.java = alsutton@google.com, nathch@google.com, rthakohov@google.com diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index baa266a6e5cd..2412a32bd71b 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -229,6 +229,7 @@ public class SettingsBackupTest { Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM, Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR, Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_SV, + Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_VR, Settings.Global.DEVICE_DEMO_MODE, Settings.Global.BATTERY_SAVER_ADAPTIVE_CONSTANTS, Settings.Global.BATTERY_SAVER_CONSTANTS, diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml index 3714db324fb4..939c5f9f7ecb 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml @@ -73,7 +73,7 @@ android:id="@+id/gradient_clock_view" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textSize="100dp" + android:textSize="80dp" android:letterSpacing="0.02" android:lineSpacingMultiplier=".8" android:includeFontPadding="false" diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 2e845fbb21dd..0e6bc24b02d6 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -94,6 +94,7 @@ import com.android.settingslib.fuelgauge.BatteryStatus; import com.android.systemui.DejankUtils; import com.android.systemui.Dumpable; import com.android.systemui.R; +import com.android.systemui.biometrics.AuthController; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Background; @@ -235,6 +236,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private final Context mContext; private final boolean mIsPrimaryUser; private final boolean mIsAutomotive; + private final AuthController mAuthController; private final StatusBarStateController mStatusBarStateController; HashMap<Integer, SimData> mSimDatas = new HashMap<>(); HashMap<Integer, ServiceState> mServiceStates = new HashMap<Integer, ServiceState>(); @@ -1581,7 +1583,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab RingerModeTracker ringerModeTracker, @Background Executor backgroundExecutor, StatusBarStateController statusBarStateController, - LockPatternUtils lockPatternUtils) { + LockPatternUtils lockPatternUtils, + AuthController authController) { mContext = context; mSubscriptionManager = SubscriptionManager.from(context); mDeviceProvisioned = isDeviceProvisionedInSettingsDb(); @@ -1591,6 +1594,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mRingerModeTracker = ringerModeTracker; mStatusBarStateController = statusBarStateController; mLockPatternUtils = lockPatternUtils; + mAuthController = authController; dumpManager.registerDumpable(getClass().getName(), this); mHandler = new Handler(mainLooper) { @@ -1853,7 +1857,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private void updateLockScreenMode() { mLockScreenMode = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.SHOW_NEW_LOCKSCREEN, 0); + Settings.Global.SHOW_NEW_LOCKSCREEN, mAuthController.isUdfpsEnrolled() ? 1 : 0); } private final UserSwitchObserver mUserSwitchObserver = new UserSwitchObserver() { diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java index d8e94bb45b75..b30103ef9b59 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java @@ -188,7 +188,7 @@ public class SystemUIFactory { * This method is overridden in vendor specific implementation of Sys UI. */ public BackGestureTfClassifierProvider createBackGestureTfClassifierProvider( - AssetManager am) { + AssetManager am, String modelName) { return new BackGestureTfClassifierProvider(); } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java index 64a2acab79ee..e40185c279a8 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java @@ -32,6 +32,7 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.view.WindowManager; +import android.view.WindowManager.LayoutParams; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; @@ -67,7 +68,7 @@ class MagnificationModeSwitch { private final int mTapTimeout = ViewConfiguration.getTapTimeout(); private final int mTouchSlop; private int mMagnificationMode = Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; - private final WindowManager.LayoutParams mParams; + private final LayoutParams mParams; private boolean mIsVisible = false; MagnificationModeSwitch(Context context) { @@ -80,7 +81,7 @@ class MagnificationModeSwitch { mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class); mWindowManager = (WindowManager) mContext.getSystemService( Context.WINDOW_SERVICE); - mParams = createLayoutParams(); + mParams = createLayoutParams(context); mImageView = imageView; mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop(); applyResourcesValues(); @@ -221,11 +222,22 @@ class MagnificationModeSwitch { } void onConfigurationChanged(int configDiff) { - if ((configDiff & ActivityInfo.CONFIG_DENSITY) == 0) { + if ((configDiff & ActivityInfo.CONFIG_DENSITY) != 0) { + applyResourcesValues(); + mImageView.setImageResource(getIconResId(mMagnificationMode)); + return; + } + if ((configDiff & ActivityInfo.CONFIG_LOCALE) != 0) { + updateAccessibilityWindowTitle(); return; } - applyResourcesValues(); - mImageView.setImageResource(getIconResId(mMagnificationMode)); + } + + private void updateAccessibilityWindowTitle() { + mParams.accessibilityTitle = getAccessibilityWindowTitle(mContext); + if (mIsVisible) { + mWindowManager.updateViewLayout(mImageView, mParams); + } } private void toggleMagnificationMode() { @@ -261,14 +273,19 @@ class MagnificationModeSwitch { : R.drawable.ic_open_in_new_fullscreen; } - private static WindowManager.LayoutParams createLayoutParams() { - final WindowManager.LayoutParams params = new WindowManager.LayoutParams( - WindowManager.LayoutParams.WRAP_CONTENT, - WindowManager.LayoutParams.WRAP_CONTENT, - WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, + private static LayoutParams createLayoutParams(Context context) { + final LayoutParams params = new LayoutParams( + LayoutParams.WRAP_CONTENT, + LayoutParams.WRAP_CONTENT, + LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, + LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT); params.gravity = Gravity.BOTTOM | Gravity.RIGHT; + params.accessibilityTitle = getAccessibilityWindowTitle(context); return params; } + + private static String getAccessibilityWindowTitle(Context context) { + return context.getString(com.android.internal.R.string.android_system_label); + } } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java index e9e453b3d981..98424beab14e 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java @@ -53,7 +53,8 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall CommandQueue.Callbacks { private static final String TAG = "WindowMagnification"; private static final int CONFIG_MASK = - ActivityInfo.CONFIG_DENSITY | ActivityInfo.CONFIG_ORIENTATION; + ActivityInfo.CONFIG_DENSITY | ActivityInfo.CONFIG_ORIENTATION + | ActivityInfo.CONFIG_LOCALE; @VisibleForTesting protected WindowMagnificationAnimationController mWindowMagnificationAnimationController; diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java index 340ca044a1ef..fd89baa61657 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java @@ -16,7 +16,7 @@ package com.android.systemui.accessibility; -import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; +import static android.view.WindowManager.LayoutParams; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; @@ -254,9 +254,18 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold } } else if ((configDiff & ActivityInfo.CONFIG_ORIENTATION) != 0) { onRotate(); + } else if ((configDiff & ActivityInfo.CONFIG_LOCALE) != 0) { + updateAccessibilityWindowTitleIfNeeded(); } } + private void updateAccessibilityWindowTitleIfNeeded() { + if (!isWindowVisible()) return; + LayoutParams params = (LayoutParams) mMirrorView.getLayoutParams(); + params.accessibilityTitle = getAccessibilityWindowTitle(); + mWm.updateViewLayout(mMirrorView, params); + } + /** Handles MirrorWindow position when the navigation bar mode changed. */ public void onNavigationModeChanged(int mode) { mNavBarMode = mode; @@ -290,8 +299,8 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold return; } // The rect of MirrorView is going to be transformed. - WindowManager.LayoutParams params = - (WindowManager.LayoutParams) mMirrorView.getLayoutParams(); + LayoutParams params = + (LayoutParams) mMirrorView.getLayoutParams(); mTmpRect.set(params.x, params.y, params.x + params.width, params.y + params.height); final RectF transformedRect = new RectF(mTmpRect); matrix.mapRect(transformedRect); @@ -313,17 +322,18 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold int windowWidth = mMagnificationFrame.width() + 2 * mMirrorSurfaceMargin; int windowHeight = mMagnificationFrame.height() + 2 * mMirrorSurfaceMargin; - WindowManager.LayoutParams params = new WindowManager.LayoutParams( + LayoutParams params = new LayoutParams( windowWidth, windowHeight, - WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, - WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL - | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, + LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, + LayoutParams.FLAG_NOT_TOUCH_MODAL + | LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT); params.gravity = Gravity.TOP | Gravity.LEFT; params.x = mMagnificationFrame.left - mMirrorSurfaceMargin; params.y = mMagnificationFrame.top - mMirrorSurfaceMargin; - params.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; + params.layoutInDisplayCutoutMode = LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; params.setTitle(mContext.getString(R.string.magnification_window_title)); + params.accessibilityTitle = getAccessibilityWindowTitle(); mMirrorView = LayoutInflater.from(mContext).inflate(R.layout.window_magnifier_view, null); mMirrorSurfaceView = mMirrorView.findViewById(R.id.surface_view); @@ -369,6 +379,10 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold return regionInsideDragBorder; } + private String getAccessibilityWindowTitle() { + return mResources.getString(com.android.internal.R.string.android_system_label); + } + private void showControls() { if (mMirrorWindowControl != null) { mMirrorWindowControl.showControl(); @@ -432,8 +446,8 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold } final int maxMirrorViewX = mDisplaySize.x - mMirrorView.getWidth(); final int maxMirrorViewY = mDisplaySize.y - mMirrorView.getHeight() - mNavGestureHeight; - WindowManager.LayoutParams params = - (WindowManager.LayoutParams) mMirrorView.getLayoutParams(); + LayoutParams params = + (LayoutParams) mMirrorView.getLayoutParams(); params.x = mMagnificationFrame.left - mMirrorSurfaceMargin; params.y = mMagnificationFrame.top - mMirrorSurfaceMargin; // If nav bar mode supports swipe-up gesture, the Y position of mirror view should not diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index 874c73baf146..c72bc2543b36 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -29,6 +29,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.res.Configuration; +import android.graphics.RectF; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricPrompt; import android.hardware.biometrics.IBiometricSysuiReceiver; @@ -42,6 +43,7 @@ import android.os.Handler; import android.os.Looper; import android.os.RemoteException; import android.util.Log; +import android.view.MotionEvent; import android.view.WindowManager; import com.android.internal.R; @@ -243,16 +245,25 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, } /** + * @return where the UDFPS exists on the screen in pixels. + */ + public RectF getUdfpsRegion() { + return mUdfpsController == null ? null : mUdfpsController.getSensorLocation(); + } + + /** * Requests fingerprint scan. * * @param screenX X position of long press * @param screenY Y position of long press + * @param major length of the major axis. See {@link MotionEvent#AXIS_TOOL_MAJOR}. + * @param minor length of the minor axis. See {@link MotionEvent#AXIS_TOOL_MINOR}. */ - public void onAodInterrupt(int screenX, int screenY) { + public void onAodInterrupt(int screenX, int screenY, float major, float minor) { if (mUdfpsController == null) { return; } - mUdfpsController.onAodInterrupt(screenX, screenY); + mUdfpsController.onAodInterrupt(screenX, screenY, major, minor); } /** @@ -475,7 +486,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, /** * Whether the current user has a UDFP enrolled. */ - public boolean hasUdfpsEnrolled() { + public boolean isUdfpsEnrolled() { // TODO: (b/171392825) right now only checks whether the UDFPS sensor exists on this device // but not whether user has enrolled or not return mUdfpsController != null; diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index 3c2e00869ab8..a4b407d2785d 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -25,6 +25,7 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.PixelFormat; import android.graphics.Point; +import android.graphics.RectF; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.IUdfpsOverlayController; @@ -244,6 +245,13 @@ class UdfpsController implements DozeReceiver { mView.dozeTimeTick(); } + /** + * @return where the UDFPS exists on the screen in pixels. + */ + public RectF getSensorLocation() { + return mView.getSensorRect(); + } + private void setShowOverlay(boolean show) { if (show == mIsOverlayRequested) { return; @@ -337,7 +345,7 @@ class UdfpsController implements DozeReceiver { * This is intented to be called in response to a sensor that triggers an AOD interrupt for the * fingerprint sensor. */ - void onAodInterrupt(int screenX, int screenY) { + void onAodInterrupt(int screenX, int screenY, float major, float minor) { if (mIsAodInterruptActive) { return; } @@ -348,7 +356,7 @@ class UdfpsController implements DozeReceiver { mCancelAodTimeoutAction = mFgExecutor.executeDelayed(this::onCancelAodInterrupt, AOD_INTERRUPT_TIMEOUT_MILLIS); // using a hard-coded value for major and minor until it is available from the sensor - onFingerDown(screenX, screenY, 13.0f, 13.0f); + onFingerDown(screenX, screenY, minor, major); } /** diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java index 0ed3bda40c4b..7edcf66196e4 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java @@ -196,6 +196,10 @@ public class UdfpsView extends View implements DozeReceiver, canvas.restore(); } + RectF getSensorRect() { + return new RectF(mSensorRect); + } + void setHbmSupported(boolean hbmSupported) { mHbmSupported = hbmSupported; } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java index 8220835ac509..f07e5afdd887 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java @@ -156,7 +156,7 @@ public class DozeSensors { findSensorWithType(config.udfpsLongPressSensorType()), "doze_pulse_on_auth", true /* settingDef */, - authController.hasUdfpsEnrolled() /* configured */, + authController.isUdfpsEnrolled() /* configured */, DozeLog.REASON_SENSOR_UDFPS_LONG_PRESS, true /* reports touch coordinates */, true /* touchscreen */, diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index c581e85ec444..58e49f896931 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -131,7 +131,10 @@ public class DozeTriggers implements DozeMachine.Part { DOZING_UPDATE_SENSOR_WAKE_LOCKSCREEN(440), @UiEvent(doc = "Dozing updated because sensor was tapped.") - DOZING_UPDATE_SENSOR_TAP(441); + DOZING_UPDATE_SENSOR_TAP(441), + + @UiEvent(doc = "Dozing updated because on display auth was triggered from AOD.") + DOZING_UPDATE_AUTH_TRIGGERED(442); private final int mId; @@ -155,6 +158,7 @@ public class DozeTriggers implements DozeMachine.Part { case 7: return DOZING_UPDATE_SENSOR_WAKEUP; case 8: return DOZING_UPDATE_SENSOR_WAKE_LOCKSCREEN; case 9: return DOZING_UPDATE_SENSOR_TAP; + case 10: return DOZING_UPDATE_AUTH_TRIGGERED; default: return null; } } @@ -289,7 +293,8 @@ public class DozeTriggers implements DozeMachine.Part { requestPulse(DozeLog.REASON_SENSOR_UDFPS_LONG_PRESS, true, null); // Since the gesture won't be received by the UDFPS view, manually inject an // event. - mAuthController.onAodInterrupt((int) screenX, (int) screenY); + mAuthController.onAodInterrupt((int) screenX, (int) screenY, + rawValues[2] /* major */, rawValues[3] /* minor */); } else { mDozeHost.extendPulse(pulseReason); } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt index 1beb875af70c..5eb6687f0b81 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt @@ -143,6 +143,11 @@ class MediaCarouselController @Inject constructor( if (newConfig == null) return isRtl = newConfig.layoutDirection == View.LAYOUT_DIRECTION_RTL } + + override fun onUiModeChanged() { + // Only settings button needs to update for dark theme + inflateSettingsButton() + } } init { diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt index 6f6ee4c8091d..c6ed9c096544 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt @@ -641,7 +641,8 @@ class MediaDataManager( // Move to resume key (aka package name) if that key doesn't already exist. val resumeAction = getResumeMediaAction(removed.resumeAction!!) val updated = removed.copy(token = null, actions = listOf(resumeAction), - actionsToShowInCompact = listOf(0), active = false, resumption = true) + actionsToShowInCompact = listOf(0), active = false, resumption = true, + isClearable = true) val pkg = removed.packageName val migrate = mediaEntries.put(pkg, updated) == null // Notify listeners of "new" controls when migrating or removed and update when not diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java index 18cc746666d8..f9982d04e04b 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java @@ -137,7 +137,9 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa && (properties.getKeyset().contains( SystemUiDeviceConfigFlags.BACK_GESTURE_ML_MODEL_THRESHOLD) || properties.getKeyset().contains( - SystemUiDeviceConfigFlags.USE_BACK_GESTURE_ML_MODEL))) { + SystemUiDeviceConfigFlags.USE_BACK_GESTURE_ML_MODEL) + || properties.getKeyset().contains( + SystemUiDeviceConfigFlags.BACK_GESTURE_ML_MODEL_NAME))) { updateMLModelState(); } } @@ -483,14 +485,15 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa private void updateMLModelState() { boolean newState = mIsEnabled && DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, SystemUiDeviceConfigFlags.USE_BACK_GESTURE_ML_MODEL, false); - if (newState == mUseMLModel) { return; } if (newState) { + String mlModelName = DeviceConfig.getString(DeviceConfig.NAMESPACE_SYSTEMUI, + SystemUiDeviceConfigFlags.BACK_GESTURE_ML_MODEL_NAME, "backgesture"); mBackGestureTfClassifierProvider = SystemUIFactory.getInstance() - .createBackGestureTfClassifierProvider(mContext.getAssets()); + .createBackGestureTfClassifierProvider(mContext.getAssets(), mlModelName); mMLModelThreshold = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_SYSTEMUI, SystemUiDeviceConfigFlags.BACK_GESTURE_ML_MODEL_THRESHOLD, 0.9f); if (mBackGestureTfClassifierProvider.isActive()) { @@ -540,21 +543,22 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa boolean withinRange = false; float results = -1; + // Disallow if we are in the bottom gesture area + if (y >= (mDisplaySize.y - mBottomGestureHeight)) { + return false; + } + // If the point is way too far (twice the margin), it is + // not interesting to us for logging purposes, nor we + // should process it. Simply return false and keep + // mLogGesture = false. + if (x > 2 * (mEdgeWidthLeft + mLeftInset) + && x < (mDisplaySize.x - 2 * (mEdgeWidthRight + mRightInset))) { + return false; + } + if (mUseMLModel && (results = getBackGesturePredictionsCategory(x, y)) != -1) { withinRange = results == 1 ? true : false; } else { - // Disallow if we are in the bottom gesture area - if (y >= (mDisplaySize.y - mBottomGestureHeight)) { - return false; - } - // If the point is way too far (twice the margin), it is - // not interesting to us for logging purposes, nor we - // should process it. Simply return false and keep - // mLogGesture = false. - if (x > 2 * (mEdgeWidthLeft + mLeftInset) - && x < (mDisplaySize.x - 2 * (mEdgeWidthRight + mRightInset))) { - return false; - } // Denotes whether we should proceed with the gesture. // Even if it is false, we may want to log it assuming // it is not invalid due to exclusion. 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 5cee5bd0cc4e..2a2a0b14a2d2 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 @@ -835,7 +835,13 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable if (!mShouldDrawNotificationBackground) { return; } - + final boolean clearUndershelf = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.SHOW_NEW_NOTIF_DISMISS, 0 /* show background by default */) == 1; + if (clearUndershelf) { + mBackgroundPaint.setColor(Color.TRANSPARENT); + invalidate(); + return; + } // Interpolate between semi-transparent notification panel background color // and white AOD separator. float colorInterpolation = MathUtils.smoothStep(0.4f /* start */, 1f /* end */, 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 ef4108b9762d..bd228933c8a5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java @@ -86,9 +86,14 @@ public class KeyguardClockPositionAlgorithm { private int mMaxShadeBottom; /** - * Minimum distance from the status bar. + * Recommended distance from the status bar without the lock icon. */ - private int mContainerTopPadding; + private int mContainerTopPaddingWithoutLockIcon; + + /** + * Recommended distance from the status bar with the lock icon. + */ + private int mContainerTopPaddingWithLockIcon; /** * @see NotificationPanelViewController#getExpandedFraction() @@ -131,24 +136,31 @@ public class KeyguardClockPositionAlgorithm { public void loadDimens(Resources res) { mClockNotificationsMargin = res.getDimensionPixelSize( R.dimen.keyguard_clock_notifications_margin); + + mContainerTopPaddingWithoutLockIcon = + res.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin) / 2; // Consider the lock icon when determining the minimum top padding between the status bar // and top of the clock. - mContainerTopPadding = Math.max(res.getDimensionPixelSize( - R.dimen.keyguard_clock_top_margin), - res.getDimensionPixelSize(R.dimen.keyguard_lock_height) - + res.getDimensionPixelSize(R.dimen.keyguard_lock_padding) - + res.getDimensionPixelSize(R.dimen.keyguard_clock_lock_margin)); + mContainerTopPaddingWithLockIcon = + Math.max(res.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin), + res.getDimensionPixelSize(R.dimen.keyguard_lock_height) + + res.getDimensionPixelSize(R.dimen.keyguard_lock_padding) + + res.getDimensionPixelSize(R.dimen.keyguard_clock_lock_margin)); mBurnInPreventionOffsetX = res.getDimensionPixelSize( R.dimen.burn_in_prevention_offset_x); mBurnInPreventionOffsetY = res.getDimensionPixelSize( R.dimen.burn_in_prevention_offset_y); } - public void setup(int minTopMargin, int maxShadeBottom, int notificationStackHeight, + /** + * Sets up algorithm values. + */ + public void setup(int statusBarMinHeight, int maxShadeBottom, int notificationStackHeight, float panelExpansion, int parentHeight, int keyguardStatusHeight, int clockPreferredY, boolean hasCustomClock, boolean hasVisibleNotifs, float dark, float emptyDragAmount, - boolean bypassEnabled, int unlockedStackScrollerPadding) { - mMinTopMargin = minTopMargin + mContainerTopPadding; + boolean bypassEnabled, int unlockedStackScrollerPadding, boolean udfpsEnrolled) { + mMinTopMargin = statusBarMinHeight + (udfpsEnrolled ? mContainerTopPaddingWithoutLockIcon : + mContainerTopPaddingWithLockIcon); mMaxShadeBottom = maxShadeBottom; mNotificationStackHeight = notificationStackHeight; mPanelExpansion = panelExpansion; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java index 77ae059a0cb9..5e883bee13a8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.phone; +import static android.view.View.GONE; + import static com.android.systemui.statusbar.phone.LockIcon.STATE_BIOMETRICS_ERROR; import static com.android.systemui.statusbar.phone.LockIcon.STATE_LOCKED; import static com.android.systemui.statusbar.phone.LockIcon.STATE_LOCK_OPEN; @@ -37,6 +39,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.R; +import com.android.systemui.biometrics.AuthController; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dock.DockManager; @@ -74,6 +77,7 @@ public class LockscreenLockIconController { private final KeyguardStateController mKeyguardStateController; private final Resources mResources; private final HeadsUpManagerPhone mHeadsUpManagerPhone; + private final AuthController mAuthController; private boolean mKeyguardShowing; private boolean mKeyguardJustShown; private boolean mBlockUpdates; @@ -322,7 +326,8 @@ public class LockscreenLockIconController { @Nullable DockManager dockManager, KeyguardStateController keyguardStateController, @Main Resources resources, - HeadsUpManagerPhone headsUpManagerPhone) { + HeadsUpManagerPhone headsUpManagerPhone, + AuthController authController) { mLockscreenGestureLogger = lockscreenGestureLogger; mKeyguardUpdateMonitor = keyguardUpdateMonitor; mLockPatternUtils = lockPatternUtils; @@ -337,6 +342,7 @@ public class LockscreenLockIconController { mKeyguardStateController = keyguardStateController; mResources = resources; mHeadsUpManagerPhone = headsUpManagerPhone; + mAuthController = authController; mKeyguardIndicationController.setLockIconController(this); } @@ -502,6 +508,11 @@ public class LockscreenLockIconController { * @return true if the visibility changed */ private boolean updateIconVisibility() { + if (mAuthController.isUdfpsEnrolled()) { + boolean changed = mLockIcon.getVisibility() == GONE; + mLockIcon.setVisibility(GONE); + return changed; + } boolean onAodOrDocked = mStatusBarStateController.isDozing() || mDocked; boolean invisible = onAodOrDocked || mWakeAndUnlockRunning || mShowingLaunchAffordance; boolean fingerprintOrBypass = mFingerprintUnlock 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 b185f48b0245..e9a7132f4a5c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -77,6 +77,7 @@ import com.android.keyguard.dagger.KeyguardStatusViewComponent; import com.android.systemui.DejankUtils; import com.android.systemui.Interpolators; import com.android.systemui.R; +import com.android.systemui.biometrics.AuthController; import com.android.systemui.classifier.Classifier; import com.android.systemui.dagger.qualifiers.DisplayId; import com.android.systemui.dagger.qualifiers.Main; @@ -263,6 +264,7 @@ public class NotificationPanelViewController extends PanelViewController { private final KeyguardBypassController mKeyguardBypassController; private final KeyguardUpdateMonitor mUpdateMonitor; private final ConversationNotificationManager mConversationNotificationManager; + private final AuthController mAuthController; private final MediaHierarchyManager mMediaHierarchyManager; private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory; @@ -516,7 +518,8 @@ public class NotificationPanelViewController extends PanelViewController { NotificationStackScrollLayoutController notificationStackScrollLayoutController, KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory, NotificationGroupManagerLegacy groupManager, - NotificationIconAreaController notificationIconAreaController) { + NotificationIconAreaController notificationIconAreaController, + AuthController authController) { super(view, falsingManager, dozeLog, keyguardStateController, (SysuiStatusBarStateController) statusBarStateController, vibratorHelper, latencyTracker, flingAnimationUtilsBuilder, statusBarTouchableRegionManager); @@ -581,6 +584,7 @@ public class NotificationPanelViewController extends PanelViewController { mLockscreenUserManager = notificationLockscreenUserManager; mEntryManager = notificationEntryManager; mConversationNotificationManager = conversationNotificationManager; + mAuthController = authController; mView.setBackgroundColor(Color.TRANSPARENT); OnAttachStateChangeListener onAttachStateChangeListener = new OnAttachStateChangeListener(); @@ -868,7 +872,8 @@ public class NotificationPanelViewController extends PanelViewController { - mShelfHeight / 2.0f - mDarkIconSize / 2.0f), clockPreferredY, hasCustomClock(), hasVisibleNotifications, mInterpolatedDarkAmount, mEmptyDragAmount, - bypassEnabled, getUnlockedStackScrollerPadding()); + bypassEnabled, getUnlockedStackScrollerPadding(), + mAuthController.isUdfpsEnrolled()); mClockPositionAlgorithm.run(mClockPositionResult); mKeyguardStatusViewController.updatePosition( mClockPositionResult.clockX, mClockPositionResult.clockY, animateClock); @@ -908,6 +913,13 @@ public class NotificationPanelViewController extends PanelViewController { mNotificationStackScrollLayoutController.getHeight() - minPadding - shelfSize - Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding) - mKeyguardStatusViewController.getLogoutButtonHeight(); + + if (mAuthController.isUdfpsEnrolled()) { + availableSpace = mNotificationStackScrollLayoutController.getHeight() + - minPadding - shelfSize + - (mStatusBar.getDisplayHeight() - mAuthController.getUdfpsRegion().top); + } + int count = 0; ExpandableView previousView = null; for (int i = 0; i < mNotificationStackScrollLayoutController.getChildCount(); i++) { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index e6479ddaedb3..caab2abd7ec6 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -79,6 +79,7 @@ import com.android.internal.widget.ILockSettings; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor.BiometricAuthenticated; import com.android.systemui.SysuiTestCase; +import com.android.systemui.biometrics.AuthController; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dump.DumpManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -156,6 +157,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { private LiveData<Integer> mRingerModeLiveData; @Mock private StatusBarStateController mStatusBarStateController; + @Mock + private AuthController mAuthController; // Direct executor private Executor mBackgroundExecutor = Runnable::run; private TestableLooper mTestableLooper; @@ -198,6 +201,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { when(mTelephonyManager.getServiceStateForSubscriber(anyInt())) .thenReturn(new ServiceState()); when(mLockPatternUtils.getLockSettings()).thenReturn(mLockSettings); + when(mAuthController.isUdfpsEnrolled()).thenReturn(false); mSpiedContext.addMockSystemService(TrustManager.class, mTrustManager); mSpiedContext.addMockSystemService(FingerprintManager.class, mFingerprintManager); mSpiedContext.addMockSystemService(BiometricManager.class, mBiometricManager); @@ -796,7 +800,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { TestableLooper.get(KeyguardUpdateMonitorTest.this).getLooper(), mBroadcastDispatcher, mDumpManager, mRingerModeTracker, mBackgroundExecutor, - mStatusBarStateController, mLockPatternUtils); + mStatusBarStateController, mLockPatternUtils, + mAuthController); setStrongAuthTracker(KeyguardUpdateMonitorTest.this.mStrongAuthTracker); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java index c923515fc8cc..a0ae35ffef00 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java @@ -287,6 +287,33 @@ public class MagnificationModeSwitchTest extends SysuiTestCase { assertShowFadingAnimation(FADE_OUT_ALPHA); } + @Test + public void showButton_hasAccessibilityWindowTitle() { + mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW); + + ArgumentCaptor<WindowManager.LayoutParams> paramsArgumentCaptor = ArgumentCaptor.forClass( + WindowManager.LayoutParams.class); + verify(mWindowManager).addView(eq(mSpyImageView), paramsArgumentCaptor.capture()); + assertEquals(getContext().getResources().getString( + com.android.internal.R.string.android_system_label), + paramsArgumentCaptor.getValue().accessibilityTitle); + } + + @Test + public void onLocaleChanged_buttonIsShowing_updateA11yWindowTitle() { + final String newA11yWindowTitle = "new a11y window title"; + mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN); + + getContext().getOrCreateTestableResources().addOverride( + com.android.internal.R.string.android_system_label, newA11yWindowTitle); + mMagnificationModeSwitch.onConfigurationChanged(ActivityInfo.CONFIG_LOCALE); + + ArgumentCaptor<WindowManager.LayoutParams> paramsArgumentCaptor = ArgumentCaptor.forClass( + WindowManager.LayoutParams.class); + verify(mWindowManager).updateViewLayout(eq(mSpyImageView), paramsArgumentCaptor.capture()); + assertEquals(newA11yWindowTitle, paramsArgumentCaptor.getValue().accessibilityTitle); + } + private void assertModeUnchanged(int expectedMode) { final int actualMode = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0); diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java index f1606c5660ed..a39bc702900e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java @@ -41,6 +41,7 @@ import android.content.pm.ActivityInfo; import android.content.res.Resources; import android.os.Handler; import android.testing.AndroidTestingRunner; +import android.testing.TestableResources; import android.view.Display; import android.view.Surface; import android.view.SurfaceControl; @@ -114,8 +115,7 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { when(mTransaction.remove(any())).thenReturn(mTransaction); when(mTransaction.setGeometry(any(), any(), any(), anyInt())).thenReturn(mTransaction); - mResources = Mockito.spy(mContext.getResources()); - when(mContext.getResources()).thenReturn(mResources); + mResources = getContext().getOrCreateTestableResources().getResources(); mWindowMagnificationController = new WindowMagnificationController(mContext, mHandler, mSfVsyncFrameProvider, mMirrorWindowControl, mTransaction, mWindowMagnifierCallback); @@ -222,7 +222,6 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { assertEquals(Surface.ROTATION_90, mWindowMagnificationController.mRotation); } - @Test public void onDensityChanged_enabled_updateDimensionsAndResetWindowMagnification() { mInstrumentation.runOnMainSync(() -> { @@ -310,4 +309,41 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { verify(mWindowManager).updateViewLayout(eq(mMirrorView), any()); } + + @Test + public void enableWindowMagnification_hasA11yWindowTitle() { + mInstrumentation.runOnMainSync(() -> { + mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN, + Float.NaN); + }); + + ArgumentCaptor<WindowManager.LayoutParams> paramsArgumentCaptor = ArgumentCaptor.forClass( + WindowManager.LayoutParams.class); + verify(mWindowManager).addView(eq(mMirrorView), paramsArgumentCaptor.capture()); + assertEquals(getContext().getResources().getString( + com.android.internal.R.string.android_system_label), + paramsArgumentCaptor.getValue().accessibilityTitle); + } + + @Test + public void onLocaleChanged_enabled_updateA11yWindowTitle() { + final String newA11yWindowTitle = "new a11y window title"; + mInstrumentation.runOnMainSync(() -> { + mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN, + Float.NaN); + }); + final TestableResources testableResources = getContext().getOrCreateTestableResources(); + testableResources.addOverride(com.android.internal.R.string.android_system_label, + newA11yWindowTitle); + when(mContext.getResources()).thenReturn(testableResources.getResources()); + + mInstrumentation.runOnMainSync(() -> { + mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_LOCALE); + }); + + ArgumentCaptor<WindowManager.LayoutParams> paramsArgumentCaptor = ArgumentCaptor.forClass( + WindowManager.LayoutParams.class); + verify(mWindowManager).updateViewLayout(eq(mMirrorView), paramsArgumentCaptor.capture()); + assertEquals(newA11yWindowTitle, paramsArgumentCaptor.getValue().accessibilityTitle); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java index 0186d7394ecb..42bb005b5144 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java @@ -494,8 +494,9 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testOnAodInterrupt() { final int pos = 10; - mAuthController.onAodInterrupt(pos, pos); - verify(mUdfpsController).onAodInterrupt(eq(pos), eq(pos)); + final float majorMinor = 5f; + mAuthController.onAodInterrupt(pos, pos, majorMinor, majorMinor); + verify(mUdfpsController).onAodInterrupt(eq(pos), eq(pos), eq(majorMinor), eq(majorMinor)); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java index a95396cccd66..82ffd46f7164 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -234,10 +234,10 @@ public class UdfpsControllerTest extends SysuiTestCase { mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID); mFgExecutor.runAllReady(); // WHEN fingerprint is requested because of AOD interrupt - mUdfpsController.onAodInterrupt(0, 0); + mUdfpsController.onAodInterrupt(0, 0, 2f, 3f); // THEN the event is passed to the FingerprintManager verify(mFingerprintManager).onPointerDown(eq(mUdfpsController.mSensorProps.sensorId), eq(0), - eq(0), anyFloat(), anyFloat()); + eq(0), eq(3f) /* minor */, eq(2f) /* major */); // AND the scrim and dot is shown verify(mUdfpsView).showScrimAndDot(); } @@ -247,7 +247,7 @@ public class UdfpsControllerTest extends SysuiTestCase { // GIVEN AOD interrupt mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID); mFgExecutor.runAllReady(); - mUdfpsController.onAodInterrupt(0, 0); + mUdfpsController.onAodInterrupt(0, 0, 0f, 0f); // WHEN it is cancelled mUdfpsController.onCancelAodInterrupt(); // THEN the scrim and dot is hidden @@ -259,7 +259,7 @@ public class UdfpsControllerTest extends SysuiTestCase { // GIVEN AOD interrupt mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID); mFgExecutor.runAllReady(); - mUdfpsController.onAodInterrupt(0, 0); + mUdfpsController.onAodInterrupt(0, 0, 0f, 0f); // WHEN it times out mFgExecutor.advanceClockToNext(); mFgExecutor.runAllReady(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java index 6d87cc3c3e38..4bbba56395f8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java @@ -194,10 +194,13 @@ public class DozeTriggersTest extends SysuiTestCase { public void testOnSensor_Fingerprint() { final int screenX = 100; final int screenY = 100; + final float minor = 2f; + final float major = 3f; final int reason = DozeLog.REASON_SENSOR_UDFPS_LONG_PRESS; - mTriggers.onSensor(reason, screenX, screenY, null); + float[] rawValues = new float[]{screenX, screenY, minor, major}; + mTriggers.onSensor(reason, screenX, screenY, rawValues); verify(mHost).extendPulse(reason); - verify(mAuthController).onAodInterrupt(eq(screenX), eq(screenY)); + verify(mAuthController).onAodInterrupt(eq(screenX), eq(screenY), eq(minor), eq(major)); } private void waitForSensorManager() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java index 2042faba2b3a..83ef87a1066c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java @@ -384,7 +384,7 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase { mClockPositionAlgorithm.setup(EMPTY_MARGIN, SCREEN_HEIGHT, mNotificationStackHeight, mPanelExpansion, SCREEN_HEIGHT, mKeyguardStatusHeight, mPreferredClockY, mHasCustomClock, mHasVisibleNotifs, mDark, ZERO_DRAG, false /* bypassEnabled */, - 0 /* unlockedStackScrollerPadding */); + 0 /* unlockedStackScrollerPadding */, false /* udfpsEnrolled */); mClockPositionAlgorithm.run(mClockPosition); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java index 06d0331543da..72a0258e148a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java @@ -32,6 +32,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.SysuiTestCase; +import com.android.systemui.biometrics.AuthController; import com.android.systemui.dock.DockManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.KeyguardIndicationController; @@ -80,6 +81,8 @@ public class LockscreenIconControllerTest extends SysuiTestCase { private Resources mResources; @Mock private HeadsUpManagerPhone mHeadsUpManagerPhone; + @Mock + private AuthController mAuthController; private LockscreenLockIconController mLockIconController; private OnAttachStateChangeListener mOnAttachStateChangeListener; @@ -89,13 +92,14 @@ public class LockscreenIconControllerTest extends SysuiTestCase { public void setUp() { MockitoAnnotations.initMocks(this); + when(mAuthController.isUdfpsEnrolled()).thenReturn(false); when(mLockIcon.getContext()).thenReturn(mContext); mLockIconController = new LockscreenLockIconController( mLockscreenGestureLogger, mKeyguardUpdateMonitor, mLockPatternUtils, mShadeController, mAccessibilityController, mKeyguardIndicationController, mStatusBarStateController, mConfigurationController, mNotificationWakeUpCoordinator, mKeyguardBypassController, mDockManager, mKeyguardStateController, mResources, - mHeadsUpManagerPhone); + mHeadsUpManagerPhone, mAuthController); ArgumentCaptor<OnAttachStateChangeListener> onAttachStateChangeListenerArgumentCaptor = ArgumentCaptor.forClass(OnAttachStateChangeListener.class); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java index cb56f1fbc054..3b123f65d886 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java @@ -58,6 +58,7 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.dagger.KeyguardStatusViewComponent; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.biometrics.AuthController; import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.doze.DozeLog; import com.android.systemui.media.MediaHierarchyManager; @@ -194,6 +195,8 @@ public class NotificationPanelViewTest extends SysuiTestCase { private KeyguardStatusViewController mKeyguardStatusViewController; @Mock private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController; + @Mock + private AuthController mAuthController; private NotificationPanelViewController mNotificationPanelViewController; private View.AccessibilityDelegate mAccessibiltyDelegate; @@ -201,6 +204,7 @@ public class NotificationPanelViewTest extends SysuiTestCase { @Before public void setup() { MockitoAnnotations.initMocks(this); + when(mAuthController.isUdfpsEnrolled()).thenReturn(false); when(mHeadsUpCallback.getContext()).thenReturn(mContext); when(mView.getResources()).thenReturn(mResources); when(mResources.getConfiguration()).thenReturn(mConfiguration); @@ -267,7 +271,8 @@ public class NotificationPanelViewTest extends SysuiTestCase { mNotificationStackScrollLayoutController, mKeyguardStatusViewComponentFactory, mGroupManager, - mNotificationAreaController); + mNotificationAreaController, + mAuthController); mNotificationPanelViewController.initDependencies( mStatusBar, mNotificationShelfController); diff --git a/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values-bn/strings.xml b/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values-bn/strings.xml new file mode 100644 index 000000000000..3e9c962f8946 --- /dev/null +++ b/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values-bn/strings.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ 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. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="display_cutout_emulation_overlay" msgid="7305489596221077240">"পাঞ্চ হোল কাট-আউট"</string> +</resources> diff --git a/services/backup/OWNERS b/services/backup/OWNERS index 7c7e74285bf5..3c5268c5a2a9 100644 --- a/services/backup/OWNERS +++ b/services/backup/OWNERS @@ -1,7 +1,6 @@ # Bug component: 656484 aabhinav@google.com -alsutton@google.com bryanmawhinney@google.com jstemmer@google.com nathch@google.com diff --git a/services/core/java/com/android/server/biometrics/sensors/face/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/Face10.java index f7998ee8caeb..15f8c5373672 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/Face10.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/Face10.java @@ -46,6 +46,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.util.Slog; +import android.util.proto.ProtoOutputStream; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; @@ -81,14 +82,14 @@ import java.util.Map; * Supports a single instance of the {@link android.hardware.biometrics.face.V1_0} or * its extended minor versions. */ -class Face10 implements IHwBinder.DeathRecipient { +class Face10 implements IHwBinder.DeathRecipient, ServiceProvider { private static final String TAG = "Face10"; private static final int ENROLL_TIMEOUT_SEC = 75; static final String NOTIFICATION_TAG = "FaceService"; static final int NOTIFICATION_ID = 1; - @NonNull private final FaceSensorPropertiesInternal mFaceSensorProperties; + @NonNull private final FaceSensorPropertiesInternal mSensorProperties; @NonNull private final Context mContext; @NonNull private final BiometricScheduler mScheduler; @NonNull private final Handler mHandler; @@ -96,23 +97,22 @@ class Face10 implements IHwBinder.DeathRecipient { @NonNull private final LockoutResetDispatcher mLockoutResetDispatcher; @NonNull private final LockoutHalImpl mLockoutTracker; @NonNull private final UsageStats mUsageStats; - @NonNull private NotificationManager mNotificationManager; - private final int mSensorId; + @NonNull private final NotificationManager mNotificationManager; @NonNull private final Map<Integer, Long> mAuthenticatorIds; - @Nullable private IBiometricsFace mDaemon; - private int mCurrentUserId = UserHandle.USER_NULL; // If a challenge is generated, keep track of its owner. Since IBiometricsFace@1.0 only // supports a single in-flight challenge, we must notify the interrupted owner that its // challenge is no longer valid. The interrupted owner will be notified when the interrupter // has finished. @Nullable private FaceGenerateChallengeClient mCurrentChallengeOwner; + private int mCurrentUserId = UserHandle.USER_NULL; + private final int mSensorId; private final UserSwitchObserver mUserSwitchObserver = new SynchronousUserSwitchObserver() { @Override public void onUserSwitching(int newUserId) { scheduleInternalCleanup(newUserId); - scheduleGetFeature(new Binder(), newUserId, + scheduleGetFeature(mSensorId, new Binder(), newUserId, BiometricFaceConstants.FEATURE_REQUIRE_ATTENTION, null, mContext.getOpPackageName()); } @@ -283,7 +283,7 @@ class Face10 implements IHwBinder.DeathRecipient { @BiometricManager.Authenticators.Types int strength, @NonNull LockoutResetDispatcher lockoutResetDispatcher, boolean supportsSelfIllumination, int maxTemplatesAllowed) { - mFaceSensorProperties = new FaceSensorPropertiesInternal(sensorId, + mSensorProperties = new FaceSensorPropertiesInternal(sensorId, Utils.authenticatorStrengthToPropertyStrength(strength), maxTemplatesAllowed, false /* supportsFaceDetect */, supportsSelfIllumination); mContext = context; @@ -375,9 +375,10 @@ class Face10 implements IHwBinder.DeathRecipient { if (halId != 0) { scheduleLoadAuthenticatorIds(); scheduleInternalCleanup(ActivityManager.getCurrentUser()); - scheduleGetFeature(new Binder(), ActivityManager.getCurrentUser(), - BiometricFaceConstants.FEATURE_REQUIRE_ATTENTION, - null, mContext.getOpPackageName()); + scheduleGetFeature(mSensorId, new Binder(), + ActivityManager.getCurrentUser(), + BiometricFaceConstants.FEATURE_REQUIRE_ATTENTION, null, + mContext.getOpPackageName()); } else { Slog.e(TAG, "Unable to set callback"); mDaemon = null; @@ -386,116 +387,39 @@ class Face10 implements IHwBinder.DeathRecipient { return mDaemon; } - @LockoutTracker.LockoutMode int getLockoutModeForUser(int userId) { - return mLockoutTracker.getLockoutModeForUser(userId); + @Override + public boolean containsSensor(int sensorId) { + return mSensorId == sensorId; } - private void scheduleLoadAuthenticatorIds() { - // Note that this can be performed on the scheduler (as opposed to being done immediately - // when the HAL is (re)loaded, since - // 1) If this is truly the first time it's being performed (e.g. system has just started), - // this will be run very early and way before any applications need to generate keys. - // 2) If this is being performed to refresh the authenticatorIds (e.g. HAL crashed and has - // just been reloaded), the framework already has a cache of the authenticatorIds. This - // is safe because authenticatorIds only change when A) new template has been enrolled, - // or B) all templates are removed. - mHandler.post(() -> { - for (UserInfo user : UserManager.get(mContext).getAliveUsers()) { - final int targetUserId = user.id; - if (!mAuthenticatorIds.containsKey(targetUserId)) { - scheduleUpdateActiveUserWithoutHandler(targetUserId); - } - } - }); + @Override + @NonNull + public List<FaceSensorPropertiesInternal> getSensorProperties() { + final List<FaceSensorPropertiesInternal> properties = new ArrayList<>(); + properties.add(mSensorProperties); + return properties; } - /** - * Schedules the {@link FaceUpdateActiveUserClient} without posting the work onto the - * handler. Many/most APIs are user-specific. However, the HAL requires explicit "setActiveUser" - * invocation prior to authenticate/enroll/etc. Thus, internally we usually want to schedule - * this operation on the same lambda/runnable as those operations so that the ordering is - * correct. - */ - private void scheduleUpdateActiveUserWithoutHandler(int targetUserId) { - final boolean hasEnrolled = !getEnrolledFaces(targetUserId).isEmpty(); - final FaceUpdateActiveUserClient client = new FaceUpdateActiveUserClient(mContext, - mLazyDaemon, targetUserId, mContext.getOpPackageName(), mSensorId, mCurrentUserId, - hasEnrolled, mAuthenticatorIds); - mScheduler.scheduleClientMonitor(client, new ClientMonitor.Callback() { - @Override - public void onClientFinished(@NonNull ClientMonitor<?> clientMonitor, boolean success) { - if (success) { - mCurrentUserId = targetUserId; - } - } - }); + @Override + @NonNull + public List<Face> getEnrolledFaces(int sensorId, int userId) { + return FaceUtils.getInstance().getBiometricsForUser(mContext, userId); } - void scheduleResetLockout(int userId, @NonNull byte[] hardwareAuthToken) { - mHandler.post(() -> { - if (getEnrolledFaces(userId).isEmpty()) { - Slog.w(TAG, "Ignoring lockout reset, no templates enrolled for user: " + userId); - return; - } - - scheduleUpdateActiveUserWithoutHandler(userId); - - final FaceResetLockoutClient client = new FaceResetLockoutClient(mContext, - mLazyDaemon, userId, mContext.getOpPackageName(), mSensorId, - hardwareAuthToken); - mScheduler.scheduleClientMonitor(client); - }); + @Override + @LockoutTracker.LockoutMode + public int getLockoutModeForUser(int sensorId, int userId) { + return mLockoutTracker.getLockoutModeForUser(userId); } - void scheduleSetFeature(@NonNull IBinder token, int userId, int feature, boolean enabled, - @NonNull byte[] hardwareAuthToken, @NonNull IFaceServiceReceiver receiver, - @NonNull String opPackageName) { - mHandler.post(() -> { - final List<Face> faces = getEnrolledFaces(userId); - if (faces.isEmpty()) { - Slog.w(TAG, "Ignoring setFeature, no templates enrolled for user: " + userId); - return; - } - - scheduleUpdateActiveUserWithoutHandler(userId); - - final int faceId = faces.get(0).getBiometricId(); - final FaceSetFeatureClient client = new FaceSetFeatureClient(mContext, - mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), userId, - opPackageName, mSensorId, feature, enabled, hardwareAuthToken, faceId); - mScheduler.scheduleClientMonitor(client); - }); + @Override + public long getAuthenticatorId(int sensorId, int userId) { + return mAuthenticatorIds.get(userId); } - void scheduleGetFeature(@NonNull IBinder token, int userId, int feature, - @Nullable ClientMonitorCallbackConverter listener, @NonNull String opPackageName) { - mHandler.post(() -> { - final List<Face> faces = getEnrolledFaces(userId); - if (faces.isEmpty()) { - Slog.w(TAG, "Ignoring getFeature, no templates enrolled for user: " + userId); - return; - } - - scheduleUpdateActiveUserWithoutHandler(userId); - - final int faceId = faces.get(0).getBiometricId(); - final FaceGetFeatureClient client = new FaceGetFeatureClient(mContext, mLazyDaemon, - token, listener, userId, opPackageName, mSensorId, feature, faceId); - mScheduler.scheduleClientMonitor(client, new ClientMonitor.Callback() { - @Override - public void onClientFinished( - @NonNull ClientMonitor<?> clientMonitor, boolean success) { - if (success && feature == BiometricFaceConstants.FEATURE_REQUIRE_ATTENTION) { - final int settingsValue = client.getValue() ? 1 : 0; - Slog.d(TAG, "Updating attention value for user: " + userId - + " to value: " + settingsValue); - Settings.Secure.putIntForUser(mContext.getContentResolver(), - Settings.Secure.FACE_UNLOCK_ATTENTION_REQUIRED, - settingsValue, userId); - } - } - }); - }); + @Override + public boolean isHardwareDetected(int sensorId) { + return getDaemon() != null; } /** @@ -514,8 +438,9 @@ class Face10 implements IHwBinder.DeathRecipient { * The only case of conflicting challenges is currently resetLockout --> enroll. So, the second * option seems better as it prioritizes the new operation, which is user-facing. */ - void scheduleGenerateChallenge(@NonNull IBinder token, @NonNull IFaceServiceReceiver receiver, - @NonNull String opPackageName) { + @Override + public void scheduleGenerateChallenge(int sensorId, int userId, @NonNull IBinder token, + @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName) { mHandler.post(() -> { if (mCurrentChallengeOwner != null) { final ClientMonitorCallbackConverter listener = @@ -550,18 +475,20 @@ class Face10 implements IHwBinder.DeathRecipient { }); } - void scheduleRevokeChallenge(@NonNull IBinder token, @NonNull String owner) { + @Override + public void scheduleRevokeChallenge(int sensorId, int userId, @NonNull IBinder token, + @NonNull String opPackageName, long challenge) { mHandler.post(() -> { if (mCurrentChallengeOwner != null && - !mCurrentChallengeOwner.getOwnerString().contentEquals(owner)) { - Slog.e(TAG, "scheduleRevokeChallenge, package: " + owner + !mCurrentChallengeOwner.getOwnerString().contentEquals(opPackageName)) { + Slog.e(TAG, "scheduleRevokeChallenge, package: " + opPackageName + " attempting to revoke challenge owned by: " + mCurrentChallengeOwner.getOwnerString()); return; } final FaceRevokeChallengeClient client = new FaceRevokeChallengeClient(mContext, - mLazyDaemon, token, owner, mSensorId); + mLazyDaemon, token, opPackageName, mSensorId); mScheduler.scheduleClientMonitor(client, new ClientMonitor.Callback() { @Override public void onClientFinished(@NonNull ClientMonitor<?> clientMonitor, @@ -582,13 +509,19 @@ class Face10 implements IHwBinder.DeathRecipient { final FaceGenerateChallengeClient previousChallengeOwner = mCurrentChallengeOwner.getInterruptedClient(); mCurrentChallengeOwner = null; + Slog.d(TAG, "Previous challenge owner: " + previousChallengeOwner); if (previousChallengeOwner != null) { - try { - previousChallengeOwner.getListener() - .onChallengeInterruptFinished(mSensorId); - } catch (RemoteException e) { - Slog.e(TAG, "Unable to notify interrupt finished", e); + final ClientMonitorCallbackConverter listener = + previousChallengeOwner.getListener(); + if (listener == null) { + Slog.w(TAG, "Listener is null"); + } else { + try { + listener.onChallengeInterruptFinished(mSensorId); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to notify interrupt finished", e); + } } } } @@ -596,9 +529,11 @@ class Face10 implements IHwBinder.DeathRecipient { }); } - void scheduleEnroll(@NonNull IBinder token, @NonNull byte[] hardwareAuthToken, int userId, - @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName, - @NonNull int[] disabledFeatures, @Nullable NativeHandle surfaceHandle) { + @Override + public void scheduleEnroll(int sensorId, @NonNull IBinder token, + @NonNull byte[] hardwareAuthToken, int userId, @NonNull IFaceServiceReceiver receiver, + @NonNull String opPackageName, @NonNull int[] disabledFeatures, + @Nullable NativeHandle surfaceHandle) { mHandler.post(() -> { scheduleUpdateActiveUserWithoutHandler(userId); @@ -623,15 +558,18 @@ class Face10 implements IHwBinder.DeathRecipient { }); } - void cancelEnrollment(@NonNull IBinder token) { + @Override + public void cancelEnrollment(int sensorId, @NonNull IBinder token) { mHandler.post(() -> { mScheduler.cancelEnrollment(token); }); } - void scheduleAuthenticate(@NonNull IBinder token, long operationId, int userId, int cookie, - @NonNull ClientMonitorCallbackConverter receiver, @NonNull String opPackageName, - boolean restricted, int statsClient) { + @Override + public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, + int userId, int cookie, @NonNull ClientMonitorCallbackConverter receiver, + @NonNull String opPackageName, boolean restricted, int statsClient, + boolean isKeyguard) { mHandler.post(() -> { scheduleUpdateActiveUserWithoutHandler(userId); @@ -644,19 +582,15 @@ class Face10 implements IHwBinder.DeathRecipient { }); } - void startPreparedClient(int cookie) { - mHandler.post(() -> { - mScheduler.startPreparedClient(cookie); - }); - } - - void cancelAuthentication(@NonNull IBinder token) { + @Override + public void cancelAuthentication(int sensorId, @NonNull IBinder token) { mHandler.post(() -> { mScheduler.cancelAuthentication(token); }); } - void scheduleRemove(@NonNull IBinder token, int faceId, int userId, + @Override + public void scheduleRemove(int sensorId, @NonNull IBinder token, int faceId, int userId, @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName) { mHandler.post(() -> { scheduleUpdateActiveUserWithoutHandler(userId); @@ -668,11 +602,82 @@ class Face10 implements IHwBinder.DeathRecipient { }); } + + @Override + public void scheduleResetLockout(int sensorId, int userId, @NonNull byte[] hardwareAuthToken) { + mHandler.post(() -> { + if (getEnrolledFaces(sensorId, userId).isEmpty()) { + Slog.w(TAG, "Ignoring lockout reset, no templates enrolled for user: " + userId); + return; + } + + scheduleUpdateActiveUserWithoutHandler(userId); + + final FaceResetLockoutClient client = new FaceResetLockoutClient(mContext, + mLazyDaemon, userId, mContext.getOpPackageName(), mSensorId, + hardwareAuthToken); + mScheduler.scheduleClientMonitor(client); + }); + } + + @Override + public void scheduleSetFeature(int sensorId, @NonNull IBinder token, int userId, int feature, + boolean enabled, @NonNull byte[] hardwareAuthToken, + @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName) { + mHandler.post(() -> { + final List<Face> faces = getEnrolledFaces(sensorId, userId); + if (faces.isEmpty()) { + Slog.w(TAG, "Ignoring setFeature, no templates enrolled for user: " + userId); + return; + } + + scheduleUpdateActiveUserWithoutHandler(userId); + + final int faceId = faces.get(0).getBiometricId(); + final FaceSetFeatureClient client = new FaceSetFeatureClient(mContext, + mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), userId, + opPackageName, mSensorId, feature, enabled, hardwareAuthToken, faceId); + mScheduler.scheduleClientMonitor(client); + }); + } + + @Override + public void scheduleGetFeature(int sensorId, @NonNull IBinder token, int userId, int feature, + @Nullable ClientMonitorCallbackConverter listener, @NonNull String opPackageName) { + mHandler.post(() -> { + final List<Face> faces = getEnrolledFaces(sensorId, userId); + if (faces.isEmpty()) { + Slog.w(TAG, "Ignoring getFeature, no templates enrolled for user: " + userId); + return; + } + + scheduleUpdateActiveUserWithoutHandler(userId); + + final int faceId = faces.get(0).getBiometricId(); + final FaceGetFeatureClient client = new FaceGetFeatureClient(mContext, mLazyDaemon, + token, listener, userId, opPackageName, mSensorId, feature, faceId); + mScheduler.scheduleClientMonitor(client, new ClientMonitor.Callback() { + @Override + public void onClientFinished( + @NonNull ClientMonitor<?> clientMonitor, boolean success) { + if (success && feature == BiometricFaceConstants.FEATURE_REQUIRE_ATTENTION) { + final int settingsValue = client.getValue() ? 1 : 0; + Slog.d(TAG, "Updating attention value for user: " + userId + + " to value: " + settingsValue); + Settings.Secure.putIntForUser(mContext.getContentResolver(), + Settings.Secure.FACE_UNLOCK_ATTENTION_REQUIRED, + settingsValue, userId); + } + } + }); + }); + } + private void scheduleInternalCleanup(int userId) { mHandler.post(() -> { scheduleUpdateActiveUserWithoutHandler(userId); - final List<Face> enrolledList = getEnrolledFaces(userId); + final List<Face> enrolledList = getEnrolledFaces(mSensorId, userId); final FaceInternalCleanupClient client = new FaceInternalCleanupClient(mContext, mLazyDaemon, userId, mContext.getOpPackageName(), mSensorId, enrolledList, FaceUtils.getInstance(), mAuthenticatorIds); @@ -680,25 +685,28 @@ class Face10 implements IHwBinder.DeathRecipient { }); } - boolean isHardwareDetected() { - final IBiometricsFace daemon = getDaemon(); - return daemon != null; + @Override + public void scheduleInternalCleanup(int sensorId, int userId) { + scheduleInternalCleanup(userId); } - @NonNull - FaceSensorPropertiesInternal getFaceSensorProperties() { - return mFaceSensorProperties; + @Override + public void startPreparedClient(int sensorId, int cookie) { + mHandler.post(() -> { + mScheduler.startPreparedClient(cookie); + }); } - List<Face> getEnrolledFaces(int userId) { - return FaceUtils.getInstance().getBiometricsForUser(mContext, userId); + @Override + public void dumpProtoState(int sensorId, ProtoOutputStream proto) { } - long getAuthenticatorId(int userId) { - return mAuthenticatorIds.get(userId); + @Override + public void dumpProtoMetrics(int sensorId, FileDescriptor fd) { } - public void dump(@NonNull PrintWriter pw) { + @Override + public void dumpInternal(int sensorId, PrintWriter pw) { PerformanceTracker performanceTracker = PerformanceTracker.getInstanceForSensorId(mSensorId); @@ -733,9 +741,51 @@ class Face10 implements IHwBinder.DeathRecipient { pw.println(dump); pw.println("HAL deaths since last reboot: " + performanceTracker.getHALDeathCount()); + mScheduler.dump(pw); mUsageStats.print(pw); } + private void scheduleLoadAuthenticatorIds() { + // Note that this can be performed on the scheduler (as opposed to being done immediately + // when the HAL is (re)loaded, since + // 1) If this is truly the first time it's being performed (e.g. system has just started), + // this will be run very early and way before any applications need to generate keys. + // 2) If this is being performed to refresh the authenticatorIds (e.g. HAL crashed and has + // just been reloaded), the framework already has a cache of the authenticatorIds. This + // is safe because authenticatorIds only change when A) new template has been enrolled, + // or B) all templates are removed. + mHandler.post(() -> { + for (UserInfo user : UserManager.get(mContext).getAliveUsers()) { + final int targetUserId = user.id; + if (!mAuthenticatorIds.containsKey(targetUserId)) { + scheduleUpdateActiveUserWithoutHandler(targetUserId); + } + } + }); + } + + /** + * Schedules the {@link FaceUpdateActiveUserClient} without posting the work onto the + * handler. Many/most APIs are user-specific. However, the HAL requires explicit "setActiveUser" + * invocation prior to authenticate/enroll/etc. Thus, internally we usually want to schedule + * this operation on the same lambda/runnable as those operations so that the ordering is + * correct. + */ + private void scheduleUpdateActiveUserWithoutHandler(int targetUserId) { + final boolean hasEnrolled = !getEnrolledFaces(mSensorId, targetUserId).isEmpty(); + final FaceUpdateActiveUserClient client = new FaceUpdateActiveUserClient(mContext, + mLazyDaemon, targetUserId, mContext.getOpPackageName(), mSensorId, mCurrentUserId, + hasEnrolled, mAuthenticatorIds); + mScheduler.scheduleClientMonitor(client, new ClientMonitor.Callback() { + @Override + public void onClientFinished(@NonNull ClientMonitor<?> clientMonitor, boolean success) { + if (success) { + mCurrentUserId = targetUserId; + } + } + }); + } + public void dumpHal(@NonNull FileDescriptor fd, @NonNull String[] args) { // WARNING: CDD restricts image data from leaving TEE unencrypted on // production devices: 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 83f10c8e658b..a298e19e4b02 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 @@ -16,10 +16,12 @@ package com.android.server.biometrics.sensors.face; +import static android.Manifest.permission.INTERACT_ACROSS_USERS; import static android.Manifest.permission.MANAGE_BIOMETRIC; import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL; import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricsProtoEnums; @@ -32,7 +34,10 @@ import android.hardware.face.IFaceServiceReceiver; import android.os.Binder; import android.os.IBinder; import android.os.NativeHandle; +import android.os.UserHandle; +import android.util.Pair; import android.util.Slog; +import android.util.proto.ProtoOutputStream; import android.view.Surface; import com.android.internal.util.DumpUtils; @@ -46,7 +51,7 @@ import com.android.server.biometrics.sensors.LockoutTracker; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.Arrays; +import java.util.Collections; import java.util.List; /** @@ -58,9 +63,65 @@ public class FaceService extends SystemService { protected static final String TAG = "FaceService"; - private Face10 mFace10; private final LockoutResetDispatcher mLockoutResetDispatcher; private final LockPatternUtils mLockPatternUtils; + @NonNull + private List<ServiceProvider> mServiceProviders; + + @Nullable + private ServiceProvider getProviderForSensor(int sensorId) { + for (ServiceProvider provider : mServiceProviders) { + if (provider.containsSensor(sensorId)) { + return provider; + } + } + return null; + } + + /** + * For devices with only a single provider, returns that provider. If no providers, or multiple + * providers exist, returns null. + */ + @Nullable + private Pair<Integer, ServiceProvider> getSingleProvider() { + final List<FaceSensorPropertiesInternal> properties = getSensorProperties(); + if (properties.size() != 1) { + Slog.e(TAG, "Multiple sensors found: " + properties.size()); + return null; + } + + // Theoretically we can just return the first provider, but maybe this is easier to + // understand. + final int sensorId = properties.get(0).sensorId; + for (ServiceProvider provider : mServiceProviders) { + if (provider.containsSensor(sensorId)) { + return new Pair<>(sensorId, provider); + } + } + + Slog.e(TAG, "Single sensor, but provider not found"); + return null; + } + + @NonNull + private List<FaceSensorPropertiesInternal> getSensorProperties() { + final List<FaceSensorPropertiesInternal> properties = new ArrayList<>(); + for (ServiceProvider provider : mServiceProviders) { + properties.addAll(provider.getSensorProperties()); + } + return properties; + } + + @NonNull + private List<Face> getEnrolledFaces(int userId, String opPackageName) { + final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + if (provider == null) { + Slog.w(TAG, "Null provider for getEnrolledFaces, caller: " + opPackageName); + return Collections.emptyList(); + } + + return provider.second.getEnrolledFaces(provider.first, userId); + } /** * Receives the incoming binder calls from FaceManager. @@ -69,13 +130,10 @@ public class FaceService extends SystemService { @Override // Binder call public List<FaceSensorPropertiesInternal> getSensorPropertiesInternal( String opPackageName) { - Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); - - final List<FaceSensorPropertiesInternal> properties = new ArrayList<>(); + Utils.checkPermission(getContext(), MANAGE_BIOMETRIC); - if (mFace10 != null) { - properties.add(mFace10.getFaceSensorProperties()); - } + final List<FaceSensorPropertiesInternal> properties = + FaceService.this.getSensorProperties(); Slog.d(TAG, "Retrieved sensor properties for: " + opPackageName + ", sensors: " + properties.size()); @@ -83,27 +141,31 @@ public class FaceService extends SystemService { } @Override // Binder call - public void generateChallenge(IBinder token, int sensorId, IFaceServiceReceiver receiver, - String opPackageName) { + public void generateChallenge(IBinder token, int sensorId, int userId, + IFaceServiceReceiver receiver, String opPackageName) { Utils.checkPermission(getContext(), MANAGE_BIOMETRIC); - if (sensorId == mFace10.getFaceSensorProperties().sensorId) { - mFace10.scheduleGenerateChallenge(token, receiver, opPackageName); + + final ServiceProvider provider = getProviderForSensor(sensorId); + if (provider == null) { + Slog.w(TAG, "No matching sensor for generateChallenge, sensorId: " + sensorId); return; } - Slog.w(TAG, "No matching sensor for generateChallenge, sensorId: " + sensorId); + provider.scheduleGenerateChallenge(sensorId, userId, token, receiver, opPackageName); } @Override // Binder call - public void revokeChallenge(IBinder token, int sensorId, String owner) { + public void revokeChallenge(IBinder token, int sensorId, int userId, String opPackageName, + long challenge) { Utils.checkPermission(getContext(), MANAGE_BIOMETRIC); - if (sensorId == mFace10.getFaceSensorProperties().sensorId) { - mFace10.scheduleRevokeChallenge(token, owner); + final ServiceProvider provider = getProviderForSensor(sensorId); + if (provider == null) { + Slog.w(TAG, "No matching sensor for revokeChallenge, sensorId: " + sensorId); return; } - Slog.w(TAG, "No matching sensor for revokeChallenge, sensorId: " + sensorId); + provider.scheduleRevokeChallenge(sensorId, userId, token, opPackageName, challenge); } @Override // Binder call @@ -111,8 +173,16 @@ public class FaceService extends SystemService { final IFaceServiceReceiver receiver, final String opPackageName, final int[] disabledFeatures, Surface surface) { Utils.checkPermission(getContext(), MANAGE_BIOMETRIC); - mFace10.scheduleEnroll(token, hardwareAuthToken, userId, receiver, opPackageName, - disabledFeatures, convertSurfaceToNativeHandle(surface)); + + final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + if (provider == null) { + Slog.w(TAG, "Null provider for enroll"); + return; + } + + provider.second.scheduleEnroll(provider.first, token, hardwareAuthToken, userId, + receiver, opPackageName, disabledFeatures, + convertSurfaceToNativeHandle(surface)); } @Override // Binder call @@ -126,7 +196,14 @@ public class FaceService extends SystemService { @Override // Binder call public void cancelEnrollment(final IBinder token) { Utils.checkPermission(getContext(), MANAGE_BIOMETRIC); - mFace10.cancelEnrollment(token); + + final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + if (provider == null) { + Slog.w(TAG, "Null provider for cancelEnrollment"); + return; + } + + provider.second.cancelEnrollment(provider.first, token); } @Override // Binder call @@ -141,9 +218,21 @@ public class FaceService extends SystemService { final int statsClient = Utils.isKeyguard(getContext(), opPackageName) ? BiometricsProtoEnums.CLIENT_KEYGUARD : BiometricsProtoEnums.CLIENT_UNKNOWN; - mFace10.scheduleAuthenticate(token, operationId, userId, 0 /* cookie */, + + // Keyguard check must be done on the caller's binder identity, since it also checks + // permission. + final boolean isKeyguard = Utils.isKeyguard(getContext(), opPackageName); + + final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + if (provider == null) { + Slog.w(TAG, "Null provider for authenticate"); + return; + } + + provider.second.scheduleAuthenticate(provider.first, token, operationId, userId, + 0 /* cookie */, new ClientMonitorCallbackConverter(receiver), opPackageName, restricted, - statsClient); + statsClient, isKeyguard); } @Override // Binder call @@ -172,22 +261,42 @@ public class FaceService extends SystemService { int callingUserId) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); + final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + if (provider == null) { + Slog.w(TAG, "Null provider for prepareForAuthentication"); + return; + } + final boolean restricted = true; // BiometricPrompt is always restricted - mFace10.scheduleAuthenticate(token, operationId, userId, cookie, - new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, - restricted, BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT); + provider.second.scheduleAuthenticate(provider.first, token, operationId, userId, cookie, + new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, restricted, + BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, false /* isKeyguard */); } @Override // Binder call public void startPreparedClient(int cookie) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); - mFace10.startPreparedClient(cookie); + + final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + if (provider == null) { + Slog.w(TAG, "Null provider for startPreparedClient"); + return; + } + + provider.second.startPreparedClient(provider.first, cookie); } @Override // Binder call public void cancelAuthentication(final IBinder token, final String opPackageName) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); - mFace10.cancelAuthentication(token); + + final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + if (provider == null) { + Slog.w(TAG, "Null provider for cancelAuthentication"); + return; + } + + provider.second.cancelAuthentication(provider.first, token); } @Override // Binder call @@ -206,14 +315,29 @@ public class FaceService extends SystemService { public void cancelAuthenticationFromService(final IBinder token, final String opPackageName, int callingUid, int callingPid, int callingUserId) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); - mFace10.cancelAuthentication(token); + + final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + if (provider == null) { + Slog.w(TAG, "Null provider for cancelAuthenticationFromService"); + return; + } + + provider.second.cancelAuthentication(provider.first, token); } @Override // Binder call public void remove(final IBinder token, final int faceId, final int userId, final IFaceServiceReceiver receiver, final String opPackageName) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); - mFace10.scheduleRemove(token, faceId, userId, receiver, opPackageName); + + final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + if (provider == null) { + Slog.w(TAG, "Null provider for remove"); + return; + } + + provider.second.scheduleRemove(provider.first, token, faceId, userId, receiver, + opPackageName); } @Override @@ -231,10 +355,28 @@ public class FaceService extends SystemService { final long ident = Binder.clearCallingIdentity(); try { - if (args.length > 1 && "--hal".equals(args[0])) { - mFace10.dumpHal(fd, Arrays.copyOfRange(args, 1, args.length, args.getClass())); + if (args.length > 1 && "--proto".equals(args[0]) && "--state".equals(args[1])) { + final ProtoOutputStream proto = new ProtoOutputStream(fd); + for (ServiceProvider provider : mServiceProviders) { + for (FaceSensorPropertiesInternal props : provider.getSensorProperties()) { + provider.dumpProtoState(props.sensorId, proto); + } + } + proto.flush(); + } else if (args.length > 0 && "--proto".equals(args[0])) { + for (ServiceProvider provider : mServiceProviders) { + for (FaceSensorPropertiesInternal props : provider.getSensorProperties()) { + provider.dumpProtoMetrics(props.sensorId, fd); + } + } } else { - mFace10.dump(pw); + for (ServiceProvider provider : mServiceProviders) { + for (FaceSensorPropertiesInternal props : provider.getSensorProperties()) { + pw.println("Dumping for sensorId: " + props.sensorId + + ", provider: " + provider.getClass().getSimpleName()); + provider.dumpInternal(props.sensorId, pw); + } + } } } finally { Binder.restoreCallingIdentity(ident); @@ -244,13 +386,15 @@ public class FaceService extends SystemService { @Override // Binder call public boolean isHardwareDetected(String opPackageName) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); - if (mFace10 == null) { - Slog.wtf(TAG, "No HAL, caller: " + opPackageName); - return false; - } + final long token = Binder.clearCallingIdentity(); try { - return mFace10.isHardwareDetected(); + final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + if (provider == null) { + Slog.w(TAG, "Null provider for isHardwareDetected, caller: " + opPackageName); + return false; + } + return provider.second.isHardwareDetected(provider.first); } finally { Binder.restoreCallingIdentity(token); } @@ -259,25 +403,50 @@ public class FaceService extends SystemService { @Override // Binder call public List<Face> getEnrolledFaces(int userId, String opPackageName) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); - return mFace10.getEnrolledFaces(userId); + + if (userId != UserHandle.getCallingUserId()) { + Utils.checkPermission(getContext(), INTERACT_ACROSS_USERS); + } + + return FaceService.this.getEnrolledFaces(userId, opPackageName); } @Override // Binder call public boolean hasEnrolledFaces(int userId, String opPackageName) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); - return !mFace10.getEnrolledFaces(userId).isEmpty(); + + if (userId != UserHandle.getCallingUserId()) { + Utils.checkPermission(getContext(), INTERACT_ACROSS_USERS); + } + + return !FaceService.this.getEnrolledFaces(userId, opPackageName).isEmpty(); } - @Override - public @LockoutTracker.LockoutMode int getLockoutModeForUser(int userId) { + @Override // Binder call + @LockoutTracker.LockoutMode + public int getLockoutModeForUser(int userId) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); - return mFace10.getLockoutModeForUser(userId); + + final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + if (provider == null) { + Slog.w(TAG, "Null provider for getLockoutModeForUser"); + return LockoutTracker.LOCKOUT_NONE; + } + + return provider.second.getLockoutModeForUser(provider.first, userId); } @Override // Binder call public long getAuthenticatorId(int userId) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); - return mFace10.getAuthenticatorId(userId); + + final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + if (provider == null) { + Slog.w(TAG, "Null provider for getAuthenticatorId"); + return 0; + } + + return provider.second.getAuthenticatorId(provider.first, userId); } @Override // Binder call @@ -285,12 +454,13 @@ public class FaceService extends SystemService { String opPackageName) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); - if (sensorId == mFace10.getFaceSensorProperties().sensorId) { - mFace10.scheduleResetLockout(userId, hardwareAuthToken); + final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + if (provider == null) { + Slog.w(TAG, "Null provider for resetLockout, caller: " + opPackageName); return; } - Slog.w(TAG, "No matching sensor for resetLockout, sensorId: " + sensorId); + provider.second.scheduleResetLockout(provider.first, userId, hardwareAuthToken); } @Override @@ -298,15 +468,29 @@ public class FaceService extends SystemService { final byte[] hardwareAuthToken, IFaceServiceReceiver receiver, final String opPackageName) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); - mFace10.scheduleSetFeature(token, userId, feature, enabled, hardwareAuthToken, receiver, - opPackageName); + + final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + if (provider == null) { + Slog.w(TAG, "Null provider for setFeature"); + return; + } + + provider.second.scheduleSetFeature(provider.first, token, userId, feature, enabled, + hardwareAuthToken, receiver, opPackageName); } @Override public void getFeature(final IBinder token, int userId, int feature, IFaceServiceReceiver receiver, final String opPackageName) { Utils.checkPermission(getContext(), MANAGE_BIOMETRIC); - mFace10.scheduleGetFeature(token, userId, feature, + + final Pair<Integer, ServiceProvider> provider = getSingleProvider(); + if (provider == null) { + Slog.w(TAG, "Null provider for getFeature"); + return; + } + + provider.second.scheduleGetFeature(provider.first, token, userId, feature, new ClientMonitorCallbackConverter(receiver), opPackageName); } @@ -314,7 +498,8 @@ public class FaceService extends SystemService { public void initializeConfiguration(int sensorId, @BiometricManager.Authenticators.Types int strength) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); - mFace10 = new Face10(getContext(), sensorId, strength, mLockoutResetDispatcher); + mServiceProviders.add( + new Face10(getContext(), sensorId, strength, mLockoutResetDispatcher)); } } @@ -322,6 +507,7 @@ public class FaceService extends SystemService { super(context); mLockoutResetDispatcher = new LockoutResetDispatcher(context); mLockPatternUtils = new LockPatternUtils(context); + mServiceProviders = new ArrayList<>(); } @Override 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 new file mode 100644 index 000000000000..e3fb750a1e14 --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java @@ -0,0 +1,113 @@ +/* + * 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.biometrics.sensors.face; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.hardware.face.Face; +import android.hardware.face.FaceSensorPropertiesInternal; +import android.hardware.face.IFaceServiceReceiver; +import android.os.IBinder; +import android.os.NativeHandle; +import android.util.proto.ProtoOutputStream; + +import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; +import com.android.server.biometrics.sensors.LockoutTracker; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.List; + +/** + * Superset of features across all the face HAL interfaces that are available to the framework. This + * is more or less mapped to the public and private APIs that {@link FaceManager} provides, and + * is used at the system server layer to provide easy mapping between requests and providers. + * + * Note that providers support both single-sensor and multi-sensor HALs. In either case, + * {@link FaceService} must ensure that providers are only requested to perform operations + * on sensors that they own. + * + * For methods other than {@link #containsSensor(int)}, the caller must ensure that the sensorId + * is supported by the provider. For example: + * if (serviceProvider.containsSensor(sensorId)) { + * serviceProvider.operation(sensorId, ...); + * } + * + * For operations that are supported by some providers but not others, clients are required + * to check (e.g. via {@link FaceManager#getSensorPropertiesInternal()}) that the code path isn't + * taken. ServiceProviders will provide a no-op for unsupported operations to fail safely. + */ +public interface ServiceProvider { + /** + * Checks if the specified sensor is owned by this provider. + */ + boolean containsSensor(int sensorId); + + @NonNull + List<FaceSensorPropertiesInternal> getSensorProperties(); + + @NonNull + List<Face> getEnrolledFaces(int sensorId, int userId); + + @LockoutTracker.LockoutMode + int getLockoutModeForUser(int sensorId, int userId); + + long getAuthenticatorId(int sensorId, int userId); + + boolean isHardwareDetected(int sensorId); + + void scheduleGenerateChallenge(int sensorId, int userId, @NonNull IBinder token, + @NonNull IFaceServiceReceiver receiver, String opPackageName); + + void scheduleRevokeChallenge(int sensorId, int userId, @NonNull IBinder token, + @NonNull String opPackageName, long challenge); + + void scheduleEnroll(int sensorId, @NonNull IBinder token, @NonNull byte[] hardwareAuthToken, + int userId, @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName, + @NonNull int[] disabledFeatures, @Nullable NativeHandle surfaceHandle); + + void cancelEnrollment(int sensorId, @NonNull IBinder token); + + void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId, + int cookie, @NonNull ClientMonitorCallbackConverter callback, + @NonNull String opPackageName, boolean restricted, int statsClient, boolean isKeyguard); + + + void cancelAuthentication(int sensorId, @NonNull IBinder token); + + void scheduleRemove(int sensorId, @NonNull IBinder token, int faceId, int userId, + @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName); + + void scheduleResetLockout(int sensorId, int userId, @NonNull byte[] hardwareAuthToken); + + void scheduleSetFeature(int sensorId, @NonNull IBinder token, int userId, int feature, + boolean enabled, @NonNull byte[] hardwareAuthToken, + @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName); + + void scheduleGetFeature(int sensorId, @NonNull IBinder token, int userId, int feature, + @NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName); + + void startPreparedClient(int sensorId, int cookie); + + void scheduleInternalCleanup(int sensorId, int userId); + + void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto); + + void dumpProtoMetrics(int sensorId, @NonNull FileDescriptor fd); + + void dumpInternal(int sensorId, @NonNull PrintWriter pw); +} 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 c88247f59871..265ba0545395 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 @@ -469,6 +469,27 @@ public class FingerprintService extends SystemService { } @Override // Binder call + public boolean hasEnrolledTemplatesForAnySensor(int userId, + @NonNull List<FingerprintSensorPropertiesInternal> sensors, + @NonNull String opPackageName) { + Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); + + for (FingerprintSensorPropertiesInternal prop : sensors) { + final ServiceProvider provider = getProviderForSensor(prop.sensorId); + if (provider == null) { + Slog.w(TAG, "Null provider for sensorId: " + prop.sensorId + + ", caller: " + opPackageName); + continue; + } + + if (!provider.getEnrolledFingerprints(prop.sensorId, userId).isEmpty()) { + return true; + } + } + return false; + } + + @Override // Binder call public @LockoutTracker.LockoutMode int getLockoutModeForUser(int userId) { Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL); 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 a806e3f61bc8..8c766d682bf7 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 @@ -646,8 +646,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider @Override public boolean isHardwareDetected(int sensorId) { - final IBiometricsFingerprint daemon = getDaemon(); - return daemon != null; + return getDaemon() != null; } @Override diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java index 88867fcfc46f..a4ae9c87c694 100644 --- a/services/core/java/com/android/server/camera/CameraServiceProxy.java +++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java @@ -15,6 +15,7 @@ */ package com.android.server.camera; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.BroadcastReceiver; @@ -39,6 +40,7 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; +import com.android.internal.annotations.GuardedBy; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.FrameworkStatsLog; @@ -48,6 +50,8 @@ import com.android.server.SystemService; import com.android.server.SystemService.TargetUser; import com.android.server.wm.WindowManagerInternal; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -79,10 +83,19 @@ public class CameraServiceProxy extends SystemService // Handler message codes private static final int MSG_SWITCH_USER = 1; + private static final int MSG_NOTIFY_DEVICE_STATE = 2; private static final int RETRY_DELAY_TIME = 20; //ms private static final int RETRY_TIMES = 60; + @IntDef(flag = true, prefix = { "DEVICE_STATE_" }, value = { + ICameraService.DEVICE_STATE_BACK_COVERED, + ICameraService.DEVICE_STATE_FRONT_COVERED, + ICameraService.DEVICE_STATE_FOLDED + }) + @Retention(RetentionPolicy.SOURCE) + @interface DeviceStateFlags {} + // Maximum entries to keep in usage history before dumping out private static final int MAX_USAGE_HISTORY = 100; @@ -94,6 +107,15 @@ public class CameraServiceProxy extends SystemService private final Object mLock = new Object(); private Set<Integer> mEnabledCameraUsers; private int mLastUser; + // The current set of device state flags. May be different from mLastReportedDeviceState if the + // native camera service has not been notified of the change. + @GuardedBy("mLock") + @DeviceStateFlags + private int mDeviceState; + // The most recent device state flags reported to the native camera server. + @GuardedBy("mLock") + @DeviceStateFlags + private int mLastReportedDeviceState; private ICameraService mCameraServiceRaw; @@ -185,6 +207,7 @@ public class CameraServiceProxy extends SystemService return; } notifySwitchWithRetries(RETRY_TIMES); + notifyDeviceStateWithRetries(RETRY_TIMES); } @Override @@ -218,12 +241,55 @@ public class CameraServiceProxy extends SystemService mLogWriterService.allowCoreThreadTimeOut(true); } + /** + * Sets the device state bits set within {@code deviceStateFlags} leaving all other bits the + * same. + * <p> + * Calling requires permission {@link android.Manifest.permission#CAMERA_SEND_SYSTEM_EVENTS}. + * + * @param deviceStateFlags a bitmask of the device state bits that should be set. + * + * @see #clearDeviceStateFlags(int) + */ + public void setDeviceStateFlags(@DeviceStateFlags int deviceStateFlags) { + synchronized (mLock) { + mHandler.removeMessages(MSG_NOTIFY_DEVICE_STATE); + mDeviceState |= deviceStateFlags; + if (mDeviceState != mLastReportedDeviceState) { + notifyDeviceStateWithRetriesLocked(RETRY_TIMES); + } + } + } + + /** + * Clears the device state bits set within {@code deviceStateFlags} leaving all other bits the + * same. + * <p> + * Calling requires permission {@link android.Manifest.permission#CAMERA_SEND_SYSTEM_EVENTS}. + * + * @param deviceStateFlags a bitmask of the device state bits that should be cleared. + * + * @see #setDeviceStateFlags(int) + */ + public void clearDeviceStateFlags(@DeviceStateFlags int deviceStateFlags) { + synchronized (mLock) { + mHandler.removeMessages(MSG_NOTIFY_DEVICE_STATE); + mDeviceState &= ~deviceStateFlags; + if (mDeviceState != mLastReportedDeviceState) { + notifyDeviceStateWithRetriesLocked(RETRY_TIMES); + } + } + } + @Override public boolean handleMessage(Message msg) { switch(msg.what) { case MSG_SWITCH_USER: { notifySwitchWithRetries(msg.arg1); } break; + case MSG_NOTIFY_DEVICE_STATE: { + notifyDeviceStateWithRetries(msg.arg1); + } break; default: { Slog.e(TAG, "CameraServiceProxy error, invalid message: " + msg.what); } break; @@ -386,6 +452,25 @@ public class CameraServiceProxy extends SystemService } } + @Nullable + private ICameraService getCameraServiceRawLocked() { + if (mCameraServiceRaw == null) { + IBinder cameraServiceBinder = getBinderService(CAMERA_SERVICE_BINDER_NAME); + if (cameraServiceBinder == null) { + return null; + } + try { + cameraServiceBinder.linkToDeath(this, /*flags*/ 0); + } catch (RemoteException e) { + Slog.w(TAG, "Could not link to death of native camera service"); + return null; + } + + mCameraServiceRaw = ICameraService.Stub.asInterface(cameraServiceBinder); + } + return mCameraServiceRaw; + } + private void switchUserLocked(int userHandle) { Set<Integer> currentUserHandles = getEnabledUserHandles(userHandle); mLastUser = userHandle; @@ -431,20 +516,10 @@ public class CameraServiceProxy extends SystemService private boolean notifyCameraserverLocked(int eventType, Set<Integer> updatedUserHandles) { // Forward the user switch event to the native camera service running in the cameraserver // process. - if (mCameraServiceRaw == null) { - IBinder cameraServiceBinder = getBinderService(CAMERA_SERVICE_BINDER_NAME); - if (cameraServiceBinder == null) { - Slog.w(TAG, "Could not notify cameraserver, camera service not available."); - return false; // Camera service not active, cannot evict user clients. - } - try { - cameraServiceBinder.linkToDeath(this, /*flags*/ 0); - } catch (RemoteException e) { - Slog.w(TAG, "Could not link to death of native camera service"); - return false; - } - - mCameraServiceRaw = ICameraService.Stub.asInterface(cameraServiceBinder); + ICameraService cameraService = getCameraServiceRawLocked(); + if (cameraService == null) { + Slog.w(TAG, "Could not notify cameraserver, camera service not available."); + return false; } try { @@ -457,6 +532,43 @@ public class CameraServiceProxy extends SystemService return true; } + private void notifyDeviceStateWithRetries(int retries) { + synchronized (mLock) { + notifyDeviceStateWithRetriesLocked(retries); + } + } + + private void notifyDeviceStateWithRetriesLocked(int retries) { + if (notifyDeviceStateChangeLocked(mDeviceState)) { + return; + } + if (retries <= 0) { + return; + } + Slog.i(TAG, "Could not notify camera service of device state change, retrying..."); + mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_NOTIFY_DEVICE_STATE, retries - 1, + 0, null), RETRY_DELAY_TIME); + } + + private boolean notifyDeviceStateChangeLocked(@DeviceStateFlags int deviceState) { + // Forward the state to the native camera service running in the cameraserver process. + ICameraService cameraService = getCameraServiceRawLocked(); + if (cameraService == null) { + Slog.w(TAG, "Could not notify cameraserver, camera service not available."); + return false; + } + + try { + mCameraServiceRaw.notifyDeviceStateChange(deviceState); + } catch (RemoteException e) { + Slog.w(TAG, "Could not notify cameraserver, remote exception: " + e); + // Not much we can do if camera service is dead. + return false; + } + mLastReportedDeviceState = deviceState; + return true; + } + private void updateActivityCount(String cameraId, int newCameraState, int facing, String clientName, int apiLevel) { synchronized(mLock) { diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java index bc3bff1b966f..ff3193182501 100644 --- a/services/core/java/com/android/server/compat/CompatChange.java +++ b/services/core/java/com/android/server/compat/CompatChange.java @@ -18,7 +18,7 @@ package com.android.server.compat; import android.annotation.Nullable; import android.compat.annotation.ChangeId; -import android.compat.annotation.EnabledAfter; +import android.compat.annotation.EnabledSince; import android.content.pm.ApplicationInfo; import com.android.internal.compat.CompatibilityChangeInfo; @@ -43,8 +43,8 @@ public final class CompatChange extends CompatibilityChangeInfo { * A change ID to be used only in the CTS test for this SystemApi */ @ChangeId - @EnabledAfter(targetSdkVersion = 1234) // Needs to be > test APK targetSdkVersion. - private static final long CTS_SYSTEM_API_CHANGEID = 149391281; // This is a bug id. + @EnabledSince(targetSdkVersion = 1235) // Needs to be > test APK targetSdkVersion. + static final long CTS_SYSTEM_API_CHANGEID = 149391281; // This is a bug id. /** * Callback listener for when compat changes are updated for a package. diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java index e4f52f1fc927..77d5411f5f7f 100644 --- a/services/core/java/com/android/server/compat/PlatformCompat.java +++ b/services/core/java/com/android/server/compat/PlatformCompat.java @@ -381,6 +381,9 @@ public class PlatformCompat extends IPlatformCompat.Stub { if (change.getLoggingOnly()) { return false; } + if (change.getId() == CompatChange.CTS_SYSTEM_API_CHANGEID) { + return false; + } if (change.getEnableSinceTargetSdk() > 0) { if (change.getEnableSinceTargetSdk() < sMinTargetSdk || change.getEnableSinceTargetSdk() > sMaxTargetSdk) { diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 6a3e7b7a0ecd..b10cd12cdba5 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -227,8 +227,35 @@ public final class DisplayManagerService extends SystemService { private final CopyOnWriteArrayList<DisplayTransactionListener> mDisplayTransactionListeners = new CopyOnWriteArrayList<DisplayTransactionListener>(); - // Display power controller. - private DisplayPowerController mDisplayPowerController; + /** 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() { + @Override + public void requestDisplayState(int displayId, int state, float brightness) { + // The order of operations is important for legacy reasons. + if (state == Display.STATE_OFF) { + requestGlobalDisplayStateInternal(state, brightness); + } + + mDisplayPowerCallbacks.onDisplayStateChange(state); + + if (state != Display.STATE_OFF) { + requestGlobalDisplayStateInternal(state, brightness); + } + } + }; + + /** + * Used to inform {@link com.android.server.power.PowerManagerService} of changes to display + * state. + */ + private DisplayManagerInternal.DisplayPowerCallbacks mDisplayPowerCallbacks; + + /** The {@link Handler} used by all {@link DisplayPowerController}s. */ + private Handler mPowerHandler; // The overall display state, independent of changes that might influence one // display or another in particular. @@ -419,14 +446,16 @@ public final class DisplayManagerService extends SystemService { final int newUserId = to.getUserIdentifier(); final int userSerial = getUserManager().getUserSerialNumber(newUserId); synchronized (mSyncRoot) { + final DisplayPowerController displayPowerController = mDisplayPowerControllers.get( + Display.DEFAULT_DISPLAY); if (mCurrentUserId != newUserId) { mCurrentUserId = newUserId; BrightnessConfiguration config = mPersistentDataStore.getBrightnessConfiguration(userSerial); - mDisplayPowerController.setBrightnessConfiguration(config); + displayPowerController.setBrightnessConfiguration(config); handleSettingsChange(); } - mDisplayPowerController.onSwitchUser(newUserId); + displayPowerController.onSwitchUser(newUserId); } } @@ -957,6 +986,7 @@ public final class DisplayManagerService extends SystemService { recordStableDisplayStatsIfNeededLocked(display); recordTopInsetLocked(display); } + addDisplayPowerControllerLocked(displayId); DisplayManagerGlobal.invalidateLocalDisplayInfoCaches(); @@ -990,6 +1020,7 @@ public final class DisplayManagerService extends SystemService { private void handleLogicalDisplayRemovedLocked(@NonNull LogicalDisplay display) { final int displayId = display.getDisplayIdLocked(); + mDisplayPowerControllers.delete(displayId); DisplayManagerGlobal.invalidateLocalDisplayInfoCaches(); sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED); scheduleTraversalLocked(false); @@ -1111,7 +1142,7 @@ public final class DisplayManagerService extends SystemService { mPersistentDataStore.saveIfNeeded(); } if (userId == mCurrentUserId) { - mDisplayPowerController.setBrightnessConfiguration(c); + mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY).setBrightnessConfiguration(c); } } } @@ -1143,7 +1174,8 @@ public final class DisplayManagerService extends SystemService { final int userSerial = getUserManager().getUserSerialNumber(mCurrentUserId); BrightnessConfiguration config = mPersistentDataStore.getBrightnessConfiguration(userSerial); - mDisplayPowerController.setBrightnessConfiguration(config); + mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY).setBrightnessConfiguration( + config); } } @@ -1350,25 +1382,31 @@ public final class DisplayManagerService extends SystemService { } void setAutoBrightnessLoggingEnabled(boolean enabled) { - if (mDisplayPowerController != null) { - synchronized (mSyncRoot) { - mDisplayPowerController.setAutoBrightnessLoggingEnabled(enabled); + synchronized (mSyncRoot) { + final DisplayPowerController displayPowerController = mDisplayPowerControllers.get( + Display.DEFAULT_DISPLAY); + if (displayPowerController != null) { + displayPowerController.setAutoBrightnessLoggingEnabled(enabled); } } } void setDisplayWhiteBalanceLoggingEnabled(boolean enabled) { - if (mDisplayPowerController != null) { - synchronized (mSyncRoot) { - mDisplayPowerController.setDisplayWhiteBalanceLoggingEnabled(enabled); + synchronized (mSyncRoot) { + final DisplayPowerController displayPowerController = mDisplayPowerControllers.get( + Display.DEFAULT_DISPLAY); + if (displayPowerController != null) { + displayPowerController.setDisplayWhiteBalanceLoggingEnabled(enabled); } } } void setAmbientColorTemperatureOverride(float cct) { - if (mDisplayPowerController != null) { - synchronized (mSyncRoot) { - mDisplayPowerController.setAmbientColorTemperatureOverride(cct); + synchronized (mSyncRoot) { + final DisplayPowerController displayPowerController = mDisplayPowerControllers.get( + Display.DEFAULT_DISPLAY); + if (displayPowerController != null) { + displayPowerController.setAmbientColorTemperatureOverride(cct); } } } @@ -1594,8 +1632,11 @@ public final class DisplayManagerService extends SystemService { + ", mWifiDisplayScanRequested=" + callback.mWifiDisplayScanRequested); } - if (mDisplayPowerController != null) { - mDisplayPowerController.dump(pw); + final int displayPowerControllerCount = mDisplayPowerControllers.size(); + pw.println(); + pw.println("Display Power Controllers: size=" + displayPowerControllerCount); + for (int i = 0; i < displayPowerControllerCount; i++) { + mDisplayPowerControllers.valueAt(i).dump(pw); } pw.println(); @@ -1668,6 +1709,22 @@ public final class DisplayManagerService extends SystemService { } } + private void initializeDisplayPowerControllersLocked() { + mLogicalDisplayMapper.forEachLocked((logicalDisplay) -> addDisplayPowerControllerLocked( + logicalDisplay.getDisplayIdLocked())); + } + + private void addDisplayPowerControllerLocked(int displayId) { + if (mPowerHandler == null) { + // initPowerManagement has not yet been called. + return; + } + final DisplayPowerController displayPowerController = new DisplayPowerController( + mContext, mDisplayPowerCallbacks, mPowerHandler, mSensorManager, + mDisplayBlanker, displayId); + mDisplayPowerControllers.append(displayId, displayPowerController); + } + private final class DisplayManagerHandler extends Handler { public DisplayManagerHandler(Looper looper) { super(looper, null, true /*async*/); @@ -2187,7 +2244,8 @@ public final class DisplayManagerService extends SystemService { final long token = Binder.clearCallingIdentity(); try { synchronized (mSyncRoot) { - return mDisplayPowerController.getBrightnessEvents(userId, hasUsageStats); + return mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY) + .getBrightnessEvents(userId, hasUsageStats); } } finally { Binder.restoreCallingIdentity(token); @@ -2204,7 +2262,8 @@ public final class DisplayManagerService extends SystemService { final long token = Binder.clearCallingIdentity(); try { synchronized (mSyncRoot) { - return mDisplayPowerController.getAmbientBrightnessStats(userId); + return mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY) + .getAmbientBrightnessStats(userId); } } finally { Binder.restoreCallingIdentity(token); @@ -2252,7 +2311,8 @@ public final class DisplayManagerService extends SystemService { BrightnessConfiguration config = mPersistentDataStore.getBrightnessConfiguration(userSerial); if (config == null) { - config = mDisplayPowerController.getDefaultBrightnessConfiguration(); + config = mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY) + .getDefaultBrightnessConfiguration(); } return config; } @@ -2269,7 +2329,8 @@ public final class DisplayManagerService extends SystemService { final long token = Binder.clearCallingIdentity(); try { synchronized (mSyncRoot) { - return mDisplayPowerController.getDefaultBrightnessConfiguration(); + return mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY) + .getDefaultBrightnessConfiguration(); } } finally { Binder.restoreCallingIdentity(token); @@ -2292,7 +2353,8 @@ public final class DisplayManagerService extends SystemService { final long token = Binder.clearCallingIdentity(); try { synchronized (mSyncRoot) { - mDisplayPowerController.setTemporaryBrightness(brightness); + mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY) + .setTemporaryBrightness(brightness); } } finally { Binder.restoreCallingIdentity(token); @@ -2307,7 +2369,8 @@ public final class DisplayManagerService extends SystemService { final long token = Binder.clearCallingIdentity(); try { synchronized (mSyncRoot) { - mDisplayPowerController.setTemporaryAutoBrightnessAdjustment(adjustment); + mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY) + .setTemporaryAutoBrightnessAdjustment(adjustment); } } finally { Binder.restoreCallingIdentity(token); @@ -2428,25 +2491,10 @@ public final class DisplayManagerService extends SystemService { public void initPowerManagement(final DisplayPowerCallbacks callbacks, Handler handler, SensorManager sensorManager) { synchronized (mSyncRoot) { - DisplayBlanker blanker = new DisplayBlanker() { - @Override - public void requestDisplayState(int displayId, int state, float brightness) { - // The order of operations is important for legacy reasons. - if (state == Display.STATE_OFF) { - requestGlobalDisplayStateInternal(state, brightness); - } - - callbacks.onDisplayStateChange(state); - - if (state != Display.STATE_OFF) { - requestGlobalDisplayStateInternal(state, brightness); - } - } - }; - mDisplayPowerController = new DisplayPowerController( - mContext, callbacks, handler, sensorManager, blanker, - Display.DEFAULT_DISPLAY); + mDisplayPowerCallbacks = callbacks; mSensorManager = sensorManager; + mPowerHandler = handler; + initializeDisplayPowerControllersLocked(); } mHandler.sendEmptyMessage(MSG_LOAD_BRIGHTNESS_CONFIGURATION); @@ -2456,14 +2504,16 @@ public final class DisplayManagerService extends SystemService { public boolean requestPowerState(DisplayPowerRequest request, boolean waitForNegativeProximity) { synchronized (mSyncRoot) { - return mDisplayPowerController.requestPowerState(request, waitForNegativeProximity); + return mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY) + .requestPowerState(request, waitForNegativeProximity); } } @Override public boolean isProximitySensorAvailable() { synchronized (mSyncRoot) { - return mDisplayPowerController.isProximitySensorAvailable(); + return mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY) + .isProximitySensorAvailable(); } } @@ -2552,7 +2602,8 @@ public final class DisplayManagerService extends SystemService { @Override public void persistBrightnessTrackerState() { synchronized (mSyncRoot) { - mDisplayPowerController.persistBrightnessTrackerState(); + mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY) + .persistBrightnessTrackerState(); } } @@ -2584,7 +2635,8 @@ public final class DisplayManagerService extends SystemService { @Override public void ignoreProximitySensorUntilChanged() { - mDisplayPowerController.ignoreProximitySensorUntilChanged(); + mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY) + .ignoreProximitySensorUntilChanged(); } } diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 0211876c864d..309271c6addc 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -1815,6 +1815,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call public void dump(final PrintWriter pw) { synchronized (mLock) { pw.println(); + pw.println("Display Power Controller:"); + pw.println(" mDisplayId=" + mDisplayId); + + pw.println(); pw.println("Display Power Controller Locked State:"); pw.println(" mDisplayReadyLocked=" + mDisplayReadyLocked); pw.println(" mPendingRequestLocked=" + mPendingRequestLocked); diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 16a4b7250598..b532fa13feca 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -234,7 +234,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub static final int MSG_SET_ACTIVE = 3020; static final int MSG_SET_INTERACTIVE = 3030; static final int MSG_REPORT_FULLSCREEN_MODE = 3045; - static final int MSG_REPORT_PRE_RENDERED = 3060; static final int MSG_APPLY_IME_VISIBILITY = 3070; static final int MSG_HARD_KEYBOARD_SWITCH_CHANGED = 4000; @@ -317,8 +316,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private static final class DebugFlags { static final DebugFlag FLAG_OPTIMIZE_START_INPUT = new DebugFlag("debug.optimize_startinput", false); - static final DebugFlag FLAG_PRE_RENDER_IME_VIEWS = - new DebugFlag("persist.pre_render_ime_views", false); } @UserIdInt @@ -448,10 +445,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub final ClientDeathRecipient clientDeathRecipient; boolean sessionRequested; - // Determines if IMEs should be pre-rendered. - // DebugFlag can be flipped anytime. This flag is kept per-client to maintain behavior - // through the life of the current client. - boolean shouldPreRenderIme; SessionState curSession; @Override @@ -3440,14 +3433,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return InputBindResult.USER_SWITCHING; } - // Main feature flag that overrides other conditions and forces IME preRendering. - if (DEBUG) { - Slog.v(TAG, "IME PreRendering main flag: " - + DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.value() + ", LowRam: " + mIsLowRam); - } - // pre-rendering not supported on low-ram devices. - cs.shouldPreRenderIme = DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.value() && !mIsLowRam; - final boolean sameWindowFocused = mCurFocusedWindow == windowToken; final boolean isTextEditor = (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0; final boolean startInputByWinGainedFocus = @@ -4141,19 +4126,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } @BinderThread - private void reportPreRendered(IBinder token, EditorInfo info) { - synchronized (mMethodMap) { - if (!calledWithValidTokenLocked(token)) { - return; - } - if (mCurClient != null && mCurClient.client != null) { - executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO( - MSG_REPORT_PRE_RENDERED, info, mCurClient)); - } - } - } - - @BinderThread private void applyImeVisibility(IBinder token, IBinder windowToken, boolean setVisible) { synchronized (mMethodMap) { if (!calledWithValidTokenLocked(token)) { @@ -4430,7 +4402,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub try { setEnabledSessionInMainThread(session); session.method.startInput(startInputToken, inputContext, missingMethods, - editorInfo, restarting, session.client.shouldPreRenderIme); + editorInfo, restarting); } catch (RemoteException e) { } args.recycle(); @@ -4488,20 +4460,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } return true; } - case MSG_REPORT_PRE_RENDERED: { - args = (SomeArgs) msg.obj; - final EditorInfo info = (EditorInfo) args.arg1; - final ClientState clientState = (ClientState) args.arg2; - try { - clientState.client.reportPreRendered(info); - } catch (RemoteException e) { - Slog.w(TAG, "Got RemoteException sending " - + "reportPreRendered(" + info + ") notification to pid=" - + clientState.pid + " uid=" + clientState.uid); - } - args.recycle(); - return true; - } case MSG_APPLY_IME_VISIBILITY: { final boolean setVisible = msg.arg1 != 0; final ClientState clientState = (ClientState) msg.obj; @@ -5347,7 +5305,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @ShellCommandResult private int refreshDebugProperties() { DebugFlags.FLAG_OPTIMIZE_START_INPUT.refresh(); - DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.refresh(); return ShellCommandResult.SUCCESS; } @@ -5822,12 +5779,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @BinderThread @Override - public void reportPreRendered(EditorInfo info) { - mImms.reportPreRendered(mToken, info); - } - - @BinderThread - @Override public void applyImeVisibility(IBinder windowToken, boolean setVisible) { mImms.applyImeVisibility(mToken, windowToken, setVisible); } diff --git a/services/core/java/com/android/server/location/ContextHubServiceUtil.java b/services/core/java/com/android/server/location/ContextHubServiceUtil.java index 76cd9ceaf7c4..9145eca9ad6f 100644 --- a/services/core/java/com/android/server/location/ContextHubServiceUtil.java +++ b/services/core/java/com/android/server/location/ContextHubServiceUtil.java @@ -30,12 +30,16 @@ import android.hardware.location.ContextHubTransaction; import android.hardware.location.NanoAppBinary; import android.hardware.location.NanoAppMessage; import android.hardware.location.NanoAppState; +import android.os.Binder; +import android.os.Build; import android.util.Log; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Set; /** * A class encapsulating helper functions used by the ContextHubService class @@ -45,6 +49,9 @@ import java.util.List; private static final String HARDWARE_PERMISSION = Manifest.permission.LOCATION_HARDWARE; private static final String CONTEXT_HUB_PERMISSION = Manifest.permission.ACCESS_CONTEXT_HUB; + // A set of packages that have already been warned regarding the ACCESS_CONTEXT_HUB permission. + private static final Set<String> PERMISSION_WARNED_PACKAGES = new HashSet<String>(); + /** * Creates a ConcurrentHashMap of the Context Hub ID to the ContextHubInfo object given an * ArrayList of HIDL ContextHub objects. @@ -95,6 +102,7 @@ import java.util.List; /** * Creates a primitive integer array given a Collection<Integer>. + * * @param collection the collection to iterate * @return the primitive integer array */ @@ -200,10 +208,25 @@ import java.util.List; */ /* package */ static void checkPermissions(Context context) { - if (context.checkCallingPermission(HARDWARE_PERMISSION) != PERMISSION_GRANTED - && context.checkCallingPermission(CONTEXT_HUB_PERMISSION) != PERMISSION_GRANTED) { + boolean hasLocationHardwarePermission = (context.checkCallingPermission(HARDWARE_PERMISSION) + == PERMISSION_GRANTED); + boolean hasAccessContextHubPermission = (context.checkCallingPermission( + CONTEXT_HUB_PERMISSION) == PERMISSION_GRANTED); + + if (!hasLocationHardwarePermission && !hasAccessContextHubPermission) { throw new SecurityException( - "LOCATION_HARDWARE or ACCESS_CONTEXT_HUB permission required to use Context Hub"); + "LOCATION_HARDWARE or ACCESS_CONTEXT_HUB permission required to use Context " + + "Hub"); + } + + if (!hasAccessContextHubPermission && !Build.IS_USER) { + String pkgName = context.getPackageManager().getNameForUid(Binder.getCallingUid()); + if (!PERMISSION_WARNED_PACKAGES.contains(pkgName)) { + Log.w(TAG, pkgName + + ": please use the ACCESS_CONTEXT_HUB permission rather than " + + "LOCATION_HARDWARE (will be removed for Context Hub APIs in T)"); + PERMISSION_WARNED_PACKAGES.add(pkgName); + } } } diff --git a/services/core/java/com/android/server/location/LocationProviderManager.java b/services/core/java/com/android/server/location/LocationProviderManager.java index f25c65192066..f8d1195be7fd 100644 --- a/services/core/java/com/android/server/location/LocationProviderManager.java +++ b/services/core/java/com/android/server/location/LocationProviderManager.java @@ -38,6 +38,7 @@ import static com.android.server.location.LocationPermissions.PERMISSION_NONE; import static java.lang.Math.max; import static java.lang.Math.min; +import android.annotation.IntDef; import android.annotation.Nullable; import android.app.AlarmManager.OnAlarmListener; import android.app.PendingIntent; @@ -107,6 +108,8 @@ import com.android.server.location.util.UserInfoHelper; import com.android.server.location.util.UserInfoHelper.UserListener; import java.io.FileDescriptor; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -142,6 +145,14 @@ class LocationProviderManager extends // will just be scheduled immediately private static final long MIN_REQUEST_DELAY_MS = 30 * 1000; + @Retention(RetentionPolicy.SOURCE) + @IntDef({STATE_STARTED, STATE_STOPPING, STATE_STOPPED}) + private @interface State {} + + private static final int STATE_STARTED = 0; + private static final int STATE_STOPPING = 1; + private static final int STATE_STOPPED = 2; + protected interface LocationTransport { void deliverOnLocationChanged(Location location, @Nullable Runnable onCompleteCallback) @@ -1082,7 +1093,7 @@ class LocationProviderManager extends protected final Context mContext; @GuardedBy("mLock") - private boolean mStarted; + private @State int mState; // maps of user id to value @GuardedBy("mLock") @@ -1148,7 +1159,7 @@ class LocationProviderManager extends mContext = context; mName = Objects.requireNonNull(name); mPassiveManager = passiveManager; - mStarted = false; + mState = STATE_STOPPED; mEnabled = new SparseBooleanArray(2); mLastLocations = new SparseArray<>(2); @@ -1180,7 +1191,8 @@ class LocationProviderManager extends public void startManager() { synchronized (mLock) { - mStarted = true; + Preconditions.checkState(mState == STATE_STOPPED); + mState = STATE_STARTED; mUserHelper.addListener(mUserChangedListener); mSettingsHelper.addOnLocationEnabledChangedListener(mLocationEnabledChangedListener); @@ -1197,6 +1209,9 @@ class LocationProviderManager extends public void stopManager() { synchronized (mLock) { + Preconditions.checkState(mState == STATE_STARTED); + mState = STATE_STOPPING; + final long identity = Binder.clearCallingIdentity(); try { onEnabledChanged(UserHandle.USER_ALL); @@ -1205,11 +1220,19 @@ class LocationProviderManager extends Binder.restoreCallingIdentity(identity); } + setRealProvider(null); + setMockProvider(null); + mUserHelper.removeListener(mUserChangedListener); mSettingsHelper.removeOnLocationEnabledChangedListener(mLocationEnabledChangedListener); + // if external entities are registering listeners it's their responsibility to + // unregister them before stopManager() is called Preconditions.checkState(mEnabledListeners.isEmpty()); - mStarted = false; + + mEnabled.clear(); + mLastLocations.clear(); + mState = STATE_STOPPED; } } @@ -1252,21 +1275,21 @@ class LocationProviderManager extends public void addEnabledListener(ProviderEnabledListener listener) { synchronized (mLock) { - Preconditions.checkState(mStarted); + Preconditions.checkState(mState != STATE_STOPPED); mEnabledListeners.add(listener); } } public void removeEnabledListener(ProviderEnabledListener listener) { synchronized (mLock) { - Preconditions.checkState(mStarted); + Preconditions.checkState(mState != STATE_STOPPED); mEnabledListeners.remove(listener); } } - public void setRealProvider(AbstractLocationProvider provider) { + public void setRealProvider(@Nullable AbstractLocationProvider provider) { synchronized (mLock) { - Preconditions.checkState(mStarted); + Preconditions.checkState(mState != STATE_STOPPED); final long identity = Binder.clearCallingIdentity(); try { @@ -1279,7 +1302,7 @@ class LocationProviderManager extends public void setMockProvider(@Nullable MockProvider provider) { synchronized (mLock) { - Preconditions.checkState(mStarted); + Preconditions.checkState(mState != STATE_STOPPED); mLocationEventLog.logProviderMocked(mName, provider != null); @@ -1408,7 +1431,7 @@ class LocationProviderManager extends Location location; synchronized (mLock) { - Preconditions.checkState(mStarted); + Preconditions.checkState(mState != STATE_STOPPED); LastLocation lastLocation = mLastLocations.get(userId); if (lastLocation == null) { location = null; @@ -1430,7 +1453,7 @@ class LocationProviderManager extends public void injectLastLocation(Location location, int userId) { synchronized (mLock) { - Preconditions.checkState(mStarted); + Preconditions.checkState(mState != STATE_STOPPED); if (getLastLocationUnsafe(userId, PERMISSION_FINE, false, Long.MAX_VALUE) == null) { setLastLocation(location, userId); } @@ -1478,7 +1501,7 @@ class LocationProviderManager extends permissionLevel); synchronized (mLock) { - Preconditions.checkState(mStarted); + Preconditions.checkState(mState != STATE_STOPPED); final long ident = Binder.clearCallingIdentity(); try { putRegistration(callback.asBinder(), registration); @@ -1520,7 +1543,7 @@ class LocationProviderManager extends permissionLevel); synchronized (mLock) { - Preconditions.checkState(mStarted); + Preconditions.checkState(mState != STATE_STOPPED); final long ident = Binder.clearCallingIdentity(); try { putRegistration(listener.asBinder(), registration); @@ -1539,7 +1562,7 @@ class LocationProviderManager extends permissionLevel); synchronized (mLock) { - Preconditions.checkState(mStarted); + Preconditions.checkState(mState != STATE_STOPPED); final long identity = Binder.clearCallingIdentity(); try { putRegistration(pendingIntent, registration); @@ -1551,7 +1574,7 @@ class LocationProviderManager extends public void unregisterLocationRequest(ILocationListener listener) { synchronized (mLock) { - Preconditions.checkState(mStarted); + Preconditions.checkState(mState != STATE_STOPPED); final long identity = Binder.clearCallingIdentity(); try { removeRegistration(listener.asBinder()); @@ -1563,7 +1586,7 @@ class LocationProviderManager extends public void unregisterLocationRequest(PendingIntent pendingIntent) { synchronized (mLock) { - Preconditions.checkState(mStarted); + Preconditions.checkState(mState != STATE_STOPPED); final long identity = Binder.clearCallingIdentity(); try { removeRegistration(pendingIntent); @@ -1890,6 +1913,10 @@ class LocationProviderManager extends private void onUserChanged(int userId, int change) { synchronized (mLock) { + if (mState == STATE_STOPPED) { + return; + } + switch (change) { case UserListener.CURRENT_USER_CHANGED: updateRegistrations( @@ -1907,6 +1934,10 @@ class LocationProviderManager extends private void onLocationEnabledChanged(int userId) { synchronized (mLock) { + if (mState == STATE_STOPPED) { + return; + } + onEnabledChanged(userId); } } @@ -2105,7 +2136,7 @@ class LocationProviderManager extends Preconditions.checkArgument(userId >= 0); - boolean enabled = mStarted + boolean enabled = mState == STATE_STARTED && mProvider.getState().allowed && mSettingsHelper.isLocationEnabled(userId); diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java index e25e605cf7d2..0c1e91d9bf24 100644 --- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java @@ -583,8 +583,10 @@ public class GnssLocationProvider extends AbstractLocationProvider implements mDownloadPsdsWakeLock.setReferenceCounted(true); mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); - mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0); - mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0); + mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), + PendingIntent.FLAG_IMMUTABLE); + mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), + PendingIntent.FLAG_IMMUTABLE); // App ops service to keep track of who is accessing the GPS mAppOps = mContext.getSystemService(AppOpsManager.class); diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index b679c0fbab83..dd338655732b 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -1563,7 +1563,7 @@ public class LauncherAppsService extends SystemService { continue; } try { - listener.onPackageProgressChanged(mUser, mPackageName, progress); + listener.onPackageLoadingProgressChanged(mUser, mPackageName, progress); } catch (RemoteException re) { Slog.d(TAG, "Callback failed ", re); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index cdd347beba0a..b3f49ade35c8 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -2737,7 +2737,7 @@ public class PackageManagerService extends IPackageManager.Stub context, lock, installer, installLock, new PackageAbiHelperImpl(), backgroundHandler, (i, pm) -> new ComponentResolver(i.getUserManagerService(), pm.mPmInternal, lock), - (i, pm) -> PermissionManagerService.create(context, lock), + (i, pm) -> PermissionManagerService.create(context), (i, pm) -> new UserManagerService(context, pm, new UserDataPreparer(installer, installLock, context, onlyCore), lock), @@ -19606,7 +19606,7 @@ public class PackageManagerService extends IPackageManager.Stub ps.setUninstallReason(UNINSTALL_REASON_UNKNOWN, userId); } - mSettings.writeRuntimePermissionsForUserLPr(userId, false); + writeRuntimePermissionsForUserLPrTEMP(userId, false); } // Regardless of writeSettings we need to ensure that this restriction // state propagation is persisted @@ -25752,7 +25752,7 @@ public class PackageManagerService extends IPackageManager.Stub public void writePermissionSettings(int[] userIds, boolean async) { synchronized (mLock) { for (int userId : userIds) { - mSettings.writeRuntimePermissionsForUserLPr(userId, !async); + writeRuntimePermissionsForUserLPrTEMP(userId, !async); } } } @@ -26401,6 +26401,17 @@ public class PackageManagerService extends IPackageManager.Stub mSettings.writeLPr(); } + /** + * Temporary method that wraps mSettings.writeRuntimePermissionsForUserLPr() and calls + * mPermissionManager.writeLegacyPermissionStateTEMP() beforehand. + * + * TODO(zhanghai): This should be removed once we finish migration of permission storage. + */ + private void writeRuntimePermissionsForUserLPrTEMP(@UserIdInt int userId, boolean async) { + mPermissionManager.writeLegacyPermissionStateTEMP(); + mSettings.writeRuntimePermissionsForUserLPr(userId, async); + } + @Override public IBinder getHoldLockToken() { if (!Build.IS_DEBUGGABLE) { diff --git a/services/core/java/com/android/server/pm/permission/Permission.java b/services/core/java/com/android/server/pm/permission/Permission.java index c121e6b4a763..4e8ddac88529 100644 --- a/services/core/java/com/android/server/pm/permission/Permission.java +++ b/services/core/java/com/android/server/pm/permission/Permission.java @@ -378,28 +378,33 @@ public final class Permission { } } + public static boolean isOverridingSystemPermission(@Nullable Permission permission, + @NonNull PermissionInfo permissionInfo, + @NonNull PackageManagerInternal packageManagerInternal) { + if (permission == null || Objects.equals(permission.mPermissionInfo.packageName, + permissionInfo.packageName)) { + return false; + } + if (!permission.mReconciled) { + return false; + } + final AndroidPackage currentPackage = packageManagerInternal.getPackage( + permission.mPermissionInfo.packageName); + if (currentPackage == null) { + return false; + } + return currentPackage.isSystem(); + } + @NonNull - static Permission createOrUpdate(PackageManagerInternal packageManagerInternal, - @Nullable Permission permission, @NonNull PermissionInfo permissionInfo, - @NonNull AndroidPackage pkg, @NonNull Collection<Permission> permissionTrees, + public static Permission createOrUpdate(@Nullable Permission permission, + @NonNull PermissionInfo permissionInfo, @NonNull AndroidPackage pkg, + @NonNull Collection<Permission> permissionTrees, boolean isOverridingSystemPermission, boolean chatty) { // Allow system apps to redefine non-system permissions boolean ownerChanged = false; if (permission != null && !Objects.equals(permission.mPermissionInfo.packageName, permissionInfo.packageName)) { - final boolean currentOwnerIsSystem; - if (!permission.mReconciled) { - currentOwnerIsSystem = false; - } else { - AndroidPackage currentPackage = packageManagerInternal.getPackage( - permission.mPermissionInfo.packageName); - if (currentPackage == null) { - currentOwnerIsSystem = false; - } else { - currentOwnerIsSystem = currentPackage.isSystem(); - } - } - if (pkg.isSystem()) { if (permission.mType == Permission.TYPE_CONFIG && !permission.mReconciled) { // It's a built-in permission and no owner, take ownership now @@ -407,11 +412,10 @@ public final class Permission { permission.mPermissionInfo = permissionInfo; permission.mReconciled = true; permission.mUid = pkg.getUid(); - } else if (!currentOwnerIsSystem) { - String msg = "New decl " + pkg + " of permission " + } else if (!isOverridingSystemPermission) { + Slog.w(TAG, "New decl " + pkg + " of permission " + permissionInfo.name + " is system; overriding " - + permission.mPermissionInfo.packageName; - PackageManagerService.reportSettingsProblem(Log.WARN, msg); + + permission.mPermissionInfo.packageName); ownerChanged = true; permission = null; } 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 6d987aee8995..84f98239a39c 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -208,7 +208,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } /** Lock to protect internal data access */ - private final Object mLock; + private final Object mLock = new Object(); /** Internal connection to the package manager */ private final PackageManagerInternal mPackageManagerInt; @@ -224,6 +224,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { private PermissionControllerManager mPermissionControllerManager; /** Map of OneTimePermissionUserManagers keyed by userId */ + @GuardedBy("mLock") + @NonNull private final SparseArray<OneTimePermissionUserManager> mOneTimePermissionUserManagers = new SparseArray<>(); @@ -252,12 +254,14 @@ public class PermissionManagerService extends IPermissionManager.Stub { /** Internal storage for permissions and related settings */ @GuardedBy("mLock") - private final PermissionRegistry mRegistry; + @NonNull + private final PermissionRegistry mRegistry = new PermissionRegistry(); /** Injector that can be used to facilitate testing. */ private final Injector mInjector; @GuardedBy("mLock") + @Nullable private ArraySet<String> mPrivappPermissionsViolations; @GuardedBy("mLock") @@ -267,13 +271,6 @@ public class PermissionManagerService extends IPermissionManager.Stub { private PermissionPolicyInternal mPermissionPolicyInternal; /** - * For each foreground/background permission the mapping: - * Background permission -> foreground permissions - */ - @GuardedBy("mLock") - private ArrayMap<String, List<String>> mBackgroundPermissions; - - /** * A permission backup might contain apps that are not installed. In this case we delay the * restoration until the app is installed. * @@ -291,7 +288,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { @GuardedBy("mLock") private CheckPermissionDelegate mCheckPermissionDelegate; - @GuardedBy("mLock") + @NonNull private final OnPermissionChangeListeners mOnPermissionChangeListeners; @GuardedBy("mLock") @@ -309,7 +306,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { // purposes. It may make sense to keep as an abstraction, but, the methods // necessary to be overridden may be different than what was initially needed // for the split. - private PermissionCallback mDefaultPermissionCallback = new PermissionCallback() { + private final PermissionCallback mDefaultPermissionCallback = new PermissionCallback() { @Override public void onGidsChanged(int appId, int userId) { mHandler.post(() -> killUid(appId, userId, KILL_APP_REASON_GIDS_CHANGED)); @@ -368,14 +365,12 @@ public class PermissionManagerService extends IPermissionManager.Stub { } }; - PermissionManagerService(Context context, - @NonNull Object externalLock) { - this(context, externalLock, new Injector(context)); + PermissionManagerService(@NonNull Context context) { + this(context, new Injector(context)); } @VisibleForTesting - PermissionManagerService(Context context, @NonNull Object externalLock, - @NonNull Injector injector) { + PermissionManagerService(@NonNull Context context, @NonNull Injector injector) { mInjector = injector; // The package info cache is the cache for package and permission information. // Disable the package info and package permission caches locally but leave the @@ -384,10 +379,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { mInjector.disablePackageNamePermissionCache(); mContext = context; - mLock = externalLock; mPackageManagerInt = LocalServices.getService(PackageManagerInternal.class); mUserManagerInt = LocalServices.getService(UserManagerInternal.class); - mRegistry = new PermissionRegistry(mLock); mAppOpsManager = context.getSystemService(AppOpsManager.class); mHandlerThread = new ServiceThread(TAG, @@ -409,10 +402,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { synchronized (mLock) { for (int i=0; i<permConfig.size(); i++) { final SystemConfig.PermissionEntry perm = permConfig.valueAt(i); - Permission bp = mRegistry.getPermissionLocked(perm.name); + Permission bp = mRegistry.getPermission(perm.name); if (bp == null) { bp = new Permission(perm.name, "android", Permission.TYPE_CONFIG); - mRegistry.addPermissionLocked(bp); + mRegistry.addPermission(bp); } if (perm.gids != null) { bp.setGids(perm.gids, perm.perUser); @@ -444,8 +437,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { * NOTE: The external lock is temporary and should be removed. This needs to be a * lock created by the permission manager itself. */ - public static PermissionManagerServiceInternal create(Context context, - @NonNull Object externalLock) { + @NonNull + public static PermissionManagerServiceInternal create(@NonNull Context context) { final PermissionManagerServiceInternal permMgrInt = LocalServices.getService(PermissionManagerServiceInternal.class); if (permMgrInt != null) { @@ -454,8 +447,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { PermissionManagerService permissionService = (PermissionManagerService) ServiceManager.getService("permissionmgr"); if (permissionService == null) { - permissionService = - new PermissionManagerService(context, externalLock); + permissionService = new PermissionManagerService(context); ServiceManager.addService("permissionmgr", permissionService); } return LocalServices.getService(PermissionManagerServiceInternal.class); @@ -484,13 +476,6 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } - @Nullable - Permission getPermission(String permName) { - synchronized (mLock) { - return mRegistry.getPermissionLocked(permName); - } - } - @Override public String[] getAppOpPermissionPackages(String permName) { return getAppOpPermissionPackagesInternal(permName, getCallingUid()); @@ -501,7 +486,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { return null; } synchronized (mLock) { - final ArraySet<String> pkgs = mRegistry.getAppOpPermissionPackagesLocked(permName); + final ArraySet<String> pkgs = mRegistry.getAppOpPermissionPackages(permName); if (pkgs == null) { return null; } @@ -519,7 +504,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } synchronized (mLock) { final List<PermissionGroupInfo> out = new ArrayList<>(); - for (ParsedPermissionGroup pg : mRegistry.getPermissionGroupsLocked()) { + for (ParsedPermissionGroup pg : mRegistry.getPermissionGroups()) { out.add(PackageInfoUtils.generatePermissionGroupInfo(pg, flags)); } return new ParceledListSlice<>(out); @@ -537,7 +522,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } synchronized (mLock) { return PackageInfoUtils.generatePermissionGroupInfo( - mRegistry.getPermissionGroupLocked(groupName), flags); + mRegistry.getPermissionGroup(groupName), flags); } } @@ -554,7 +539,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { final int targetSdkVersion = getPermissionInfoCallingTargetSdkVersion(opPackage, callingUid); synchronized (mLock) { - final Permission bp = mRegistry.getPermissionLocked(permName); + final Permission bp = mRegistry.getPermission(permName); if (bp == null) { return null; } @@ -584,11 +569,11 @@ public class PermissionManagerService extends IPermissionManager.Stub { return null; } synchronized (mLock) { - if (groupName != null && mRegistry.getPermissionGroupLocked(groupName) == null) { + if (groupName != null && mRegistry.getPermissionGroup(groupName) == null) { return null; } final ArrayList<PermissionInfo> out = new ArrayList<PermissionInfo>(10); - for (Permission bp : mRegistry.getPermissionsLocked()) { + for (Permission bp : mRegistry.getPermissions()) { if (Objects.equals(bp.getGroup(), groupName)) { out.add(bp.generatePermissionInfo(flags)); } @@ -606,24 +591,23 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (info.labelRes == 0 && info.nonLocalizedLabel == null) { throw new SecurityException("Label must be specified in permission"); } - final Permission tree = mRegistry.enforcePermissionTree(info.name, callingUid); final boolean added; final boolean changed; synchronized (mLock) { - Permission bp = mRegistry.getPermissionLocked(info.name); + final Permission tree = mRegistry.enforcePermissionTree(info.name, callingUid); + Permission bp = mRegistry.getPermission(info.name); added = bp == null; int fixedLevel = PermissionInfo.fixProtectionLevel(info.protectionLevel); if (added) { enforcePermissionCapLocked(info, tree); - bp = new Permission(info.name, tree.getPackageName(), - Permission.TYPE_DYNAMIC); + bp = new Permission(info.name, tree.getPackageName(), Permission.TYPE_DYNAMIC); } else if (!bp.isDynamic()) { throw new SecurityException("Not allowed to modify non-dynamic permission " + info.name); } changed = bp.addToTree(fixedLevel, info, tree); if (added) { - mRegistry.addPermissionLocked(bp); + mRegistry.addPermission(bp); } } if (changed) { @@ -638,9 +622,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) { throw new SecurityException("Instant applications don't have access to this method"); } - final Permission tree = mRegistry.enforcePermissionTree(permName, callingUid); synchronized (mLock) { - final Permission bp = mRegistry.getPermissionLocked(permName); + mRegistry.enforcePermissionTree(permName, callingUid); + final Permission bp = mRegistry.getPermission(permName); if (bp == null) { return; } @@ -649,9 +633,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { Slog.wtf(TAG, "Not allowed to modify non-dynamic permission " + permName); } - mRegistry.removePermissionLocked(permName); - mPackageManagerInt.writeSettings(false); + mRegistry.removePermission(permName); } + mPackageManagerInt.writeSettings(false); } @Override @@ -682,7 +666,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } synchronized (mLock) { - if (mRegistry.getPermissionLocked(permName) == null) { + if (mRegistry.getPermission(permName) == null) { return 0; } @@ -807,14 +791,16 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } - final Permission bp; + final boolean isRuntimePermission; final boolean permissionUpdated; synchronized (mLock) { - bp = mRegistry.getPermissionLocked(permName); + final Permission bp = mRegistry.getPermission(permName); if (bp == null) { throw new IllegalArgumentException("Unknown permission: " + permName); } + isRuntimePermission = bp.isRuntime(); + if (bp.isInstallerExemptIgnored()) { flagValues &= ~FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT; } @@ -833,14 +819,14 @@ public class PermissionManagerService extends IPermissionManager.Stub { permissionUpdated = uidState.updatePermissionFlags(bp, flagMask, flagValues); } - if (permissionUpdated && bp.isRuntime()) { + if (permissionUpdated && isRuntimePermission) { notifyRuntimePermissionStateChanged(packageName, userId); } if (permissionUpdated && callback != null) { // Install and runtime permissions are stored in different places, // so figure out what permission changed and persist the change. - if (!bp.isRuntime()) { - int userUid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.getUid())); + if (!isRuntimePermission) { + int userUid = UserHandle.getUid(userId, pkg.getUid()); callback.onInstallPermissionUpdatedNotifyListener(userUid); } else { callback.onPermissionUpdatedNotifyListener(new int[]{userId}, false, pkg.getUid()); @@ -962,6 +948,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { return PackageManager.PERMISSION_DENIED; } + @GuardedBy("mLock") private boolean checkSinglePermissionInternalLocked(@NonNull UidPermissionState uidState, @NonNull String permissionName, boolean isInstantApp) { if (!uidState.isPermissionGranted(permissionName)) { @@ -969,7 +956,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { } if (isInstantApp) { - return mRegistry.isPermissionInstant(permissionName); + final Permission permission = mRegistry.getPermission(permissionName); + return permission != null && permission.isInstant(); } return true; @@ -1031,6 +1019,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { return PackageManager.PERMISSION_DENIED; } + @GuardedBy("mLock") private boolean checkSingleUidPermissionInternalLocked(int uid, @NonNull String permissionName) { ArraySet<String> permissions = mSystemPermissions.get(uid); @@ -1096,9 +1085,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS, "addOnPermissionsChangeListener"); - synchronized (mLock) { - mOnPermissionChangeListeners.addListenerLocked(listener); - } + mOnPermissionChangeListeners.addListener(listener); } @Override @@ -1106,9 +1093,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (mPackageManagerInt.getInstantAppPackageName(Binder.getCallingUid()) != null) { throw new SecurityException("Instant applications don't have access to this method"); } - synchronized (mLock) { - mOnPermissionChangeListeners.removeListenerLocked(listener); - } + mOnPermissionChangeListeners.removeListener(listener); } @Override @@ -1230,21 +1215,23 @@ public class PermissionManagerService extends IPermissionManager.Stub { private boolean checkExistsAndEnforceCannotModifyImmutablyRestrictedPermission( @NonNull String permName) { + final boolean isImmutablyRestrictedPermission; synchronized (mLock) { - final Permission bp = mRegistry.getPermissionLocked(permName); + final Permission bp = mRegistry.getPermission(permName); if (bp == null) { Slog.w(TAG, "No such permissions: " + permName); return false; } - if (bp.isHardOrSoftRestricted() && bp.isImmutablyRestricted() - && mContext.checkCallingOrSelfPermission( - Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Cannot modify whitelisting of an immutably " - + "restricted permission: " + permName); - } - return true; + isImmutablyRestrictedPermission = bp.isHardOrSoftRestricted() + && bp.isImmutablyRestricted(); } + if (isImmutablyRestrictedPermission && mContext.checkCallingOrSelfPermission( + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Cannot modify whitelisting of an immutably " + + "restricted permission: " + permName); + } + return true; } @Override @@ -1472,36 +1459,33 @@ public class PermissionManagerService extends IPermissionManager.Stub { throw new IllegalArgumentException("Unknown package: " + packageName); } - final Permission bp; + final boolean isSoftRestrictedPermission; synchronized (mLock) { - bp = mRegistry.getPermissionLocked(permName); - } - if (bp == null) { - throw new IllegalArgumentException("Unknown permission: " + permName); - } - - if (!(bp.isRuntime() || bp.isDevelopment())) { - throw new SecurityException("Permission " + permName + " requested by " - + pkg.getPackageName() + " is not a changeable permission type"); + final Permission permission = mRegistry.getPermission(permName); + isSoftRestrictedPermission = permission != null && permission.isSoftRestricted(); } + final boolean mayGrantSoftRestrictedPermission = isSoftRestrictedPermission + && SoftRestrictedPermissionPolicy.forPermission(mContext, + pkg.toAppInfoWithoutState(), pkg, UserHandle.of(userId), permName) + .mayGrantPermission(); - // If a permission review is required for legacy apps we represent - // their permissions as always granted runtime ones since we need - // to keep the review required permission flag per user while an - // install permission's state is shared across all users. - if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M && bp.isRuntime()) { - return; - } + final boolean isRuntimePermission; + final boolean isDevelopmentPermission; + final boolean permissionHasGids; + synchronized (mLock) { + final Permission bp = mRegistry.getPermission(permName); + if (bp == null) { + throw new IllegalArgumentException("Unknown permission: " + permName); + } - if (bp.isSoftRestricted() && !SoftRestrictedPermissionPolicy.forPermission(mContext, - pkg.toAppInfoWithoutState(), pkg, UserHandle.of(userId), permName) - .mayGrantPermission()) { - Log.e(TAG, "Cannot grant soft restricted permission " + permName + " for package " - + packageName); - return; - } + isRuntimePermission = bp.isRuntime(); + isDevelopmentPermission = bp.isDevelopment(); + permissionHasGids = bp.hasGids(); + if (!(isRuntimePermission || isDevelopmentPermission)) { + throw new SecurityException("Permission " + permName + " requested by " + + pkg.getPackageName() + " is not a changeable permission type"); + } - synchronized (mLock) { final UidPermissionState uidState = getUidStateLocked(pkg, userId); if (uidState == null) { Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName() + " and user " @@ -1515,6 +1499,14 @@ public class PermissionManagerService extends IPermissionManager.Stub { + " has not requested permission " + permName); } + // If a permission review is required for legacy apps we represent + // their permissions as always granted runtime ones since we need + // to keep the review required permission flag per user while an + // install permission's state is shared across all users. + if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M && bp.isRuntime()) { + return; + } + final int flags = uidState.getPermissionFlags(permName); if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) { Log.e(TAG, "Cannot grant system fixed permission " @@ -1534,6 +1526,12 @@ public class PermissionManagerService extends IPermissionManager.Stub { return; } + if (bp.isSoftRestricted() && !mayGrantSoftRestrictedPermission) { + Log.e(TAG, "Cannot grant soft restricted permission " + permName + " for package " + + packageName); + return; + } + if (bp.isDevelopment()) { // Development permissions must be handled specially, since they are not // normal runtime permissions. For now they apply to all users. @@ -1559,23 +1557,23 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } - if (bp.isRuntime()) { + if (isRuntimePermission) { logPermission(MetricsEvent.ACTION_PERMISSION_GRANTED, permName, packageName); } - final int uid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.getUid())); + final int uid = UserHandle.getUid(userId, pkg.getUid()); if (callback != null) { - if (bp.isDevelopment()) { + if (isDevelopmentPermission) { callback.onInstallPermissionGranted(); } else { callback.onPermissionGranted(uid, userId); } - if (bp.hasGids()) { + if (permissionHasGids) { callback.onGidsChanged(UserHandle.getAppId(pkg.getUid()), userId); } } - if (bp.isRuntime()) { + if (isRuntimePermission) { notifyRuntimePermissionStateChanged(packageName, userId); } } @@ -1626,17 +1624,22 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) { throw new IllegalArgumentException("Unknown package: " + packageName); } - final Permission bp = mRegistry.getPermission(permName); - if (bp == null) { - throw new IllegalArgumentException("Unknown permission: " + permName); - } - - if (!(bp.isRuntime() || bp.isDevelopment())) { - throw new SecurityException("Permission " + permName + " requested by " - + pkg.getPackageName() + " is not a changeable permission type"); - } + final boolean isRuntimePermission; + final boolean isDevelopmentPermission; synchronized (mLock) { + final Permission bp = mRegistry.getPermission(permName); + if (bp == null) { + throw new IllegalArgumentException("Unknown permission: " + permName); + } + + isRuntimePermission = bp.isRuntime(); + isDevelopmentPermission = bp.isDevelopment(); + if (!(isRuntimePermission || isDevelopmentPermission)) { + throw new SecurityException("Permission " + permName + " requested by " + + pkg.getPackageName() + " is not a changeable permission type"); + } + final UidPermissionState uidState = getUidStateLocked(pkg, userId); if (uidState == null) { Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName() + " and user " @@ -1679,20 +1682,20 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } - if (bp.isRuntime()) { + if (isRuntimePermission) { logPermission(MetricsEvent.ACTION_PERMISSION_REVOKED, permName, packageName); } if (callback != null) { - if (bp.isDevelopment()) { + if (isDevelopmentPermission) { mDefaultPermissionCallback.onInstallPermissionRevoked(); } else { - callback.onPermissionRevoked(UserHandle.getUid(userId, - UserHandle.getAppId(pkg.getUid())), userId, reason); + callback.onPermissionRevoked(UserHandle.getUid(userId, pkg.getUid()), userId, + reason); } } - if (bp.isRuntime()) { + if (isRuntimePermission) { notifyRuntimePermissionStateChanged(packageName, userId); } } @@ -1807,16 +1810,18 @@ public class PermissionManagerService extends IPermissionManager.Stub { for (int i = 0; i < permissionCount; i++) { final String permName = pkg.getRequestedPermissions().get(i); - final Permission bp; + + final boolean isRuntimePermission; synchronized (mLock) { - bp = mRegistry.getPermissionLocked(permName); - } - if (bp == null) { - continue; - } + final Permission permission = mRegistry.getPermission(permName); + if (permission == null) { + continue; + } - if (bp.isRemoved()) { - continue; + if (permission.isRemoved()) { + continue; + } + isRuntimePermission = permission.isRuntime(); } // If shared user we just reset the state to which only this app contributed. @@ -1846,7 +1851,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { // permission as requiring a review as this is the initial state. final int uid = mPackageManagerInt.getPackageUid(packageName, 0, userId); final int targetSdk = mPackageManagerInt.getUidTargetSdkVersion(uid); - final int flags = (targetSdk < Build.VERSION_CODES.M && bp.isRuntime()) + final int flags = (targetSdk < Build.VERSION_CODES.M && isRuntimePermission) ? FLAG_PERMISSION_REVIEW_REQUIRED | FLAG_PERMISSION_REVOKED_COMPAT : 0; @@ -1855,7 +1860,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { false, delayingPermCallback); // Below is only runtime permission handling. - if (!bp.isRuntime()) { + if (!isRuntimePermission) { continue; } @@ -2092,13 +2097,15 @@ public class PermissionManagerService extends IPermissionManager.Stub { return false; } - Permission permission = getPermission(permName); - if (permission == null) { - return false; - } - if (permission.isHardRestricted() - && (flags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) == 0) { - return false; + synchronized (mLock) { + final Permission permission = mRegistry.getPermission(permName); + if (permission == null) { + return false; + } + if (permission.isHardRestricted() + && (flags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) == 0) { + return false; + } } final long token = Binder.clearCallingIdentity(); @@ -2177,8 +2184,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { private void restoreRuntimePermissions(@NonNull byte[] backup, @NonNull UserHandle user) { synchronized (mLock) { mHasNoDelayedPermBackup.delete(user.getIdentifier()); - mPermissionControllerManager.stageAndApplyRuntimePermissionsBackup(backup, user); } + mPermissionControllerManager.stageAndApplyRuntimePermissionsBackup(backup, user); } /** @@ -2197,18 +2204,16 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (mHasNoDelayedPermBackup.get(user.getIdentifier(), false)) { return; } - - mPermissionControllerManager.applyStagedRuntimePermissionBackup(packageName, user, - mContext.getMainExecutor(), (hasMoreBackup) -> { - if (hasMoreBackup) { - return; - } - - synchronized (mLock) { - mHasNoDelayedPermBackup.put(user.getIdentifier(), true); - } - }); } + mPermissionControllerManager.applyStagedRuntimePermissionBackup(packageName, user, + mContext.getMainExecutor(), (hasMoreBackup) -> { + if (hasMoreBackup) { + return; + } + synchronized (mLock) { + mHasNoDelayedPermBackup.put(user.getIdentifier(), true); + } + }); } private void addOnRuntimePermissionStateChangedListener(@NonNull @@ -2346,10 +2351,12 @@ public class PermissionManagerService extends IPermissionManager.Stub { final int callingUid = Binder.getCallingUid(); for (int permNum = 0; permNum < numPermissions; permNum++) { - String permName = permissionsToRevoke.get(permNum); - Permission bp = mRegistry.getPermission(permName); - if (bp == null || !bp.isRuntime()) { - continue; + final String permName = permissionsToRevoke.get(permNum); + synchronized (mLock) { + final Permission bp = mRegistry.getPermission(permName); + if (bp == null || !bp.isRuntime()) { + continue; + } } for (int userIdNum = 0; userIdNum < numUserIds; userIdNum++) { final int userId = userIds[userIdNum]; @@ -2387,7 +2394,6 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } } - bp.setDefinitionChanged(false); } } @@ -2400,13 +2406,15 @@ public class PermissionManagerService extends IPermissionManager.Stub { // Assume by default that we did not install this permission into the system. p.setFlags(p.getFlags() & ~PermissionInfo.FLAG_INSTALLED); + final PermissionInfo permissionInfo; + final Permission oldPermission; synchronized (mLock) { // Now that permission groups have a special meaning, we ignore permission // groups for legacy apps to prevent unexpected behavior. In particular, // permissions for one app being granted to someone just because they happen // to be in a group defined by another app (before this had no implications). if (pkg.getTargetSdkVersion() > Build.VERSION_CODES.LOLLIPOP_MR1) { - p.setParsedPermissionGroup(mRegistry.getPermissionGroupLocked(p.getGroup())); + p.setParsedPermissionGroup(mRegistry.getPermissionGroup(p.getGroup())); // Warn for a permission in an unknown group. if (DEBUG_PERMISSIONS && p.getGroup() != null && p.getParsedPermissionGroup() == null) { @@ -2415,27 +2423,30 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } - final PermissionInfo permissionInfo = PackageInfoUtils.generatePermissionInfo(p, + permissionInfo = PackageInfoUtils.generatePermissionInfo(p, PackageManager.GET_META_DATA); - final Permission bp; + oldPermission = p.isTree() ? mRegistry.getPermissionTree(p.getName()) + : mRegistry.getPermission(p.getName()); + } + // TODO(zhanghai): Maybe we should store whether a permission is owned by system inside + // itself. + final boolean isOverridingSystemPermission = Permission.isOverridingSystemPermission( + oldPermission, permissionInfo, mPackageManagerInt); + synchronized (mLock) { + final Permission permission = Permission.createOrUpdate(oldPermission, + permissionInfo, pkg, mRegistry.getPermissionTrees(), + isOverridingSystemPermission, chatty); if (p.isTree()) { - bp = Permission.createOrUpdate( - mPackageManagerInt, - mRegistry.getPermissionTreeLocked(p.getName()), permissionInfo, pkg, - mRegistry.getPermissionTreesLocked(), chatty); - mRegistry.addPermissionTreeLocked(bp); + mRegistry.addPermissionTree(permission); } else { - bp = Permission.createOrUpdate( - mPackageManagerInt, - mRegistry.getPermissionLocked(p.getName()), - permissionInfo, pkg, mRegistry.getPermissionTreesLocked(), chatty); - mRegistry.addPermissionLocked(bp); + mRegistry.addPermission(permission); } - if (bp.isInstalled()) { + if (permission.isInstalled()) { p.setFlags(p.getFlags() | PermissionInfo.FLAG_INSTALLED); } - if (bp.isDefinitionChanged()) { + if (permission.isDefinitionChanged()) { definitionChangedPermissions.add(p.getName()); + permission.setDefinitionChanged(false); } } } @@ -2448,11 +2459,11 @@ public class PermissionManagerService extends IPermissionManager.Stub { StringBuilder r = null; for (int i = 0; i < N; i++) { final ParsedPermissionGroup pg = pkg.getPermissionGroups().get(i); - final ParsedPermissionGroup cur = mRegistry.getPermissionGroupLocked(pg.getName()); + final ParsedPermissionGroup cur = mRegistry.getPermissionGroup(pg.getName()); final String curPackageName = (cur == null) ? null : cur.getPackageName(); final boolean isPackageUpdate = pg.getPackageName().equals(curPackageName); if (cur == null || isPackageUpdate) { - mRegistry.addPermissionGroupLocked(pg); + mRegistry.addPermissionGroup(pg); if (chatty && DEBUG_PACKAGE_SCANNING) { if (r == null) { r = new StringBuilder(256); @@ -2491,9 +2502,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { StringBuilder r = null; for (int i=0; i<N; i++) { ParsedPermission p = pkg.getPermissions().get(i); - Permission bp = mRegistry.getPermissionLocked(p.getName()); + Permission bp = mRegistry.getPermission(p.getName()); if (bp == null) { - bp = mRegistry.getPermissionTreeLocked(p.getName()); + bp = mRegistry.getPermissionTree(p.getName()); } if (bp != null && bp.isPermission(p)) { bp.setPermissionInfo(null); @@ -2508,7 +2519,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } if (p.isAppOp()) { // TODO(zhanghai): Should we just remove the entry for this permission directly? - mRegistry.removeAppOpPermissionPackageLocked(p.getName(), pkg.getPackageName()); + mRegistry.removeAppOpPermissionPackage(p.getName(), pkg.getPackageName()); } } if (r != null) { @@ -2518,9 +2529,11 @@ public class PermissionManagerService extends IPermissionManager.Stub { N = pkg.getRequestedPermissions().size(); r = null; for (int i=0; i<N; i++) { - String perm = pkg.getRequestedPermissions().get(i); - if (mRegistry.isPermissionAppOp(perm)) { - mRegistry.removeAppOpPermissionPackageLocked(perm, pkg.getPackageName()); + final String permissionName = pkg.getRequestedPermissions().get(i); + final Permission permission = mRegistry.getPermission(permissionName); + if (permission != null && permission.isAppOp()) { + mRegistry.removeAppOpPermissionPackage(permissionName, + pkg.getPackageName()); } } if (r != null) { @@ -2576,11 +2589,13 @@ public class PermissionManagerService extends IPermissionManager.Stub { @NonNull private int[] getPermissionGids(@NonNull String permissionName, @UserIdInt int userId) { - Permission permission = mRegistry.getPermission(permissionName); - if (permission == null) { - return EmptyArray.INT; + synchronized (mLock) { + Permission permission = mRegistry.getPermission(permissionName); + if (permission == null) { + return EmptyArray.INT; + } + return permission.computeGids(userId); } - return permission.computeGids(userId); } /** @@ -2629,12 +2644,14 @@ public class PermissionManagerService extends IPermissionManager.Stub { for (int i = 0; i < requestedPermissionsSize; i++) { final String permissionName = pkg.getRequestedPermissions().get(i); - final Permission permission = mRegistry.getPermission(permissionName); + final Permission permission; + synchronized (mLock) { + permission = mRegistry.getPermission(permissionName); + } if (permission == null) { continue; } - if (permission.isSignature() && shouldGrantSignaturePermission(pkg, ps, - permission)) { + if (permission.isSignature() && shouldGrantSignaturePermission(pkg, ps, permission)) { shouldGrantSignaturePermission.add(permissionName); } } @@ -2716,12 +2733,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { // the runtime ones are written only if changed. The only cases of // changed runtime permissions here are promotion of an install to // runtime and revocation of a runtime from a shared user. - synchronized (mLock) { - if (revokeUnusedSharedUserPermissionsLocked( - ps.getSharedUser().getPackages(), uidState)) { - updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId); - runtimePermissionsRevoked = true; - } + if (revokeUnusedSharedUserPermissionsLocked( + ps.getSharedUser().getPackages(), uidState)) { + updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId); + runtimePermissionsRevoked = true; } } } @@ -2825,7 +2840,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { // Keep track of app op permissions. if (bp.isAppOp()) { - mRegistry.addAppOpPermissionPackageLocked(perm, pkg.getPackageName()); + mRegistry.addAppOpPermissionPackage(perm, pkg.getPackageName()); } boolean shouldGrantNormalPermission = true; @@ -3040,6 +3055,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { * * @return The updated value of the {@code updatedUserIds} parameter */ + @GuardedBy("mLock") private @NonNull int[] revokePermissionsNoLongerImplicitLocked(@NonNull UidPermissionState ps, @NonNull AndroidPackage pkg, int userId, @NonNull int[] updatedUserIds) { String pkgName = pkg.getPackageName(); @@ -3048,7 +3064,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { for (String permission : ps.getGrantedPermissions()) { if (!pkg.getImplicitPermissions().contains(permission)) { - Permission bp = mRegistry.getPermissionLocked(permission); + Permission bp = mRegistry.getPermission(permission); if (bp != null && bp.isRuntime()) { int flags = ps.getPermissionFlags(permission); @@ -3092,6 +3108,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { * @param ps The permission state of the package * @param pkg The package requesting the permissions */ + @GuardedBy("mLock") private void inheritPermissionStateToNewImplicitPermissionLocked( @NonNull ArraySet<String> sourcePerms, @NonNull String newPerm, @NonNull UidPermissionState ps, @NonNull AndroidPackage pkg) { @@ -3122,7 +3139,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { + " for " + pkgName); } - ps.grantPermission(mRegistry.getPermissionLocked(newPerm)); + ps.grantPermission(mRegistry.getPermission(newPerm)); } // Add permission flags @@ -3163,6 +3180,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { * * @return List of users for which the permission state has been changed */ + @GuardedBy("mLock") private @NonNull int[] setInitialGrantForNewImplicitPermissionsLocked( @NonNull UidPermissionState origPs, @NonNull UidPermissionState ps, @NonNull AndroidPackage pkg, @NonNull ArraySet<String> newImplicitPermissions, @@ -3197,7 +3215,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { ArraySet<String> sourcePerms = newToSplitPerms.get(newPerm); if (sourcePerms != null) { - Permission bp = mRegistry.getPermissionLocked(newPerm); + Permission bp = mRegistry.getPermission(newPerm); if (bp.isRuntime()) { if (!newPerm.equals(Manifest.permission.ACTIVITY_RECOGNITION)) { @@ -3212,7 +3230,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { for (int sourcePermNum = 0; sourcePermNum < sourcePerms.size(); sourcePermNum++) { final String sourcePerm = sourcePerms.valueAt(sourcePermNum); - Permission sourceBp = mRegistry.getPermissionLocked(sourcePerm); + Permission sourceBp = mRegistry.getPermission(sourcePerm); if (!sourceBp.isRuntime()) { inheritsFromInstallPerm = true; break; @@ -3554,11 +3572,13 @@ public class PermissionManagerService extends IPermissionManager.Stub { + packageName + " (" + pkg.getPath() + ") not in privapp-permissions whitelist"); if (RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE) { - if (mPrivappPermissionsViolations == null) { - mPrivappPermissionsViolations = new ArraySet<>(); + synchronized (mLock) { + if (mPrivappPermissionsViolations == null) { + mPrivappPermissionsViolations = new ArraySet<>(); + } + mPrivappPermissionsViolations.add(packageName + " (" + pkg.getPath() + "): " + + permissionName); } - mPrivappPermissionsViolations.add(packageName + " (" + pkg.getPath() + "): " - + permissionName); } } } @@ -3662,15 +3682,16 @@ public class PermissionManagerService extends IPermissionManager.Stub { final boolean instantApp = mPackageManagerInt.isInstantApp(pkg.getPackageName(), userId); for (String permission : pkg.getRequestedPermissions()) { - final Permission bp; + final boolean shouldGrantPermission; synchronized (mLock) { - bp = mRegistry.getPermissionLocked(permission); - } - if (bp != null && (bp.isRuntime() || bp.isDevelopment()) - && (!instantApp || bp.isInstant()) - && (supportsRuntimePermissions || !bp.isRuntimeOnly()) - && (grantedPermissions == null - || ArrayUtils.contains(grantedPermissions, permission))) { + final Permission bp = mRegistry.getPermission(permission); + shouldGrantPermission = bp != null && (bp.isRuntime() || bp.isDevelopment()) + && (!instantApp || bp.isInstant()) + && (supportsRuntimePermissions || !bp.isRuntimeOnly()) + && (grantedPermissions == null + || ArrayUtils.contains(grantedPermissions, permission)); + } + if (shouldGrantPermission) { final int flags = getPermissionFlagsInternal(permission, pkg.getPackageName(), callingUid, userId); if (supportsRuntimePermissions) { @@ -3704,14 +3725,13 @@ public class PermissionManagerService extends IPermissionManager.Stub { for (int j = 0; j < permissionCount; j++) { final String permissionName = pkg.getRequestedPermissions().get(j); - final Permission bp = mRegistry.getPermissionLocked(permissionName); - - if (bp == null || !bp.isHardOrSoftRestricted()) { - continue; - } - final boolean isGranted; synchronized (mLock) { + final Permission bp = mRegistry.getPermission(permissionName); + if (bp == null || !bp.isHardOrSoftRestricted()) { + continue; + } + final UidPermissionState uidState = getUidStateLocked(pkg, userId); if (uidState == null) { Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName() @@ -3865,11 +3885,6 @@ public class PermissionManagerService extends IPermissionManager.Stub { int affectedUserId = UserHandle.USER_NULL; // Update permissions for (String eachPerm : deletedPs.pkg.getRequestedPermissions()) { - Permission bp = mRegistry.getPermission(eachPerm); - if (bp == null) { - continue; - } - // Check if another package in the shared user needs the permission. boolean used = false; final List<AndroidPackage> pkgs = sus.getPackages(); @@ -3913,6 +3928,11 @@ public class PermissionManagerService extends IPermissionManager.Stub { continue; } + Permission bp = mRegistry.getPermission(eachPerm); + if (bp == null) { + continue; + } + // TODO(zhanghai): Why are we only killing the UID when GIDs changed, instead of any // permission change? if (uidState.removePermissionState(bp.getName()) && bp.hasGids()) { @@ -3939,7 +3959,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { final int requestedPermCount = pkg.getRequestedPermissions().size(); for (int j = 0; j < requestedPermCount; j++) { String permission = pkg.getRequestedPermissions().get(j); - Permission bp = mRegistry.getPermissionLocked(permission); + Permission bp = mRegistry.getPermission(permission); if (bp != null) { usedPermissions.add(permission); } @@ -3954,7 +3974,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { for (int i = permissionStatesSize - 1; i >= 0; i--) { PermissionState permissionState = permissionStates.get(i); if (!usedPermissions.contains(permissionState.getName())) { - Permission bp = mRegistry.getPermissionLocked(permissionState.getName()); + Permission bp = mRegistry.getPermission(permissionState.getName()); if (bp != null) { if (uidState.removePermissionState(bp.getName()) && permissionState.isRuntime()) { @@ -4017,35 +4037,6 @@ public class PermissionManagerService extends IPermissionManager.Stub { } /** - * Cache background->foreground permission mapping. - * - * <p>This is only run once. - */ - private void cacheBackgroundToForegoundPermissionMapping() { - synchronized (mLock) { - if (mBackgroundPermissions == null) { - // Cache background -> foreground permission mapping. - // Only system declares background permissions, hence mapping does never change. - mBackgroundPermissions = new ArrayMap<>(); - for (Permission bp : mRegistry.getPermissionsLocked()) { - if (bp.getBackgroundPermission() != null) { - String fgPerm = bp.getName(); - String bgPerm = bp.getBackgroundPermission(); - - List<String> fgPerms = mBackgroundPermissions.get(bgPerm); - if (fgPerms == null) { - fgPerms = new ArrayList<>(); - mBackgroundPermissions.put(bgPerm, fgPerms); - } - - fgPerms.add(fgPerm); - } - } - } - } - } - - /** * Update all packages on the volume, <u>beside</u> the changing package. If the changing * package is set too, all packages are updated. */ @@ -4118,8 +4109,6 @@ public class PermissionManagerService extends IPermissionManager.Stub { flags |= UPDATE_PERMISSIONS_ALL; } - cacheBackgroundToForegoundPermissionMapping(); - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "restorePermissionState"); // Now update the permissions for all packages. if ((flags & UPDATE_PERMISSIONS_ALL) != 0) { @@ -4173,9 +4162,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { boolean changed = false; Set<Permission> needsUpdate = null; synchronized (mLock) { - for (final Permission bp : mRegistry.getPermissionsLocked()) { + for (final Permission bp : mRegistry.getPermissions()) { if (bp.isDynamic()) { - bp.updateDynamicPermission(mRegistry.getPermissionTreesLocked()); + bp.updateDynamicPermission(mRegistry.getPermissionTrees()); } if (!packageName.equals(bp.getPackageName())) { // Not checking sourcePackageSetting because it can be null when @@ -4225,7 +4214,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { } }); } - mRegistry.removePermissionLocked(bp.getName()); + synchronized (mLock) { + mRegistry.removePermission(bp.getName()); + } continue; } final AndroidPackage sourcePkg = @@ -4239,7 +4230,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } Slog.w(TAG, "Removing dangling permission: " + bp.getName() + " from package " + bp.getPackageName()); - mRegistry.removePermissionLocked(bp.getName()); + mRegistry.removePermission(bp.getName()); } } } @@ -4307,7 +4298,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { Set<Permission> needsUpdate = null; synchronized (mLock) { - final Iterator<Permission> it = mRegistry.getPermissionTreesLocked().iterator(); + final Iterator<Permission> it = mRegistry.getPermissionTrees().iterator(); while (it.hasNext()) { final Permission bp = it.next(); if (!packageName.equals(bp.getPackageName())) { @@ -4343,7 +4334,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } Slog.w(TAG, "Removing dangling permission tree: " + bp.getName() + " from package " + bp.getPackageName()); - mRegistry.removePermissionLocked(bp.getName()); + mRegistry.removePermission(bp.getName()); } } } @@ -4524,16 +4515,16 @@ public class PermissionManagerService extends IPermissionManager.Stub { return builder.toString(); } - @GuardedBy({"mSettings.mLock", "mLock"}) + @GuardedBy("mLock") private int calculateCurrentPermissionFootprintLocked(@NonNull Permission permissionTree) { int size = 0; - for (final Permission permission : mRegistry.getPermissionsLocked()) { + for (final Permission permission : mRegistry.getPermissions()) { size += permissionTree.calculateFootprint(permission); } return size; } - @GuardedBy({"mSettings.mLock", "mLock"}) + @GuardedBy("mLock") private void enforcePermissionCapLocked(PermissionInfo info, Permission tree) { // We calculate the max size of permissions defined by this uid and throw // if that plus the size of 'info' would exceed our stated maximum. @@ -4547,9 +4538,12 @@ public class PermissionManagerService extends IPermissionManager.Stub { private void systemReady() { mSystemReady = true; - if (mPrivappPermissionsViolations != null) { - throw new IllegalStateException("Signature|privileged permissions not in " - + "privapp-permissions whitelist: " + mPrivappPermissionsViolations); + + synchronized (mLock) { + if (mPrivappPermissionsViolations != null) { + throw new IllegalStateException("Signature|privileged permissions not in " + + "privapp-permissions whitelist: " + mPrivappPermissionsViolations); + } } mPermissionControllerManager = mContext.getSystemService(PermissionControllerManager.class); @@ -4617,29 +4611,21 @@ public class PermissionManagerService extends IPermissionManager.Stub { mMetricsLogger.write(log); } - /** - * Get the mapping of background permissions to their foreground permissions. - * - * <p>Only initialized in the system server. - * - * @return the map <bg permission -> list<fg perm>> - */ - public @Nullable ArrayMap<String, List<String>> getBackgroundPermissions() { - return mBackgroundPermissions; - } - + @GuardedBy("mLock") @Nullable private UidPermissionState getUidStateLocked(@NonNull PackageSetting ps, @UserIdInt int userId) { return getUidStateLocked(ps.getAppId(), userId); } + @GuardedBy("mLock") @Nullable private UidPermissionState getUidStateLocked(@NonNull AndroidPackage pkg, @UserIdInt int userId) { return getUidStateLocked(pkg.getUid(), userId); } + @GuardedBy("mLock") @Nullable private UidPermissionState getUidStateLocked(@AppIdInt int appId, @UserIdInt int userId) { final UserPermissionState userState = mState.getUserState(userId); @@ -4682,11 +4668,12 @@ public class PermissionManagerService extends IPermissionManager.Stub { }); } + @GuardedBy("mLock") private void readLegacyPermissionStatesLocked(@NonNull UidPermissionState uidState, @NonNull Collection<LegacyPermissionState.PermissionState> permissionStates) { for (final LegacyPermissionState.PermissionState permissionState : permissionStates) { final String permissionName = permissionState.getName(); - final Permission permission = mRegistry.getPermissionLocked(permissionName); + final Permission permission = mRegistry.getPermission(permissionName); if (permission == null) { Slog.w(TAG, "Unknown permission: " + permissionName); continue; @@ -4771,9 +4758,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { permission.setGids(configPermission.getRawGids(), configPermission.areGidsPerUser()); } - mRegistry.addPermissionLocked(permission); + mRegistry.addPermission(permission); } else { - mRegistry.addPermissionTreeLocked(permission); + mRegistry.addPermissionTree(permission); } } } @@ -4787,7 +4774,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { final List<LegacyPermission> legacyPermissions = new ArrayList<>(); synchronized (mLock) { final Collection<Permission> permissions = writePermissionOrPermissionTree == 0 - ? mRegistry.getPermissionsLocked() : mRegistry.getPermissionTreesLocked(); + ? mRegistry.getPermissions() : mRegistry.getPermissionTrees(); for (final Permission permission : permissions) { // We don't need to provide UID and GIDs, which are only retrieved when dumping. final LegacyPermission legacyPermission = new LegacyPermission( @@ -4807,7 +4794,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { private void transferPermissions(@NonNull String oldPackageName, @NonNull String newPackageName) { synchronized (mLock) { - mRegistry.transferPermissionsLocked(oldPackageName, newPackageName); + mRegistry.transferPermissions(oldPackageName, newPackageName); } } @@ -4822,7 +4809,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { private List<LegacyPermission> getLegacyPermissions() { synchronized (mLock) { final List<LegacyPermission> legacyPermissions = new ArrayList<>(); - for (final Permission permission : mRegistry.getPermissionsLocked()) { + for (final Permission permission : mRegistry.getPermissions()) { final LegacyPermission legacyPermission = new LegacyPermission( permission.getPermissionInfo(), permission.getType(), permission.getUid(), permission.getRawGids()); @@ -4836,7 +4823,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { private Map<String, Set<String>> getAllAppOpPermissionPackages() { synchronized (mLock) { final ArrayMap<String, ArraySet<String>> appOpPermissionPackages = - mRegistry.getAllAppOpPermissionPackagesLocked(); + mRegistry.getAllAppOpPermissionPackages(); final Map<String, Set<String>> deepClone = new ArrayMap<>(); final int appOpPermissionPackagesSize = appOpPermissionPackages.size(); for (int i = 0; i < appOpPermissionPackagesSize; i++) { @@ -5045,8 +5032,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { @Override public Permission getPermissionTEMP(String permName) { - synchronized (PermissionManagerService.this.mLock) { - return mRegistry.getPermissionLocked(permName); + synchronized (mLock) { + return mRegistry.getPermission(permName); } } @@ -5056,7 +5043,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { ArrayList<PermissionInfo> matchingPermissions = new ArrayList<>(); synchronized (mLock) { - for (final Permission permission : mRegistry.getPermissionsLocked()) { + for (final Permission permission : mRegistry.getPermissions()) { if (permission.getProtection() == protection) { matchingPermissions.add(permission.generatePermissionInfo(0)); } @@ -5072,7 +5059,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { ArrayList<PermissionInfo> matchingPermissions = new ArrayList<>(); synchronized (mLock) { - for (final Permission permission : mRegistry.getPermissionsLocked()) { + for (final Permission permission : mRegistry.getPermissions()) { if ((permission.getProtectionFlags() & protectionFlags) == protectionFlags) { matchingPermissions.add(permission.generatePermissionInfo(0)); } @@ -5270,7 +5257,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { Iterator<String> iterator = permissionNames.iterator(); while (iterator.hasNext()) { final String permissionName = iterator.next(); - final Permission permission = mRegistry.getPermissionLocked(permissionName); + final Permission permission = mRegistry.getPermission(permissionName); if (permission == null || !permission.isHardOrSoftRestricted()) { iterator.remove(); } @@ -5346,12 +5333,11 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } - public void addListenerLocked(IOnPermissionsChangeListener listener) { + public void addListener(IOnPermissionsChangeListener listener) { mPermissionListeners.register(listener); - } - public void removeListenerLocked(IOnPermissionsChangeListener listener) { + public void removeListener(IOnPermissionsChangeListener listener) { mPermissionListeners.unregister(listener); } diff --git a/services/core/java/com/android/server/pm/permission/PermissionRegistry.java b/services/core/java/com/android/server/pm/permission/PermissionRegistry.java index 36719203e4b5..0e3fda7b937a 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionRegistry.java +++ b/services/core/java/com/android/server/pm/permission/PermissionRegistry.java @@ -22,8 +22,6 @@ import android.content.pm.parsing.component.ParsedPermissionGroup; import android.util.ArrayMap; import android.util.ArraySet; -import com.android.internal.annotations.GuardedBy; - import java.util.Collection; /** @@ -34,87 +32,62 @@ public class PermissionRegistry { * All of the permissions known to the system. The mapping is from permission * name to permission object. */ - @GuardedBy("mLock") private final ArrayMap<String, Permission> mPermissions = new ArrayMap<>(); /** * All permission trees known to the system. The mapping is from permission tree * name to permission object. */ - @GuardedBy("mLock") private final ArrayMap<String, Permission> mPermissionTrees = new ArrayMap<>(); /** * All permisson groups know to the system. The mapping is from permission group * name to permission group object. */ - @GuardedBy("mLock") private final ArrayMap<String, ParsedPermissionGroup> mPermissionGroups = new ArrayMap<>(); /** * Set of packages that request a particular app op. The mapping is from permission * name to package names. */ - @GuardedBy("mLock") private final ArrayMap<String, ArraySet<String>> mAppOpPermissionPackages = new ArrayMap<>(); @NonNull - private final Object mLock; - - public PermissionRegistry(@NonNull Object lock) { - mLock = lock; - } - - @GuardedBy("mLock") - @NonNull - public Collection<Permission> getPermissionsLocked() { + public Collection<Permission> getPermissions() { return mPermissions.values(); } - @GuardedBy("mLock") - @Nullable - public Permission getPermissionLocked(@NonNull String permName) { - return mPermissions.get(permName); - } - @Nullable public Permission getPermission(@NonNull String permissionName) { - synchronized (mLock) { - return getPermissionLocked(permissionName); - } + return mPermissions.get(permissionName); } - @GuardedBy("mLock") - public void addPermissionLocked(@NonNull Permission permission) { + public void addPermission(@NonNull Permission permission) { mPermissions.put(permission.getName(), permission); } - @GuardedBy("mLock") - public void removePermissionLocked(@NonNull String permissionName) { + public void removePermission(@NonNull String permissionName) { mPermissions.remove(permissionName); } - @GuardedBy("mLock") @NonNull - public Collection<Permission> getPermissionTreesLocked() { + public Collection<Permission> getPermissionTrees() { return mPermissionTrees.values(); } - @GuardedBy("mLock") @Nullable - public Permission getPermissionTreeLocked(@NonNull String permissionTreeName) { + public Permission getPermissionTree(@NonNull String permissionTreeName) { return mPermissionTrees.get(permissionTreeName); } - @GuardedBy("mLock") - public void addPermissionTreeLocked(@NonNull Permission permissionTree) { + public void addPermissionTree(@NonNull Permission permissionTree) { mPermissionTrees.put(permissionTree.getName(), permissionTree); } /** * Transfers ownership of permissions from one package to another. */ - public void transferPermissionsLocked(@NonNull String oldPackageName, + public void transferPermissions(@NonNull String oldPackageName, @NonNull String newPackageName) { for (int i = 0; i < 2; i++) { ArrayMap<String, Permission> permissions = i == 0 ? mPermissionTrees : mPermissions; @@ -124,37 +97,31 @@ public class PermissionRegistry { } } - @GuardedBy("mLock") @NonNull - public Collection<ParsedPermissionGroup> getPermissionGroupsLocked() { + public Collection<ParsedPermissionGroup> getPermissionGroups() { return mPermissionGroups.values(); } - @GuardedBy("mLock") @Nullable - public ParsedPermissionGroup getPermissionGroupLocked(@NonNull String permissionGroupName) { + public ParsedPermissionGroup getPermissionGroup(@NonNull String permissionGroupName) { return mPermissionGroups.get(permissionGroupName); } - @GuardedBy("mLock") - public void addPermissionGroupLocked(@NonNull ParsedPermissionGroup permissionGroup) { + public void addPermissionGroup(@NonNull ParsedPermissionGroup permissionGroup) { mPermissionGroups.put(permissionGroup.getName(), permissionGroup); } - @GuardedBy("mLock") @NonNull - public ArrayMap<String, ArraySet<String>> getAllAppOpPermissionPackagesLocked() { + public ArrayMap<String, ArraySet<String>> getAllAppOpPermissionPackages() { return mAppOpPermissionPackages; } - @GuardedBy("mLock") @Nullable - public ArraySet<String> getAppOpPermissionPackagesLocked(@NonNull String permissionName) { + public ArraySet<String> getAppOpPermissionPackages(@NonNull String permissionName) { return mAppOpPermissionPackages.get(permissionName); } - @GuardedBy("mLock") - public void addAppOpPermissionPackageLocked(@NonNull String permissionName, + public void addAppOpPermissionPackage(@NonNull String permissionName, @NonNull String packageName) { ArraySet<String> packageNames = mAppOpPermissionPackages.get(permissionName); if (packageNames == null) { @@ -164,8 +131,7 @@ public class PermissionRegistry { packageNames.add(packageName); } - @GuardedBy("mLock") - public void removeAppOpPermissionPackageLocked(@NonNull String permissionName, + public void removeAppOpPermissionPackage(@NonNull String permissionName, @NonNull String packageName) { final ArraySet<String> packageNames = mAppOpPermissionPackages.get(permissionName); if (packageNames == null) { @@ -184,23 +150,7 @@ public class PermissionRegistry { */ @NonNull public Permission enforcePermissionTree(@NonNull String permissionName, int callingUid) { - synchronized (mLock) { - return Permission.enforcePermissionTree(mPermissionTrees.values(), permissionName, - callingUid); - } - } - - public boolean isPermissionInstant(@NonNull String permissionName) { - synchronized (mLock) { - final Permission permission = mPermissions.get(permissionName); - return permission != null && permission.isInstant(); - } - } - - boolean isPermissionAppOp(@NonNull String permissionName) { - synchronized (mLock) { - final Permission permission = mPermissions.get(permissionName); - return permission != null && permission.isAppOp(); - } + return Permission.enforcePermissionTree(mPermissionTrees.values(), permissionName, + callingUid); } } diff --git a/services/core/java/com/android/server/policy/DisplayFoldController.java b/services/core/java/com/android/server/policy/DisplayFoldController.java index f8e26fc57b95..b007a75c1ca5 100644 --- a/services/core/java/com/android/server/policy/DisplayFoldController.java +++ b/services/core/java/com/android/server/policy/DisplayFoldController.java @@ -16,8 +16,10 @@ package com.android.server.policy; +import android.annotation.Nullable; import android.content.Context; import android.graphics.Rect; +import android.hardware.ICameraService; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; @@ -26,11 +28,13 @@ import android.hardware.display.DisplayManagerInternal; import android.os.Handler; import android.os.RemoteCallbackList; import android.os.RemoteException; +import android.util.Slog; import android.view.DisplayInfo; import android.view.IDisplayFoldListener; import com.android.server.DisplayThread; import com.android.server.LocalServices; +import com.android.server.camera.CameraServiceProxy; import com.android.server.wm.WindowManagerInternal; /** @@ -38,11 +42,13 @@ import com.android.server.wm.WindowManagerInternal; * TODO(b/126160895): Move DisplayFoldController from PhoneWindowManager to DisplayPolicy. */ class DisplayFoldController { - private static final String TAG = "DisplayFoldController"; private final WindowManagerInternal mWindowManagerInternal; private final DisplayManagerInternal mDisplayManagerInternal; + // Camera service proxy can be disabled through a config. + @Nullable + private final CameraServiceProxy mCameraServiceProxy; private final int mDisplayId; private final Handler mHandler; @@ -58,10 +64,12 @@ class DisplayFoldController { private final DisplayFoldDurationLogger mDurationLogger = new DisplayFoldDurationLogger(); DisplayFoldController(WindowManagerInternal windowManagerInternal, - DisplayManagerInternal displayManagerInternal, int displayId, Rect foldedArea, + DisplayManagerInternal displayManagerInternal, + @Nullable CameraServiceProxy cameraServiceProxy, int displayId, Rect foldedArea, Handler handler) { mWindowManagerInternal = windowManagerInternal; mDisplayManagerInternal = displayManagerInternal; + mCameraServiceProxy = cameraServiceProxy; mDisplayId = displayId; mFoldedArea = new Rect(foldedArea); mHandler = handler; @@ -116,6 +124,16 @@ class DisplayFoldController { } } + if (mCameraServiceProxy != null) { + if (folded) { + mCameraServiceProxy.setDeviceStateFlags(ICameraService.DEVICE_STATE_FOLDED); + } else { + mCameraServiceProxy.clearDeviceStateFlags(ICameraService.DEVICE_STATE_FOLDED); + } + } else { + Slog.w(TAG, "Camera service unavailable to toggle folded state."); + } + mDurationLogger.setDeviceFolded(folded); mDurationLogger.logFocusedAppWithFoldState(folded, mFocusedApp); mFolded = folded; @@ -193,8 +211,13 @@ class DisplayFoldController { } static DisplayFoldController create(Context context, int displayId) { + final WindowManagerInternal windowManagerService = + LocalServices.getService(WindowManagerInternal.class); final DisplayManagerInternal displayService = LocalServices.getService(DisplayManagerInternal.class); + final CameraServiceProxy cameraServiceProxy = + LocalServices.getService(CameraServiceProxy.class); + final String configFoldedArea = context.getResources().getString( com.android.internal.R.string.config_foldedArea); final Rect foldedArea; @@ -204,7 +227,7 @@ class DisplayFoldController { foldedArea = Rect.unflattenFromString(configFoldedArea); } - return new DisplayFoldController(LocalServices.getService(WindowManagerInternal.class), - displayService, displayId, foldedArea, DisplayThread.getHandler()); + return new DisplayFoldController(windowManagerService, displayService, cameraServiceProxy, + displayId, foldedArea, DisplayThread.getHandler()); } } diff --git a/services/core/java/com/android/server/power/AttentionDetector.java b/services/core/java/com/android/server/power/AttentionDetector.java index 06edd19a376a..1a4a22203e57 100644 --- a/services/core/java/com/android/server/power/AttentionDetector.java +++ b/services/core/java/com/android/server/power/AttentionDetector.java @@ -18,6 +18,7 @@ package com.android.server.power; import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE; +import android.annotation.NonNull; import android.app.ActivityManager; import android.app.SynchronousUserSwitchObserver; import android.attention.AttentionManagerInternal; @@ -42,6 +43,7 @@ import com.android.server.LocalServices; import com.android.server.wm.WindowManagerInternal; import java.io.PrintWriter; +import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; @@ -66,6 +68,9 @@ public class AttentionDetector { /** Default value in absence of {@link DeviceConfig} override. */ static final long DEFAULT_PRE_DIM_CHECK_DURATION_MILLIS = 2_000; + @VisibleForTesting + protected long mPreDimCheckDurationMillis; + /** DeviceConfig flag name, describes how long to run the check beyond the screen dim event. */ static final String KEY_POST_DIM_CHECK_DURATION_MILLIS = "post_dim_check_duration_millis"; @@ -73,12 +78,28 @@ public class AttentionDetector { /** Default value in absence of {@link DeviceConfig} override. */ static final long DEFAULT_POST_DIM_CHECK_DURATION_MILLIS = 0; + private long mRequestedPostDimTimeoutMillis; + + /** + * Keep the last used post dim timeout for the dumpsys (it can't be longer the dim duration). + */ + private long mEffectivePostDimTimeoutMillis; + /** * DeviceConfig flag name, describes the limit of how long the device can remain unlocked due to * attention checking. */ static final String KEY_MAX_EXTENSION_MILLIS = "max_extension_millis"; + /** + * The default value for the maximum time, in millis, that the phone can stay unlocked because + * of attention events, triggered by any user. + */ + @VisibleForTesting + protected long mDefaultMaximumExtensionMillis; + + private long mMaximumExtensionMillis; + private Context mContext; private boolean mIsSettingEnabled; @@ -88,13 +109,6 @@ public class AttentionDetector { */ private final Runnable mOnUserAttention; - /** - * The default value for the maximum time, in millis, that the phone can stay unlocked because - * of attention events, triggered by any user. - */ - @VisibleForTesting - protected long mDefaultMaximumExtensionMillis; - private final Object mLock; /** @@ -137,9 +151,6 @@ public class AttentionDetector { @VisibleForTesting AttentionCallbackInternalImpl mCallback; - /** Keep the last used post dim timeout for the dumpsys. */ - private long mLastPostDimTimeout; - public AttentionDetector(Runnable onUserAttention, Object lock) { mOnUserAttention = onUserAttention; mLock = lock; @@ -180,6 +191,11 @@ public class AttentionDetector { updateEnabledFromSettings(context); } }, UserHandle.USER_ALL); + + readValuesFromDeviceConfig(); + DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_ATTENTION_MANAGER_SERVICE, + context.getMainExecutor(), + (properties) -> onDeviceConfigChange(properties.getKeyset())); } /** To be called in {@link PowerManagerService#updateUserActivitySummaryLocked}. */ @@ -192,8 +208,8 @@ public class AttentionDetector { } final long now = SystemClock.uptimeMillis(); - final long whenToCheck = nextScreenDimming - getPreDimCheckDurationMillis(); - final long whenToStopExtending = mLastUserActivityTime + getMaxExtensionMillis(); + final long whenToCheck = nextScreenDimming - mPreDimCheckDurationMillis; + final long whenToStopExtending = mLastUserActivityTime + mMaximumExtensionMillis; if (now < whenToCheck) { if (DEBUG) { Slog.d(TAG, "Do not check for attention yet, wait " + (whenToCheck - now)); @@ -220,9 +236,11 @@ public class AttentionDetector { mRequestId++; mLastActedOnNextScreenDimming = nextScreenDimming; mCallback = new AttentionCallbackInternalImpl(mRequestId); + mEffectivePostDimTimeoutMillis = Math.min(mRequestedPostDimTimeoutMillis, + dimDurationMillis); Slog.v(TAG, "Checking user attention, ID: " + mRequestId); final boolean sent = mAttentionManager.checkAttention( - getPreDimCheckDurationMillis() + getPostDimCheckDurationMillis(dimDurationMillis), + mPreDimCheckDurationMillis + mEffectivePostDimTimeoutMillis, mCallback); if (!sent) { mRequested.set(false); @@ -294,9 +312,9 @@ public class AttentionDetector { public void dump(PrintWriter pw) { pw.println("AttentionDetector:"); pw.println(" mIsSettingEnabled=" + mIsSettingEnabled); - pw.println(" mMaxExtensionMillis=" + getMaxExtensionMillis()); - pw.println(" preDimCheckDurationMillis=" + getPreDimCheckDurationMillis()); - pw.println(" postDimCheckDurationMillis=" + mLastPostDimTimeout); + pw.println(" mMaxExtensionMillis=" + mMaximumExtensionMillis); + pw.println(" mPreDimCheckDurationMillis=" + mPreDimCheckDurationMillis); + pw.println(" mEffectivePostDimTimeout=" + mEffectivePostDimTimeoutMillis); pw.println(" mLastUserActivityTime(excludingAttention)=" + mLastUserActivityTime); pw.println(" mAttentionServiceSupported=" + isAttentionServiceSupported()); pw.println(" mRequested=" + mRequested); @@ -319,7 +337,7 @@ public class AttentionDetector { /** How long to check <b>after</b> the screen dims, capped at the dim duration. */ @VisibleForTesting - protected long getPostDimCheckDurationMillis(long dimDurationMillis) { + protected long getPostDimCheckDurationMillis() { final long millis = DeviceConfig.getLong(NAMESPACE_ATTENTION_MANAGER_SERVICE, KEY_POST_DIM_CHECK_DURATION_MILLIS, DEFAULT_POST_DIM_CHECK_DURATION_MILLIS); @@ -328,9 +346,7 @@ public class AttentionDetector { Slog.w(TAG, "Bad flag value supplied for: " + KEY_POST_DIM_CHECK_DURATION_MILLIS); return DEFAULT_POST_DIM_CHECK_DURATION_MILLIS; } - - mLastPostDimTimeout = Math.min(millis, dimDurationMillis); - return mLastPostDimTimeout; + return millis; } /** How long the device can remain unlocked due to attention checking. */ @@ -348,6 +364,32 @@ public class AttentionDetector { return millis; } + private void onDeviceConfigChange(@NonNull Set<String> keys) { + for (String key : keys) { + switch (key) { + case KEY_MAX_EXTENSION_MILLIS: + case KEY_POST_DIM_CHECK_DURATION_MILLIS: + case KEY_PRE_DIM_CHECK_DURATION_MILLIS: + readValuesFromDeviceConfig(); + return; + default: + Slog.i(TAG, "Ignoring change on " + key); + } + } + } + + private void readValuesFromDeviceConfig() { + mMaximumExtensionMillis = getMaxExtensionMillis(); + mPreDimCheckDurationMillis = getPreDimCheckDurationMillis(); + mRequestedPostDimTimeoutMillis = getPostDimCheckDurationMillis(); + + Slog.i(TAG, "readValuesFromDeviceConfig():" + + "\nmMaximumExtensionMillis=" + mMaximumExtensionMillis + + "\nmPreDimCheckDurationMillis=" + mPreDimCheckDurationMillis + + "\nmRequestedPostDimTimeoutMillis=" + mRequestedPostDimTimeoutMillis); + + } + @VisibleForTesting final class AttentionCallbackInternalImpl extends AttentionCallbackInternal { private final int mId; diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java index 7433a3a53ad8..d3b1ac6e6096 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -247,6 +247,13 @@ public class StatsPullAtomService extends SystemService { // 20% as a conservative estimate. private static final int MAX_PROCSTATS_RAW_SHARD_SIZE = (int) (MAX_PROCSTATS_SHARD_SIZE * 1.20); + /** + * Threshold to filter out small CPU times at frequency per UID. Those small values appear + * because of more precise accounting in a BPF program. Discarding them reduces the data by at + * least 20% with negligible error. + */ + private static final int MIN_CPU_TIME_PER_UID_FREQ = 10; + private final Object mThermalLock = new Object(); @GuardedBy("mThermalLock") private IThermalService mThermalService; @@ -1509,7 +1516,7 @@ public class StatsPullAtomService extends SystemService { int pullCpuTimePerUidFreqLocked(int atomTag, List<StatsEvent> pulledData) { mCpuUidFreqTimeReader.readAbsolute((uid, cpuFreqTimeMs) -> { for (int freqIndex = 0; freqIndex < cpuFreqTimeMs.length; ++freqIndex) { - if (cpuFreqTimeMs[freqIndex] != 0) { + if (cpuFreqTimeMs[freqIndex] >= MIN_CPU_TIME_PER_UID_FREQ) { pulledData.add(FrameworkStatsLog.buildStatsEvent( atomTag, uid, freqIndex, cpuFreqTimeMs[freqIndex])); } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index c51e63f5f8c0..9273bf71f673 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -125,7 +125,6 @@ import static com.android.server.wm.Task.ActivityState.PAUSED; import static com.android.server.wm.Task.ActivityState.PAUSING; import static com.android.server.wm.Task.ActivityState.RESUMED; import static com.android.server.wm.Task.ActivityState.STARTED; -import static com.android.server.wm.Task.ActivityState.STOPPED; import static com.android.server.wm.Task.ActivityState.STOPPING; import static com.android.server.wm.TaskProto.ACTIVITY_TYPE; import static com.android.server.wm.TaskProto.BOUNDS; @@ -4127,6 +4126,10 @@ class Task extends WindowContainer<WindowContainer> { forAllActivities(r -> { info.addLaunchCookie(r.mLaunchCookie); }); + final Task rootTask = getRootTask(); + info.parentTaskId = rootTask == getParent() && rootTask.mCreatedByOrganizer + ? rootTask.mTaskId + : INVALID_TASK_ID; } @Nullable PictureInPictureParams getPictureInPictureParams() { @@ -4843,6 +4846,17 @@ class Task extends WindowContainer<WindowContainer> { return mTaskOrganizer != null; } + private boolean canBeOrganized() { + // All root tasks can be organized + if (isRootTask()) { + return true; + } + + // Task could be organized if it's the direct child of the root created by organizer. + final Task rootTask = getRootTask(); + return rootTask == getParent() && rootTask.mCreatedByOrganizer; + } + @Override boolean showSurfaceOnCreation() { // Organized tasks handle their own surface visibility @@ -4991,7 +5005,7 @@ class Task extends WindowContainer<WindowContainer> { // is created. return false; } - if (!isRootTask()) { + if (!canBeOrganized()) { return setTaskOrganizer(null); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 084b7667b5a5..c806c94358cb 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1218,9 +1218,9 @@ public class WindowManagerService extends IWindowManager.Stub mAnimator = new WindowAnimator(this); mRoot = new RootWindowContainer(this); - mUseBLAST = DeviceConfig.getBoolean( - DeviceConfig.NAMESPACE_WINDOW_MANAGER_NATIVE_BOOT, - WM_USE_BLAST_ADAPTER_FLAG, false); + final ContentResolver resolver = context.getContentResolver(); + mUseBLAST = Settings.Global.getInt(resolver, + Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_VR, 1) == 1; mSyncEngine = new BLASTSyncEngine(this); @@ -1298,7 +1298,6 @@ public class WindowManagerService extends IWindowManager.Stub } }, UserHandle.ALL, suspendPackagesFilter, null, null); - final ContentResolver resolver = context.getContentResolver(); // Get persisted window scale setting mWindowAnimationScaleSetting = Settings.Global.getFloat(resolver, Settings.Global.WINDOW_ANIMATION_SCALE, mWindowAnimationScaleSetting); diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 51857dcd323b..7d54ea95579e 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -104,13 +104,55 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub @Override public void applyTransaction(WindowContainerTransaction t) { - applyTransaction(t, null /*callback*/, null /*transition*/); + enforceTaskPermission("applyTransaction()"); + if (t == null) { + throw new IllegalArgumentException("Null transaction passed to applySyncTransaction"); + } + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mGlobalLock) { + applyTransaction(t, -1 /*syncId*/, null /*transition*/); + } + } finally { + Binder.restoreCallingIdentity(ident); + } } @Override public int applySyncTransaction(WindowContainerTransaction t, IWindowContainerTransactionCallback callback) { - return applyTransaction(t, callback, null /*transition*/); + enforceTaskPermission("applySyncTransaction()"); + if (t == null) { + throw new IllegalArgumentException("Null transaction passed to applySyncTransaction"); + } + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mGlobalLock) { + /** + * If callback is non-null we are looking to synchronize this transaction by + * collecting all the results in to a SurfaceFlinger transaction and then delivering + * that to the given transaction ready callback. See {@link BLASTSyncEngine} for the + * details of the operation. But at a high level we create a sync operation with a + * given ID and an associated callback. Then we notify each WindowContainer in this + * WindowContainer transaction that it is participating in a sync operation with + * that ID. Once everything is notified we tell the BLASTSyncEngine "setSyncReady" + * which means that we have added everything to the set. At any point after this, + * all the WindowContainers will eventually finish applying their changes and notify + * the BLASTSyncEngine which will deliver the Transaction to the callback. + */ + int syncId = -1; + if (callback != null) { + syncId = startSyncWithOrganizer(callback); + } + applyTransaction(t, syncId, null /*transition*/); + if (syncId >= 0) { + setSyncReady(syncId); + } + return syncId; + } + } finally { + Binder.restoreCallingIdentity(ident); + } } @Override @@ -131,7 +173,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub if (t == null) { t = new WindowContainerTransaction(); } - applyTransaction(t, null /*callback*/, transition); + applyTransaction(t, -1 /*syncId*/, transition); return transition; } } finally { @@ -148,10 +190,16 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub try { synchronized (mGlobalLock) { int syncId = -1; - if (t != null) { - syncId = applyTransaction(t, callback, null /*transition*/); + if (t != null && callback != null) { + syncId = startSyncWithOrganizer(callback); } getTransitionController().finishTransition(transitionToken); + if (t != null) { + applyTransaction(t, syncId, null /*transition*/); + } + if (syncId >= 0) { + setSyncReady(syncId); + } return syncId; } } finally { @@ -160,154 +208,114 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } /** - * @param callback If non-null, this will be a sync-transaction. + * @param syncId If non-null, this will be a sync-transaction. * @param transition A transition to collect changes into. - * @return a BLAST sync-id if this is a non-transition, sync transaction. */ - private int applyTransaction(@NonNull WindowContainerTransaction t, - @Nullable IWindowContainerTransactionCallback callback, + private void applyTransaction(@NonNull WindowContainerTransaction t, int syncId, @Nullable Transition transition) { - enforceTaskPermission("applySyncTransaction()"); - int syncId = -1; - if (t == null) { - throw new IllegalArgumentException( - "Null transaction passed to applySyncTransaction"); - } - final long ident = Binder.clearCallingIdentity(); + int effects = 0; + ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d", syncId); + mService.deferWindowLayout(); try { - synchronized (mGlobalLock) { - int effects = 0; + ArraySet<WindowContainer> haveConfigChanges = new ArraySet<>(); + Iterator<Map.Entry<IBinder, WindowContainerTransaction.Change>> entries = + t.getChanges().entrySet().iterator(); + while (entries.hasNext()) { + final Map.Entry<IBinder, WindowContainerTransaction.Change> entry = entries.next(); + final WindowContainer wc = WindowContainer.fromBinder(entry.getKey()); + if (wc == null || !wc.isAttached()) { + Slog.e(TAG, "Attempt to operate on detached container: " + wc); + continue; + } + // Make sure we add to the syncSet before performing + // operations so we don't end up splitting effects between the WM + // pending transaction and the BLASTSync transaction. + if (syncId >= 0) { + addToSyncSet(syncId, wc); + } - /** - * If callback is non-null we are looking to synchronize this transaction by - * collecting all the results in to a SurfaceFlinger transaction and then delivering - * that to the given transaction ready callback. See {@link BLASTSyncEngine} for the - * details of the operation. But at a high level we create a sync operation with a - * given ID and an associated callback. Then we notify each WindowContainer in this - * WindowContainer transaction that it is participating in a sync operation with - * that ID. Once everything is notified we tell the BLASTSyncEngine "setSyncReady" - * which means that we have added everything to the set. At any point after this, - * all the WindowContainers will eventually finish applying their changes and notify - * the BLASTSyncEngine which will deliver the Transaction to the callback. - */ - if (callback != null) { - syncId = startSyncWithOrganizer(callback); + int containerEffect = applyWindowContainerChange(wc, entry.getValue()); + if (transition != null) transition.collect(wc); + effects |= containerEffect; + + // Lifecycle changes will trigger ensureConfig for everything. + if ((effects & TRANSACT_EFFECTS_LIFECYCLE) == 0 + && (containerEffect & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) { + haveConfigChanges.add(wc); + } + } + // Hierarchy changes + final List<WindowContainerTransaction.HierarchyOp> hops = t.getHierarchyOps(); + for (int i = 0, n = hops.size(); i < n; ++i) { + final WindowContainerTransaction.HierarchyOp hop = hops.get(i); + final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer()); + if (!wc.isAttached()) { + Slog.e(TAG, "Attempt to operate on detached container: " + wc); + continue; + } + if (syncId >= 0) { + addToSyncSet(syncId, wc); } - ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d", - syncId); - mService.deferWindowLayout(); - try { - ArraySet<WindowContainer> haveConfigChanges = new ArraySet<>(); - Iterator<Map.Entry<IBinder, WindowContainerTransaction.Change>> entries = - t.getChanges().entrySet().iterator(); - while (entries.hasNext()) { - final Map.Entry<IBinder, WindowContainerTransaction.Change> entry = - entries.next(); - final WindowContainer wc = WindowContainer.fromBinder(entry.getKey()); - if (wc == null || !wc.isAttached()) { - Slog.e(TAG, "Attempt to operate on detached container: " + wc); - continue; - } - // Make sure we add to the syncSet before performing - // operations so we don't end up splitting effects between the WM - // pending transaction and the BLASTSync transaction. - if (syncId >= 0) { - addToSyncSet(syncId, wc); - } - - int containerEffect = applyWindowContainerChange(wc, entry.getValue()); - if (transition != null) transition.collect(wc); - effects |= containerEffect; - - // Lifecycle changes will trigger ensureConfig for everything. - if ((effects & TRANSACT_EFFECTS_LIFECYCLE) == 0 - && (containerEffect & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) { - haveConfigChanges.add(wc); - } - } - // Hierarchy changes - final List<WindowContainerTransaction.HierarchyOp> hops = t.getHierarchyOps(); - for (int i = 0, n = hops.size(); i < n; ++i) { - final WindowContainerTransaction.HierarchyOp hop = hops.get(i); - final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer()); - if (!wc.isAttached()) { - Slog.e(TAG, "Attempt to operate on detached container: " + wc); - continue; - } - if (syncId >= 0) { - addToSyncSet(syncId, wc); - } effects |= sanitizeAndApplyHierarchyOp(wc, hop); - if (transition != null) { - transition.collect(wc); - if (hop.isReparent() && hop.getNewParent() != null) { - transition.collect(WindowContainer.fromBinder(hop.getNewParent())); - } - } - } - // Queue-up bounds-change transactions for tasks which are now organized. Do - // this after hierarchy ops so we have the final organized state. - entries = t.getChanges().entrySet().iterator(); - while (entries.hasNext()) { - final Map.Entry<IBinder, WindowContainerTransaction.Change> entry = - entries.next(); - final Task task = WindowContainer.fromBinder(entry.getKey()).asTask(); - final Rect surfaceBounds = entry.getValue().getBoundsChangeSurfaceBounds(); - if (task == null || !task.isAttached() || surfaceBounds == null) { - continue; - } - if (!task.isOrganized()) { - final Task parent = - task.getParent() != null ? task.getParent().asTask() : null; - // Also allow direct children of created-by-organizer tasks to be - // controlled. In the future, these will become organized anyways. - if (parent == null || !parent.mCreatedByOrganizer) { - throw new IllegalArgumentException( - "Can't manipulate non-organized task surface " + task); - } - } - final SurfaceControl.Transaction sft = new SurfaceControl.Transaction(); - final SurfaceControl sc = task.getSurfaceControl(); - sft.setPosition(sc, surfaceBounds.left, surfaceBounds.top); - if (surfaceBounds.isEmpty()) { - sft.setWindowCrop(sc, null); - } else { - sft.setWindowCrop(sc, surfaceBounds.width(), surfaceBounds.height()); - } - task.setMainWindowSizeChangeTransaction(sft); + if (transition != null) { + transition.collect(wc); + if (hop.isReparent() && hop.getNewParent() != null) { + transition.collect(WindowContainer.fromBinder(hop.getNewParent())); } - if ((effects & TRANSACT_EFFECTS_LIFECYCLE) != 0) { - // Already calls ensureActivityConfig - mService.mRootWindowContainer.ensureActivitiesVisible( - null, 0, PRESERVE_WINDOWS); - } else if ((effects & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) { - final PooledConsumer f = PooledLambda.obtainConsumer( - ActivityRecord::ensureActivityConfiguration, - PooledLambda.__(ActivityRecord.class), 0, - true /* preserveWindow */); - try { - for (int i = haveConfigChanges.size() - 1; i >= 0; --i) { - haveConfigChanges.valueAt(i).forAllActivities(f); - } - } finally { - f.recycle(); - } + } + } + // Queue-up bounds-change transactions for tasks which are now organized. Do + // this after hierarchy ops so we have the final organized state. + entries = t.getChanges().entrySet().iterator(); + while (entries.hasNext()) { + final Map.Entry<IBinder, WindowContainerTransaction.Change> entry = entries.next(); + final Task task = WindowContainer.fromBinder(entry.getKey()).asTask(); + final Rect surfaceBounds = entry.getValue().getBoundsChangeSurfaceBounds(); + if (task == null || !task.isAttached() || surfaceBounds == null) { + continue; + } + if (!task.isOrganized()) { + final Task parent = task.getParent() != null ? task.getParent().asTask() : null; + // Also allow direct children of created-by-organizer tasks to be + // controlled. In the future, these will become organized anyways. + if (parent == null || !parent.mCreatedByOrganizer) { + throw new IllegalArgumentException( + "Can't manipulate non-organized task surface " + task); } - - if ((effects & TRANSACT_EFFECTS_CLIENT_CONFIG) == 0) { - mService.addWindowLayoutReasons(LAYOUT_REASON_CONFIG_CHANGED); + } + final SurfaceControl.Transaction sft = new SurfaceControl.Transaction(); + final SurfaceControl sc = task.getSurfaceControl(); + sft.setPosition(sc, surfaceBounds.left, surfaceBounds.top); + if (surfaceBounds.isEmpty()) { + sft.setWindowCrop(sc, null); + } else { + sft.setWindowCrop(sc, surfaceBounds.width(), surfaceBounds.height()); + } + task.setMainWindowSizeChangeTransaction(sft); + } + if ((effects & TRANSACT_EFFECTS_LIFECYCLE) != 0) { + // Already calls ensureActivityConfig + mService.mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS); + } else if ((effects & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) { + final PooledConsumer f = PooledLambda.obtainConsumer( + ActivityRecord::ensureActivityConfiguration, + PooledLambda.__(ActivityRecord.class), 0, + true /* preserveWindow */); + try { + for (int i = haveConfigChanges.size() - 1; i >= 0; --i) { + haveConfigChanges.valueAt(i).forAllActivities(f); } } finally { - mService.continueWindowLayout(); - if (syncId >= 0) { - setSyncReady(syncId); - } + f.recycle(); } } + + if ((effects & TRANSACT_EFFECTS_CLIENT_CONFIG) == 0) { + mService.addWindowLayoutReasons(LAYOUT_REASON_CONFIG_CHANGED); + } } finally { - Binder.restoreCallingIdentity(ident); + mService.continueWindowLayout(); } - return syncId; } private int applyChanges(WindowContainer container, WindowContainerTransaction.Change change) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 4d553e2f92aa..3bfcb6def252 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -4255,18 +4255,18 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { mInjector.getPackageManager().getPackagesForUid( mInjector.binderGetCallingUid())) .write(); - final int callingUserId = mInjector.userHandleGetCallingUserId(); + final CallerIdentity caller = getCallerIdentity(); - if (parent) { - enforceProfileOwnerOrSystemUser(); - } - enforceUserUnlocked(callingUserId); + Preconditions.checkCallAuthorization(!parent || (isDeviceOwner(caller) + || isProfileOwner(caller) || isSystemUid(caller)), + "Only profile owner, device owner and system may call this method."); + enforceUserUnlocked(caller.getUserId()); mContext.enforceCallingOrSelfPermission( REQUEST_PASSWORD_COMPLEXITY, "Must have " + REQUEST_PASSWORD_COMPLEXITY + " permission."); synchronized (getLockObject()) { - final int credentialOwner = getCredentialOwner(callingUserId, parent); + final int credentialOwner = getCredentialOwner(caller.getUserId(), parent); PasswordMetrics metrics = mLockSettingsInternal.getUserPasswordMetrics(credentialOwner); return metrics == null ? PASSWORD_COMPLEXITY_NONE : metrics.determineComplexity(); } @@ -7299,7 +7299,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @Override public boolean hasDeviceOwner() { - enforceDeviceOwnerOrManageUsers(); + final CallerIdentity caller = getCallerIdentity(); + Preconditions.checkCallAuthorization(isDeviceOwner(caller) || canManageUsers(caller)); return mOwners.hasDeviceOwner(); } @@ -8355,32 +8356,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { || hasCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS); } - private void enforceDeviceOwnerOrManageUsers() { - final CallerIdentity caller = getCallerIdentity(); - if (isDeviceOwner(caller)) { - return; - } - Preconditions.checkCallAuthorization(canManageUsers(caller)); - } - - private void enforceProfileOwnerOrSystemUser() { - final CallerIdentity caller = getCallerIdentity(); - if (isDeviceOwner(caller) || isProfileOwner(caller)) { - return; - } - Preconditions.checkState(isSystemUid(caller), - "Only profile owner, device owner and system may call this method."); - } - - private void enforceProfileOwnerOrFullCrossUsersPermission(CallerIdentity caller, - int userId) { - if ((userId == caller.getUserId()) && (isProfileOwner(caller) || isDeviceOwner(caller))) { - // Device Owner/Profile Owner may access the user it runs on. - return; - } - Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userId)); - } - private boolean canUserUseLockTaskLocked(int userId) { if (isUserAffiliatedWithDeviceLocked(userId)) { return true; @@ -12458,7 +12433,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (!mHasFeature) { return null; } - enforceDeviceOwnerOrManageUsers(); + final CallerIdentity caller = getCallerIdentity(); + Preconditions.checkCallAuthorization(isDeviceOwner(caller) || canManageUsers(caller)); synchronized (getLockObject()) { final ActiveAdmin deviceOwnerAdmin = getDeviceOwnerAdminLocked(); return deviceOwnerAdmin == null ? null : deviceOwnerAdmin.organizationName; @@ -13605,19 +13581,22 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @Override public long getLastSecurityLogRetrievalTime() { - enforceDeviceOwnerOrManageUsers(); + final CallerIdentity caller = getCallerIdentity(); + Preconditions.checkCallAuthorization(isDeviceOwner(caller) || canManageUsers(caller)); return getUserData(UserHandle.USER_SYSTEM).mLastSecurityLogRetrievalTime; } @Override public long getLastBugReportRequestTime() { - enforceDeviceOwnerOrManageUsers(); + final CallerIdentity caller = getCallerIdentity(); + Preconditions.checkCallAuthorization(isDeviceOwner(caller) || canManageUsers(caller)); return getUserData(UserHandle.USER_SYSTEM).mLastBugReportRequestTime; } @Override public long getLastNetworkLogRetrievalTime() { - enforceDeviceOwnerOrManageUsers(); + final CallerIdentity caller = getCallerIdentity(); + Preconditions.checkCallAuthorization(isDeviceOwner(caller) || canManageUsers(caller)); return getUserData(UserHandle.USER_SYSTEM).mLastNetworkLogsRetrievalTime; } @@ -13721,15 +13700,21 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @Override public boolean isCurrentInputMethodSetByOwner() { - enforceProfileOwnerOrSystemUser(); - return getUserData(mInjector.userHandleGetCallingUserId()).mCurrentInputMethodSet; + final CallerIdentity caller = getCallerIdentity(); + Preconditions.checkCallAuthorization(isDeviceOwner(caller) + || isProfileOwner(caller) || isSystemUid(caller), + "Only profile owner, device owner and system may call this method."); + return getUserData(caller.getUserId()).mCurrentInputMethodSet; } @Override public StringParceledListSlice getOwnerInstalledCaCerts(@NonNull UserHandle user) { final int userId = user.getIdentifier(); final CallerIdentity caller = getCallerIdentity(); - enforceProfileOwnerOrFullCrossUsersPermission(caller, userId); + Preconditions.checkCallAuthorization((userId == caller.getUserId()) + || isProfileOwner(caller) || isDeviceOwner(caller) + || hasFullCrossUsersPermission(caller, userId)); + synchronized (getLockObject()) { return new StringParceledListSlice( new ArrayList<>(getUserData(userId).mOwnerInstalledCaCerts)); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 03edc585b46a..267c9b7e40f7 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -1266,6 +1266,12 @@ public final class SystemServer implements Dumpable { inputManager = new InputManagerService(context); t.traceEnd(); + if (!disableCameraService) { + t.traceBegin("StartCameraServiceProxy"); + mSystemServiceManager.startService(CameraServiceProxy.class); + t.traceEnd(); + } + t.traceBegin("StartWindowManagerService"); // WMS needs sensor service ready ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE); @@ -2200,12 +2206,6 @@ public final class SystemServer implements Dumpable { t.traceEnd(); } - if (!disableCameraService) { - t.traceBegin("StartCameraServiceProxy"); - mSystemServiceManager.startService(CameraServiceProxy.class); - t.traceEnd(); - } - if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_EMBEDDED)) { t.traceBegin("StartIoTSystemService"); mSystemServiceManager.startService(IOT_SERVICE_CLASS); diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localbackend/AppSearchImplTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java index 081bfb5b2724..0d0ac6d2794d 100644 --- a/services/tests/servicestests/src/com/android/server/appsearch/external/localbackend/AppSearchImplTest.java +++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.appsearch.external.localbackend; +package com.android.server.appsearch.external.localstorage; import static com.google.common.truth.Truth.assertThat; diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localbackend/converter/GenericDocumentToProtoConverterTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverterTest.java index a95290d89b59..85d4f01f8d41 100644 --- a/services/tests/servicestests/src/com/android/server/appsearch/external/localbackend/converter/GenericDocumentToProtoConverterTest.java +++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverterTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.appsearch.external.localbackend.converter; +package com.android.server.appsearch.external.localstorage.converter; import static com.google.common.truth.Truth.assertThat; @@ -53,13 +53,13 @@ public class GenericDocumentToProtoConverterTest { .setScore(1) .setTtlMillis(1L) .setNamespace("namespace") - .setProperty("longKey1", 1L) - .setProperty("doubleKey1", 1.0) - .setProperty("booleanKey1", true) - .setProperty("stringKey1", "test-value1") - .setProperty("byteKey1", BYTE_ARRAY_1, BYTE_ARRAY_2) - .setProperty("documentKey1", DOCUMENT_PROPERTIES_1) - .setProperty(GenericDocument.PROPERTIES_FIELD, DOCUMENT_PROPERTIES_2) + .setPropertyLong("longKey1", 1L) + .setPropertyDouble("doubleKey1", 1.0) + .setPropertyBoolean("booleanKey1", true) + .setPropertyString("stringKey1", "test-value1") + .setPropertyBytes("byteKey1", BYTE_ARRAY_1, BYTE_ARRAY_2) + .setPropertyDocument("documentKey1", DOCUMENT_PROPERTIES_1) + .setPropertyDocument("documentKey2", DOCUMENT_PROPERTIES_2) .build(); // Create the Document proto. Need to sort the property order by key. @@ -87,8 +87,8 @@ public class GenericDocumentToProtoConverterTest { PropertyProto.newBuilder().setName("documentKey1") .addDocumentValues( GenericDocumentToProtoConverter.convert(DOCUMENT_PROPERTIES_1))); - propertyProtoMap.put(GenericDocument.PROPERTIES_FIELD, - PropertyProto.newBuilder().setName(GenericDocument.PROPERTIES_FIELD) + propertyProtoMap.put("documentKey2", + PropertyProto.newBuilder().setName("documentKey2") .addDocumentValues( GenericDocumentToProtoConverter.convert(DOCUMENT_PROPERTIES_2))); List<String> sortedKey = new ArrayList<>(propertyProtoMap.keySet()); diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localbackend/converter/SchemaToProtoConverterTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverterTest.java index 8b2fd1ce9fef..7336c3c36417 100644 --- a/services/tests/servicestests/src/com/android/server/appsearch/external/localbackend/converter/SchemaToProtoConverterTest.java +++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverterTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.appsearch.external.localbackend.converter; +package com.android.server.appsearch.external.localstorage.converter; import static com.google.common.truth.Truth.assertThat; @@ -50,7 +50,6 @@ public class SchemaToProtoConverterTest { .addProperties(PropertyConfigProto.newBuilder() .setPropertyName("subject") .setDataType(PropertyConfigProto.DataType.Code.STRING) - .setSchemaType("") .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL) .setIndexingConfig( com.android.server.appsearch.proto.IndexingConfig.newBuilder() @@ -60,7 +59,6 @@ public class SchemaToProtoConverterTest { ).addProperties(PropertyConfigProto.newBuilder() .setPropertyName("body") .setDataType(PropertyConfigProto.DataType.Code.STRING) - .setSchemaType("") .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL) .setIndexingConfig( com.android.server.appsearch.proto.IndexingConfig.newBuilder() @@ -94,7 +92,6 @@ public class SchemaToProtoConverterTest { .addProperties(PropertyConfigProto.newBuilder() .setPropertyName("artist") .setDataType(PropertyConfigProto.DataType.Code.STRING) - .setSchemaType("") .setCardinality(PropertyConfigProto.Cardinality.Code.REPEATED) .setIndexingConfig( com.android.server.appsearch.proto.IndexingConfig.newBuilder() @@ -104,7 +101,6 @@ public class SchemaToProtoConverterTest { ).addProperties(PropertyConfigProto.newBuilder() .setPropertyName("pubDate") .setDataType(PropertyConfigProto.DataType.Code.INT64) - .setSchemaType("") .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL) .setIndexingConfig( com.android.server.appsearch.proto.IndexingConfig.newBuilder() diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localbackend/converter/SnippetTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java index e9357aa60632..d5762a1317b5 100644 --- a/services/tests/servicestests/src/com/android/server/appsearch/external/localbackend/converter/SnippetTest.java +++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.appsearch.external.localbackend.converter; +package com.android.server.appsearch.external.localstorage.converter; import static com.google.common.truth.Truth.assertThat; @@ -123,7 +123,7 @@ public class SnippetTest { for (SearchResultProto.ResultProto proto : searchResultProto.getResultsList()) { SearchResult result = SearchResultToProtoConverter.convertSearchResult(proto); - assertThat(result.getMatches()).isEqualTo(null); + assertThat(result.getMatches()).isEmpty(); } } diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/Face10Test.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/Face10Test.java index 7a0d8946d179..b73a783af299 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/Face10Test.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/Face10Test.java @@ -46,6 +46,10 @@ public class Face10Test { private Face10 mFace10; private IBinder mBinder; + private static void waitForIdle() { + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + } + @Before public void setUp() { MockitoAnnotations.initMocks(this); @@ -59,11 +63,8 @@ public class Face10Test { @Test public void scheduleRevokeChallenge_doesNotCrash() { - mFace10.scheduleRevokeChallenge(mBinder, TAG); + mFace10.scheduleRevokeChallenge(0 /* sensorId */, 0 /* userId */, mBinder, TAG, + 0 /* challenge */); waitForIdle(); } - - private static void waitForIdle() { - InstrumentationRegistry.getInstrumentation().waitForIdleSync(); - } } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyConstantsTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyConstantsTest.java index be05245deea1..9660d6ba2f74 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyConstantsTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyConstantsTest.java @@ -15,33 +15,33 @@ */ package com.android.server.devicepolicy; -import android.test.AndroidTestCase; +import static com.google.common.truth.Truth.assertThat; + import android.test.suitebuilder.annotation.SmallTest; +import org.junit.Test; + /** * Test for {@link DevicePolicyConstants}. * - m FrameworksServicesTests && - adb install \ - -r ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk && - adb shell am instrument -e class com.android.server.devicepolicy.DevicePolicyConstantsTest \ - -w com.android.frameworks.servicestests - - - -w com.android.frameworks.servicestests/androidx.test.runner.AndroidJUnitRunner + * <p>Run this test with: + * + * {@code atest FrameworksServicesTests:com.android.server.devicepolicy.DevicePolicyConstantsTest} */ @SmallTest -public class DevicePolicyConstantsTest extends AndroidTestCase { +public class DevicePolicyConstantsTest { private static final String TAG = "DevicePolicyConstantsTest"; + @Test public void testDefaultValues() throws Exception { final DevicePolicyConstants constants = DevicePolicyConstants.loadFromString(""); - assertEquals(1 * 60 * 60, constants.DAS_DIED_SERVICE_RECONNECT_BACKOFF_SEC); - assertEquals(24 * 60 * 60, constants.DAS_DIED_SERVICE_RECONNECT_MAX_BACKOFF_SEC); - assertEquals(2.0, constants.DAS_DIED_SERVICE_RECONNECT_BACKOFF_INCREASE); + assertThat(constants.DAS_DIED_SERVICE_RECONNECT_BACKOFF_SEC).isEqualTo(1 * 60 * 60); + assertThat(constants.DAS_DIED_SERVICE_RECONNECT_MAX_BACKOFF_SEC).isEqualTo(24 * 60 * 60); + assertThat(constants.DAS_DIED_SERVICE_RECONNECT_BACKOFF_INCREASE).isWithin(1.0e-10).of(2.0); } + @Test public void testCustomValues() throws Exception { final DevicePolicyConstants constants = DevicePolicyConstants.loadFromString( "das_died_service_reconnect_backoff_sec=10," @@ -49,11 +49,13 @@ public class DevicePolicyConstantsTest extends AndroidTestCase { + "das_died_service_reconnect_max_backoff_sec=15" ); - assertEquals(10, constants.DAS_DIED_SERVICE_RECONNECT_BACKOFF_SEC); - assertEquals(15, constants.DAS_DIED_SERVICE_RECONNECT_MAX_BACKOFF_SEC); - assertEquals(1.25, constants.DAS_DIED_SERVICE_RECONNECT_BACKOFF_INCREASE); + assertThat(constants.DAS_DIED_SERVICE_RECONNECT_BACKOFF_SEC).isEqualTo(10); + assertThat(constants.DAS_DIED_SERVICE_RECONNECT_MAX_BACKOFF_SEC).isEqualTo(15); + assertThat(constants.DAS_DIED_SERVICE_RECONNECT_BACKOFF_INCREASE).isWithin(1.0e-10) + .of(1.25); } + @Test public void testMinMax() throws Exception { final DevicePolicyConstants constants = DevicePolicyConstants.loadFromString( "das_died_service_reconnect_backoff_sec=3," @@ -61,8 +63,8 @@ public class DevicePolicyConstantsTest extends AndroidTestCase { + "das_died_service_reconnect_max_backoff_sec=1" ); - assertEquals(5, constants.DAS_DIED_SERVICE_RECONNECT_BACKOFF_SEC); - assertEquals(5, constants.DAS_DIED_SERVICE_RECONNECT_MAX_BACKOFF_SEC); - assertEquals(1.0, constants.DAS_DIED_SERVICE_RECONNECT_BACKOFF_INCREASE); + assertThat(constants.DAS_DIED_SERVICE_RECONNECT_BACKOFF_SEC).isEqualTo(5); + assertThat(constants.DAS_DIED_SERVICE_RECONNECT_MAX_BACKOFF_SEC).isEqualTo(5); + assertThat(constants.DAS_DIED_SERVICE_RECONNECT_BACKOFF_INCREASE).isWithin(1.0e-10).of(1.0); } } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyEventLoggerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyEventLoggerTest.java index b24bca8fc050..350b390a2130 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyEventLoggerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyEventLoggerTest.java @@ -46,8 +46,8 @@ public class DevicePolicyEventLoggerTest { .setTimePeriod(1234L); assertThat(eventLogger.getEventId()).isEqualTo(5); assertThat(eventLogger.getBoolean()).isTrue(); - assertThat(eventLogger.getStringArray()) - .isEqualTo(new String[] {"string1", "string2", "string3"}); + assertThat(eventLogger.getStringArray()).asList() + .containsExactly("string1", "string2", "string3"); assertThat(eventLogger.getAdminPackageName()).isEqualTo("com.test.package"); assertThat(eventLogger.getInt()).isEqualTo(4321); assertThat(eventLogger.getTimePeriod()).isEqualTo(1234L); @@ -57,23 +57,22 @@ public class DevicePolicyEventLoggerTest { public void testStrings() { assertThat(DevicePolicyEventLogger .createEvent(0) - .setStrings("string1", "string2", "string3").getStringArray()) - .isEqualTo(new String[] {"string1", "string2", "string3"}); + .setStrings("string1", "string2", "string3").getStringArray()).asList() + .containsExactly("string1", "string2", "string3").inOrder(); assertThat(DevicePolicyEventLogger .createEvent(0) .setStrings("string1", new String[] {"string2", "string3"}).getStringArray()) - .isEqualTo(new String[] {"string1", "string2", "string3"}); + .asList().containsExactly("string1", "string2", "string3").inOrder(); assertThat(DevicePolicyEventLogger .createEvent(0) .setStrings("string1", "string2", new String[] {"string3"}).getStringArray()) - .isEqualTo(new String[] {"string1", "string2", "string3"}); - + .asList().containsExactly("string1", "string2", "string3").inOrder(); assertThat(DevicePolicyEventLogger .createEvent(0) - .setStrings((String) null).getStringArray()) - .isEqualTo(new String[] {null}); + .setStrings((String) null).getStringArray()).asList() + .containsExactly((String) null); assertThat(DevicePolicyEventLogger .createEvent(0) @@ -106,8 +105,8 @@ public class DevicePolicyEventLoggerTest { .createEvent(0); assertThat(eventLogger.getEventId()).isEqualTo(0); assertThat(eventLogger.getBoolean()).isFalse(); - assertThat(eventLogger.getStringArray()).isEqualTo(null); - assertThat(eventLogger.getAdminPackageName()).isEqualTo(null); + assertThat(eventLogger.getStringArray()).isNull(); + assertThat(eventLogger.getAdminPackageName()).isNull(); assertThat(eventLogger.getInt()).isEqualTo(0); assertThat(eventLogger.getTimePeriod()).isEqualTo(0L); } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java index 3167820f0a48..fa3f45c08202 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java @@ -20,7 +20,9 @@ import static android.os.UserHandle.USER_SYSTEM; import static com.android.server.devicepolicy.DpmTestUtils.writeInputStreamToFile; import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; -import static org.junit.Assert.assertArrayEquals; +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; @@ -43,17 +45,23 @@ import android.platform.test.annotations.Presubmit; import android.provider.Settings; import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; import com.android.frameworks.servicestests.R; import com.android.server.LocalServices; import com.android.server.SystemService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + import java.io.File; import java.util.HashMap; import java.util.Map; import java.util.Set; @Presubmit +@RunWith(AndroidJUnit4.class) public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { private static final String USER_TYPE_EMPTY = ""; @@ -63,9 +71,8 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { private DpmMockContext mContext; - @Override - protected void setUp() throws Exception { - super.setUp(); + @Before + public void setUp() throws Exception { mContext = getContext(); @@ -77,6 +84,7 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { .thenReturn(true); } + @Test public void testMigration() throws Exception { final File user10dir = getServices().addUser(10, 0, USER_TYPE_EMPTY); final File user11dir = getServices().addUser(11, 0, @@ -160,19 +168,19 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { mContext.binder.restoreCallingIdentity(ident); } - assertTrue(dpms.mOwners.hasDeviceOwner()); - assertFalse(dpms.mOwners.hasProfileOwner(USER_SYSTEM)); - assertTrue(dpms.mOwners.hasProfileOwner(10)); - assertTrue(dpms.mOwners.hasProfileOwner(11)); - assertFalse(dpms.mOwners.hasProfileOwner(12)); + assertThat(dpms.mOwners.hasDeviceOwner()).isTrue(); + assertThat(dpms.mOwners.hasProfileOwner(USER_SYSTEM)).isFalse(); + assertThat(dpms.mOwners.hasProfileOwner(10)).isTrue(); + assertThat(dpms.mOwners.hasProfileOwner(11)).isTrue(); + assertThat(dpms.mOwners.hasProfileOwner(12)).isFalse(); // Now all information should be migrated. - assertFalse(dpms.mOwners.getDeviceOwnerUserRestrictionsNeedsMigration()); - assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration( - USER_SYSTEM)); - assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(10)); - assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(11)); - assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(12)); + assertThat(dpms.mOwners.getDeviceOwnerUserRestrictionsNeedsMigration()).isFalse(); + assertThat(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(USER_SYSTEM)) + .isFalse(); + assertThat(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isFalse(); + assertThat(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isFalse(); + assertThat(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(12)).isFalse(); // Check the new base restrictions. DpmTestUtils.assertRestrictions( @@ -221,6 +229,7 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { dpms.getProfileOwnerAdminLocked(11).ensureUserRestrictions()); } + @Test public void testMigration2_profileOwnerOnUser0() throws Exception { setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_SYSTEM_USER_UID); @@ -271,13 +280,13 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { } finally { mContext.binder.restoreCallingIdentity(ident); } - assertFalse(dpms.mOwners.hasDeviceOwner()); - assertTrue(dpms.mOwners.hasProfileOwner(USER_SYSTEM)); + assertThat(dpms.mOwners.hasDeviceOwner()).isFalse(); + assertThat(dpms.mOwners.hasProfileOwner(USER_SYSTEM)).isTrue(); // Now all information should be migrated. - assertFalse(dpms.mOwners.getDeviceOwnerUserRestrictionsNeedsMigration()); - assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration( - USER_SYSTEM)); + assertThat(dpms.mOwners.getDeviceOwnerUserRestrictionsNeedsMigration()).isFalse(); + assertThat(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(USER_SYSTEM)) + .isFalse(); // Check the new base restrictions. DpmTestUtils.assertRestrictions( @@ -297,6 +306,7 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { } // Test setting default restrictions for managed profile. + @Test public void testMigration3_managedProfileOwner() throws Exception { // Create a managed profile user. final File user10dir = getServices().addUser(10, 0, @@ -339,8 +349,8 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { mContext.binder.restoreCallingIdentity(ident); } - assertFalse(dpms.mOwners.hasDeviceOwner()); - assertTrue(dpms.mOwners.hasProfileOwner(10)); + assertThat(dpms.mOwners.hasDeviceOwner()).isFalse(); + assertThat(dpms.mOwners.hasProfileOwner(10)).isTrue(); // Check that default restrictions were applied. DpmTestUtils.assertRestrictions( @@ -352,11 +362,12 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { final Set<String> alreadySet = dpms.getProfileOwnerAdminLocked(10).defaultEnabledRestrictionsAlreadySet; - assertEquals(alreadySet.size(), 1); - assertTrue(alreadySet.contains(UserManager.DISALLOW_BLUETOOTH_SHARING)); + assertThat(alreadySet).hasSize(1); + assertThat(alreadySet.contains(UserManager.DISALLOW_BLUETOOTH_SHARING)).isTrue(); } @SmallTest + @Test public void testCompMigrationUnAffiliated_skipped() throws Exception { prepareAdmin1AsDo(); prepareAdminAnotherPackageAsPo(COPE_PROFILE_USER_ID); @@ -364,10 +375,11 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { final DevicePolicyManagerServiceTestable dpms = bootDpmsUp(); // DO should still be DO since no migration should happen. - assertTrue(dpms.mOwners.hasDeviceOwner()); + assertThat(dpms.mOwners.hasDeviceOwner()).isTrue(); } @SmallTest + @Test public void testCompMigrationAffiliated() throws Exception { prepareAdmin1AsDo(); prepareAdmin1AsPo(COPE_PROFILE_USER_ID, Build.VERSION_CODES.R); @@ -378,48 +390,54 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { final DevicePolicyManagerServiceTestable dpms = bootDpmsUp(); // DO should cease to be DO. - assertFalse(dpms.mOwners.hasDeviceOwner()); + assertThat(dpms.mOwners.hasDeviceOwner()).isFalse(); final DpmMockContext poContext = new DpmMockContext(getServices(), mRealTestContext); poContext.binder.callingUid = UserHandle.getUid(COPE_PROFILE_USER_ID, COPE_ADMIN1_APP_ID); runAsCaller(poContext, dpms, dpm -> { - assertEquals("Password history policy wasn't migrated to PO parent instance", - 33, dpm.getParentProfileInstance(admin1).getPasswordHistoryLength(admin1)); - assertEquals("Password history policy was put into non-parent PO instance", - 0, dpm.getPasswordHistoryLength(admin1)); - assertTrue("Screen capture restriction wasn't migrated to PO parent instance", - dpm.getParentProfileInstance(admin1).getScreenCaptureDisabled(admin1)); - - assertArrayEquals("Accounts with management disabled weren't migrated to PO parent", - new String[] {"com.google-primary"}, - dpm.getParentProfileInstance(admin1).getAccountTypesWithManagementDisabled()); - assertArrayEquals("Accounts with management disabled for profile were lost", - new String[] {"com.google-profile"}, - dpm.getAccountTypesWithManagementDisabled()); - - assertTrue("User restriction wasn't migrated to PO parent instance", - dpm.getParentProfileInstance(admin1).getUserRestrictions(admin1) - .containsKey(UserManager.DISALLOW_BLUETOOTH)); - assertFalse("User restriction was put into non-parent PO instance", - dpm.getUserRestrictions(admin1).containsKey(UserManager.DISALLOW_BLUETOOTH)); - - assertTrue("User restriction wasn't migrated to PO parent instance", - dpms.getProfileOwnerAdminLocked(COPE_PROFILE_USER_ID) - .getParentActiveAdmin() - .getEffectiveRestrictions() - .containsKey(UserManager.DISALLOW_CONFIG_DATE_TIME)); - assertFalse("User restriction was put into non-parent PO instance", - dpms.getProfileOwnerAdminLocked(COPE_PROFILE_USER_ID) - .getEffectiveRestrictions() - .containsKey(UserManager.DISALLOW_CONFIG_DATE_TIME)); - assertEquals("Personal apps suspension wasn't migrated", - DevicePolicyManager.PERSONAL_APPS_NOT_SUSPENDED, - dpm.getPersonalAppsSuspendedReasons(admin1)); + assertWithMessage("Password history policy wasn't migrated to PO parent instance") + .that(dpm.getParentProfileInstance(admin1).getPasswordHistoryLength(admin1)) + .isEqualTo(33); + assertWithMessage("Password history policy was put into non-parent PO instance") + .that(dpm.getPasswordHistoryLength(admin1)).isEqualTo(0); + assertWithMessage("Screen capture restriction wasn't migrated to PO parent instance") + .that(dpm.getParentProfileInstance(admin1).getScreenCaptureDisabled(admin1)) + .isTrue(); + + assertWithMessage("Accounts with management disabled weren't migrated to PO parent") + .that(dpm.getParentProfileInstance(admin1) + .getAccountTypesWithManagementDisabled()).asList() + .containsExactly("com.google-primary"); + + assertWithMessage("Accounts with management disabled for profile were lost") + .that(dpm.getAccountTypesWithManagementDisabled()).asList() + .containsExactly("com.google-profile"); + + assertWithMessage("User restriction wasn't migrated to PO parent instance") + .that(dpm.getParentProfileInstance(admin1).getUserRestrictions(admin1).keySet()) + .contains(UserManager.DISALLOW_BLUETOOTH); + + assertWithMessage("User restriction was put into non-parent PO instance").that( + dpm.getUserRestrictions(admin1).keySet()) + .doesNotContain(UserManager.DISALLOW_BLUETOOTH); + + assertWithMessage("User restriction wasn't migrated to PO parent instance") + .that(dpms.getProfileOwnerAdminLocked(COPE_PROFILE_USER_ID) + .getParentActiveAdmin().getEffectiveRestrictions().keySet()) + .contains(UserManager.DISALLOW_CONFIG_DATE_TIME); + assertWithMessage("User restriction was put into non-parent PO instance") + .that(dpms.getProfileOwnerAdminLocked(COPE_PROFILE_USER_ID) + .getEffectiveRestrictions().keySet()) + .doesNotContain(UserManager.DISALLOW_CONFIG_DATE_TIME); + assertWithMessage("Personal apps suspension wasn't migrated") + .that(dpm.getPersonalAppsSuspendedReasons(admin1)) + .isEqualTo(DevicePolicyManager.PERSONAL_APPS_NOT_SUSPENDED); }); } @SmallTest + @Test public void testCompMigration_keepSuspendedAppsWhenDpcIsRPlus() throws Exception { prepareAdmin1AsDo(); prepareAdmin1AsPo(COPE_PROFILE_USER_ID, Build.VERSION_CODES.R); @@ -445,13 +463,14 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { poContext.binder.callingUid = UserHandle.getUid(COPE_PROFILE_USER_ID, COPE_ADMIN1_APP_ID); runAsCaller(poContext, dpms, dpm -> { - assertEquals("Personal apps suspension wasn't migrated", - DevicePolicyManager.PERSONAL_APPS_SUSPENDED_EXPLICITLY, - dpm.getPersonalAppsSuspendedReasons(admin1)); + assertWithMessage("Personal apps suspension wasn't migrated") + .that(dpm.getPersonalAppsSuspendedReasons(admin1)) + .isEqualTo(DevicePolicyManager.PERSONAL_APPS_SUSPENDED_EXPLICITLY); }); } @SmallTest + @Test public void testCompMigration_unsuspendAppsWhenDpcNotRPlus() throws Exception { prepareAdmin1AsDo(); prepareAdmin1AsPo(COPE_PROFILE_USER_ID, Build.VERSION_CODES.Q); @@ -470,9 +489,9 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { poContext.binder.callingUid = UserHandle.getUid(COPE_PROFILE_USER_ID, COPE_ADMIN1_APP_ID); runAsCaller(poContext, dpms, dpm -> { - assertEquals("Personal apps weren't unsuspended", - DevicePolicyManager.PERSONAL_APPS_NOT_SUSPENDED, - dpm.getPersonalAppsSuspendedReasons(admin1)); + assertWithMessage("Personal apps weren't unsuspended") + .that(dpm.getPersonalAppsSuspendedReasons(admin1)) + .isEqualTo(DevicePolicyManager.PERSONAL_APPS_NOT_SUSPENDED); }); } 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 c4f7b9547277..8d7bc16fcf56 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -39,7 +39,9 @@ import static com.android.server.devicepolicy.DpmMockContext.CALLER_USER_HANDLE; import static com.android.server.testutils.TestUtils.assertExpectException; import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; +import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyInt; @@ -89,13 +91,14 @@ import android.os.Bundle; import android.os.Process; import android.os.UserHandle; import android.os.UserManager; +import android.platform.test.annotations.FlakyTest; import android.platform.test.annotations.Presubmit; import android.provider.Settings; import android.security.KeyChain; import android.security.keystore.AttestationUtils; import android.telephony.TelephonyManager; import android.telephony.data.ApnSetting; -import android.test.MoreAsserts; +import android.test.MoreAsserts; // TODO(b/171932723): replace by Truth import android.util.ArraySet; import android.util.Pair; @@ -111,6 +114,9 @@ import com.android.server.devicepolicy.DevicePolicyManagerService.RestrictionsLi import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.hamcrest.Matcher; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; import org.mockito.Mockito; import org.mockito.internal.util.collections.Sets; import org.mockito.stubbing.Answer; @@ -127,17 +133,11 @@ import java.util.concurrent.TimeUnit; /** * Tests for DevicePolicyManager( and DevicePolicyManagerService). - * You can run them via: - m FrameworksServicesTests && - adb install \ - -r ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk && - adb shell am instrument -e class com.android.server.devicepolicy.DevicePolicyManagerTest \ - -w com.android.frameworks.servicestests/androidx.test.runner.AndroidJUnitRunner - - (mmma frameworks/base/services/tests/servicestests/ for non-ninja build) * - * , or: - * runtest -c com.android.server.devicepolicy.DevicePolicyManagerTest frameworks-services + * <p>Run this test with: + * + * {@code atest FrameworksServicesTests:com.android.server.devicepolicy.DevicePolicyManagerTest} + * */ @SmallTest @Presubmit @@ -205,9 +205,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { private static final String PROFILE_OFF_SUSPENSION_TEXT = "suspension_text"; private static final String PROFILE_OFF_SUSPENSION_SOON_TEXT = "suspension_tomorrow_text"; - @Override - protected void setUp() throws Exception { - super.setUp(); + @Before + public void setUp() throws Exception { mContext = getContext(); mServiceContext = mContext; @@ -251,11 +250,10 @@ public class DevicePolicyManagerTest extends DpmTestBase { return dpms.mTransferOwnershipMetadataManager; } - @Override - protected void tearDown() throws Exception { + @After + public void tearDown() throws Exception { flushTasks(dpms); getMockTransferMetadataManager().deleteMetadataFile(); - super.tearDown(); } private void initializeDpms() { @@ -336,14 +334,15 @@ public class DevicePolicyManagerTest extends DpmTestBase { // PO needs to be a DA. dpm.setActiveAdmin(admin, /*replace=*/ false); // Fire! - assertTrue(dpm.setProfileOwner(admin, "owner-name", CALLER_USER_HANDLE)); + assertThat(dpm.setProfileOwner(admin, "owner-name", CALLER_USER_HANDLE)).isTrue(); // Check - assertEquals(admin, dpm.getProfileOwnerAsUser(CALLER_USER_HANDLE)); + assertThat(dpm.getProfileOwnerAsUser(CALLER_USER_HANDLE)).isEqualTo(admin); }); mServiceContext.binder.restoreCallingIdentity(ident); } + @Test public void testHasNoFeature() throws Exception { when(getServices().packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN))) .thenReturn(false); @@ -352,9 +351,10 @@ public class DevicePolicyManagerTest extends DpmTestBase { new DevicePolicyManagerServiceTestable(getServices(), mContext); // If the device has no DPMS feature, it shouldn't register the local service. - assertNull(LocalServices.getService(DevicePolicyManagerInternal.class)); + assertThat(LocalServices.getService(DevicePolicyManagerInternal.class)).isNull(); } + @Test public void testLoadAdminData() throws Exception { // Device owner in SYSTEM_USER setDeviceOwner(); @@ -365,7 +365,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { final int ANOTHER_UID = UserHandle.getUid(CALLER_USER_HANDLE, 1306); setUpPackageManagerForFakeAdmin(adminAnotherPackage, ANOTHER_UID, admin2); dpm.setActiveAdmin(adminAnotherPackage, /* replace =*/ false, CALLER_USER_HANDLE); - assertTrue(dpm.isAdminActiveAsUser(adminAnotherPackage, CALLER_USER_HANDLE)); + assertThat(dpm.isAdminActiveAsUser(adminAnotherPackage, CALLER_USER_HANDLE)).isTrue(); initializeDpms(); @@ -381,6 +381,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(getServices().networkPolicyManagerInternal).onAdminDataAvailable(); } + @Test public void testLoadAdminData_noAdmins() throws Exception { final int ANOTHER_USER_ID = 15; getServices().addUser(ANOTHER_USER_ID, 0, ""); @@ -399,6 +400,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { /** * Caller doesn't have proper permissions. */ + @Test public void testSetActiveAdmin_SecurityException() { // 1. Failure cases. @@ -422,6 +424,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { * {@link DevicePolicyManager#getActiveAdmins} * {@link DevicePolicyManager#getActiveAdminsAsUser} */ + @Test public void testSetActiveAdmin() throws Exception { // 1. Make sure the caller has proper permissions. mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); @@ -456,9 +459,9 @@ public class DevicePolicyManagerTest extends DpmTestBase { // TODO Verify other calls too. // Make sure it's active admin1. - assertTrue(dpm.isAdminActive(admin1)); - assertFalse(dpm.isAdminActive(admin2)); - assertFalse(dpm.isAdminActive(admin3)); + assertThat(dpm.isAdminActive(admin1)).isTrue(); + assertThat(dpm.isAdminActive(admin2)).isFalse(); + assertThat(dpm.isAdminActive(admin3)).isFalse(); // But not admin1 for a different user. @@ -466,8 +469,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { // (Because we're checking a different user's status from CALLER_USER_HANDLE.) mContext.callerPermissions.add("android.permission.INTERACT_ACROSS_USERS_FULL"); - assertFalse(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE + 1)); - assertFalse(dpm.isAdminActiveAsUser(admin2, CALLER_USER_HANDLE + 1)); + assertThat(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE + 1)).isFalse(); + assertThat(dpm.isAdminActiveAsUser(admin2, CALLER_USER_HANDLE + 1)).isFalse(); mContext.callerPermissions.remove("android.permission.INTERACT_ACROSS_USERS_FULL"); @@ -479,9 +482,9 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm.setActiveAdmin(admin2, /* replace =*/ false); // Now we have two admins. - assertTrue(dpm.isAdminActive(admin1)); - assertTrue(dpm.isAdminActive(admin2)); - assertFalse(dpm.isAdminActive(admin3)); + assertThat(dpm.isAdminActive(admin1)).isTrue(); + assertThat(dpm.isAdminActive(admin2)).isTrue(); + assertThat(dpm.isAdminActive(admin3)).isFalse(); // Admin2 was already enabled, so setApplicationEnabledSetting() shouldn't have called // again. (times(1) because it was previously called for admin1) @@ -508,9 +511,9 @@ public class DevicePolicyManagerTest extends DpmTestBase { // 6. Test getActiveAdmins() List<ComponentName> admins = dpm.getActiveAdmins(); - assertEquals(2, admins.size()); - assertEquals(admin1, admins.get(0)); - assertEquals(admin2, admins.get(1)); + assertThat(admins.size()).isEqualTo(2); + assertThat(admins.get(0)).isEqualTo(admin1); + assertThat(admins.get(1)).isEqualTo(admin2); // There shouldn't be any callback to UsageStatsManagerInternal when the admin is being // replaced @@ -519,12 +522,13 @@ public class DevicePolicyManagerTest extends DpmTestBase { // Another user has no admins. mContext.callerPermissions.add("android.permission.INTERACT_ACROSS_USERS_FULL"); - assertEquals(0, DpmTestUtils.getListSizeAllowingNull( - dpm.getActiveAdminsAsUser(CALLER_USER_HANDLE + 1))); + assertThat(DpmTestUtils.getListSizeAllowingNull( + dpm.getActiveAdminsAsUser(CALLER_USER_HANDLE + 1))).isEqualTo(0); mContext.callerPermissions.remove("android.permission.INTERACT_ACROSS_USERS_FULL"); } + @Test public void testSetActiveAdmin_multiUsers() throws Exception { final int ANOTHER_USER_ID = 100; @@ -544,12 +548,12 @@ public class DevicePolicyManagerTest extends DpmTestBase { mMockContext.binder.callingUid = DpmMockContext.CALLER_UID; - assertTrue(dpm.isAdminActive(admin1)); - assertFalse(dpm.isAdminActive(admin2)); + assertThat(dpm.isAdminActive(admin1)).isTrue(); + assertThat(dpm.isAdminActive(admin2)).isFalse(); mMockContext.binder.callingUid = ANOTHER_ADMIN_UID; - assertFalse(dpm.isAdminActive(admin1)); - assertTrue(dpm.isAdminActive(admin2)); + assertThat(dpm.isAdminActive(admin1)).isFalse(); + assertThat(dpm.isAdminActive(admin2)).isTrue(); } /** @@ -557,12 +561,13 @@ public class DevicePolicyManagerTest extends DpmTestBase { * {@link DevicePolicyManager#setActiveAdmin} * with replace=false */ + @Test public void testSetActiveAdmin_twiceWithoutReplace() throws Exception { // 1. Make sure the caller has proper permissions. mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); dpm.setActiveAdmin(admin1, /* replace =*/ false); - assertTrue(dpm.isAdminActive(admin1)); + assertThat(dpm.isAdminActive(admin1)).isTrue(); // Add the same admin1 again without replace, which should throw. assertExpectException(IllegalArgumentException.class, /* messageRegex= */ null, @@ -574,6 +579,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { * {@link DevicePolicyManager#setActiveAdmin} when the admin isn't protected with * BIND_DEVICE_ADMIN. */ + @Test public void testSetActiveAdmin_permissionCheck() throws Exception { // 1. Make sure the caller has proper permissions. mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); @@ -581,13 +587,13 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertExpectException(IllegalArgumentException.class, /* messageRegex= */ permission.BIND_DEVICE_ADMIN, () -> dpm.setActiveAdmin(adminNoPerm, /* replace =*/ false)); - assertFalse(dpm.isAdminActive(adminNoPerm)); + assertThat(dpm.isAdminActive(adminNoPerm)).isFalse(); // Change the target API level to MNC. Now it can be set as DA. setUpPackageManagerForAdmin(adminNoPerm, DpmMockContext.CALLER_UID, null, VERSION_CODES.M); dpm.setActiveAdmin(adminNoPerm, /* replace =*/ false); - assertTrue(dpm.isAdminActive(adminNoPerm)); + assertThat(dpm.isAdminActive(adminNoPerm)).isTrue(); // TODO Test the "load from the file" case where DA will still be loaded even without // BIND_DEVICE_ADMIN and target API is N. @@ -597,6 +603,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { * Test for: * {@link DevicePolicyManager#removeActiveAdmin} */ + @Test public void testRemoveActiveAdmin_SecurityException() { mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); @@ -604,9 +611,9 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm.setActiveAdmin(admin1, /* replace =*/ false); - assertTrue(dpm.isAdminActive(admin1)); + assertThat(dpm.isAdminActive(admin1)).isTrue(); - assertFalse(dpm.isRemovingAdmin(admin1, CALLER_USER_HANDLE)); + assertThat(dpm.isRemovingAdmin(admin1, CALLER_USER_HANDLE)).isFalse(); // Directly call the DPMS method with a different userid, which should fail. assertExpectException(SecurityException.class, /* messageRegex =*/ null, @@ -627,6 +634,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { * {@link DevicePolicyManager#removeActiveAdmin} should fail with the user is not unlocked * (because we can't send the remove broadcast). */ + @Test public void testRemoveActiveAdmin_userNotRunningOrLocked() { mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); @@ -636,9 +644,9 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm.setActiveAdmin(admin1, /* replace =*/ false); - assertTrue(dpm.isAdminActive(admin1)); + assertThat(dpm.isAdminActive(admin1)).isTrue(); - assertFalse(dpm.isRemovingAdmin(admin1, CALLER_USER_HANDLE)); + assertThat(dpm.isRemovingAdmin(admin1, CALLER_USER_HANDLE)).isFalse(); // 1. User not unlocked. setUserUnlocked(CALLER_USER_HANDLE, false); @@ -646,7 +654,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { /* messageRegex= */ "User must be running and unlocked", () -> dpm.removeActiveAdmin(admin1)); - assertFalse(dpm.isRemovingAdmin(admin1, CALLER_USER_HANDLE)); + assertThat(dpm.isRemovingAdmin(admin1, CALLER_USER_HANDLE)).isFalse(); verify(getServices().usageStatsManagerInternal, times(0)).setActiveAdminApps( null, CALLER_USER_HANDLE); @@ -654,7 +662,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { setUserUnlocked(CALLER_USER_HANDLE, true); dpm.removeActiveAdmin(admin1); - assertFalse(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE)); + assertThat(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE)).isFalse(); verify(getServices().usageStatsManagerInternal).setActiveAdminApps( null, CALLER_USER_HANDLE); } @@ -663,6 +671,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { * Test for: * {@link DevicePolicyManager#removeActiveAdmin} */ + @Test public void testRemoveActiveAdmin_fromDifferentUserWithINTERACT_ACROSS_USERS_FULL() { mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); @@ -670,8 +679,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm.setActiveAdmin(admin1, /* replace =*/ false); - assertTrue(dpm.isAdminActive(admin1)); - assertFalse(dpm.isRemovingAdmin(admin1, CALLER_USER_HANDLE)); + assertThat(dpm.isAdminActive(admin1)).isTrue(); + assertThat(dpm.isRemovingAdmin(admin1, CALLER_USER_HANDLE)).isFalse(); // Different user, but should work, because caller has proper permissions. mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL); @@ -680,7 +689,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.binder.callingUid = 1234567; dpms.removeActiveAdmin(admin1, CALLER_USER_HANDLE); - assertFalse(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE)); + assertThat(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE)).isFalse(); verify(getServices().usageStatsManagerInternal).setActiveAdminApps( null, CALLER_USER_HANDLE); @@ -691,6 +700,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { * Test for: * {@link DevicePolicyManager#removeActiveAdmin} */ + @Test public void testRemoveActiveAdmin_sameUserNoMANAGE_DEVICE_ADMINS() { // Need MANAGE_DEVICE_ADMINS for setActiveAdmin. We'll remove it later. mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); @@ -699,8 +709,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm.setActiveAdmin(admin1, /* replace =*/ false); - assertTrue(dpm.isAdminActive(admin1)); - assertFalse(dpm.isRemovingAdmin(admin1, CALLER_USER_HANDLE)); + assertThat(dpm.isAdminActive(admin1)).isTrue(); + assertThat(dpm.isRemovingAdmin(admin1, CALLER_USER_HANDLE)).isFalse(); // Broadcast from saveSettingsLocked(). verify(mContext.spiedContext, times(1)).sendBroadcastAsUser( @@ -725,7 +735,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { isNull(String.class), isNull(Bundle.class)); - assertFalse(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE)); + assertThat(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE)).isFalse(); verify(getServices().usageStatsManagerInternal).setActiveAdminApps( null, CALLER_USER_HANDLE); @@ -738,6 +748,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { // TODO Check other internal calls. } + @Test public void testRemoveActiveAdmin_multipleAdminsInUser() { // Need MANAGE_DEVICE_ADMINS for setActiveAdmin. We'll remove it later. mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); @@ -745,14 +756,14 @@ public class DevicePolicyManagerTest extends DpmTestBase { // Add admin1. dpm.setActiveAdmin(admin1, /* replace =*/ false); - assertTrue(dpm.isAdminActive(admin1)); - assertFalse(dpm.isRemovingAdmin(admin1, CALLER_USER_HANDLE)); + assertThat(dpm.isAdminActive(admin1)).isTrue(); + assertThat(dpm.isRemovingAdmin(admin1, CALLER_USER_HANDLE)).isFalse(); // Add admin2. dpm.setActiveAdmin(admin2, /* replace =*/ false); - assertTrue(dpm.isAdminActive(admin2)); - assertFalse(dpm.isRemovingAdmin(admin2, CALLER_USER_HANDLE)); + assertThat(dpm.isAdminActive(admin2)).isTrue(); + assertThat(dpm.isRemovingAdmin(admin2, CALLER_USER_HANDLE)).isFalse(); // Broadcast from saveSettingsLocked(). verify(mContext.spiedContext, times(2)).sendBroadcastAsUser( @@ -777,7 +788,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { isNull(String.class), isNull(Bundle.class)); - assertFalse(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE)); + assertThat(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE)).isFalse(); verify(getServices().usageStatsManagerInternal).setActiveAdminApps( MockUtils.checkApps(admin2.getPackageName()), eq(CALLER_USER_HANDLE)); @@ -793,6 +804,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { * Test for: * {@link DevicePolicyManager#forceRemoveActiveAdmin(ComponentName, int)} */ + @Test public void testForceRemoveActiveAdmin() throws Exception { mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); @@ -802,7 +814,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { /* appId= */ 10138, /* flags= */ ApplicationInfo.FLAG_TEST_ONLY); dpm.setActiveAdmin(admin1, /* replace =*/ false); - assertTrue(dpm.isAdminActive(admin1)); + assertThat(dpm.isAdminActive(admin1)).isTrue(); // Calling from a non-shell uid should fail with a SecurityException mContext.binder.callingUid = 123456; @@ -815,7 +827,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.callerPermissions.add(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL); // Verify - assertFalse(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE)); + assertThat(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE)).isFalse(); verify(getServices().usageStatsManagerInternal).setActiveAdminApps( null, CALLER_USER_HANDLE); } @@ -825,6 +837,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { * * Validates that when the password history length is set, it is persisted after rebooting */ + @Test public void testSaveAndLoadPasswordHistoryLength_persistedAfterReboot() throws Exception { int passwordHistoryLength = 2; @@ -842,13 +855,13 @@ public class DevicePolicyManagerTest extends DpmTestBase { // Save password history length dpm.setPasswordHistoryLength(admin1, passwordHistoryLength); - assertEquals(dpm.getPasswordHistoryLength(admin1), passwordHistoryLength); + assertThat(passwordHistoryLength).isEqualTo(dpm.getPasswordHistoryLength(admin1)); initializeDpms(); reset(mContext.spiedContext); // Password history length should persist after rebooted - assertEquals(dpm.getPasswordHistoryLength(admin1), passwordHistoryLength); + assertThat(passwordHistoryLength).isEqualTo(dpm.getPasswordHistoryLength(admin1)); } /** @@ -858,6 +871,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { * {@link DeviceAdminReceiver#ACTION_PASSWORD_CHANGED} is sent to managed profile owners, in * addition to ones in the original user. */ + @Test public void testSetActivePasswordState_sendToProfiles() throws Exception { mContext.callerPermissions.add(permission.BIND_DEVICE_ADMIN); @@ -893,6 +907,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { * intent {@link DeviceAdminReceiver#ACTION_PASSWORD_CHANGED} is only sent to the profile, not * its parent. */ + @Test public void testSetActivePasswordState_notSentToParent() throws Exception { mContext.callerPermissions.add(permission.BIND_DEVICE_ADMIN); @@ -932,6 +947,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { /** * Test for: {@link DevicePolicyManager#setDeviceOwner} DO on system user installs successfully. */ + @Test public void testSetDeviceOwner() throws Exception { setDeviceOwner(); @@ -944,7 +960,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { // DO admin can't be deactivated. dpm.removeActiveAdmin(admin1); - assertTrue(dpm.isAdminActive(admin1)); + assertThat(dpm.isAdminActive(admin1)).isTrue(); // TODO Test getDeviceOwnerName() too. To do so, we need to change // DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable. @@ -969,19 +985,19 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm.setActiveAdmin(admin1, /* replace =*/ false); // Fire! - assertTrue(dpm.setDeviceOwner(admin1, "owner-name")); + assertThat(dpm.setDeviceOwner(admin1, "owner-name")).isTrue(); // getDeviceOwnerComponent should return the admin1 component. - assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser()); - assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser()); + assertThat(dpm.getDeviceOwnerComponentOnCallingUser()).isEqualTo(admin1); + assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(admin1); // Check various get APIs. checkGetDeviceOwnerInfoApi(dpm, /* hasDeviceOwner =*/ true); // getDeviceOwnerComponent should *NOT* return the admin1 component for other users. mContext.binder.callingUid = DpmMockContext.CALLER_UID; - assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser()); - assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser()); + assertThat(dpm.getDeviceOwnerComponentOnCallingUser()).isEqualTo(null); + assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(admin1); mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; @@ -997,7 +1013,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { MockUtils.checkIntentAction(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED), MockUtils.checkUserHandle(UserHandle.USER_SYSTEM)); - assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser()); + assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(admin1); } private void checkGetDeviceOwnerInfoApi(DevicePolicyManager dpm, boolean hasDeviceOwner) { @@ -1012,89 +1028,89 @@ public class DevicePolicyManagerTest extends DpmTestBase { // TODO Test getDeviceOwnerName() too. To do so, we need to change // DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable. if (hasDeviceOwner) { - assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName())); - assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())); - assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser()); + assertThat(dpm.isDeviceOwnerApp(admin1.getPackageName())).isTrue(); + assertThat(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())).isTrue(); + assertThat(dpm.getDeviceOwnerComponentOnCallingUser()).isEqualTo(admin1); - assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())); - assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser()); - assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId()); + assertThat(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())).isTrue(); + assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(admin1); + assertThat(dpm.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_SYSTEM); } else { - assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName())); - assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())); - assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser()); + assertThat(dpm.isDeviceOwnerApp(admin1.getPackageName())).isFalse(); + assertThat(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())).isFalse(); + assertThat(dpm.getDeviceOwnerComponentOnCallingUser()).isEqualTo(null); - assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())); - assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser()); - assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId()); + assertThat(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())).isFalse(); + assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(null); + assertThat(dpm.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL); } mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; if (hasDeviceOwner) { - assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName())); - assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())); - assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser()); + assertThat(dpm.isDeviceOwnerApp(admin1.getPackageName())).isTrue(); + assertThat(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())).isTrue(); + assertThat(dpm.getDeviceOwnerComponentOnCallingUser()).isEqualTo(admin1); - assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())); - assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser()); - assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId()); + assertThat(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())).isTrue(); + assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(admin1); + assertThat(dpm.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_SYSTEM); } else { - assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName())); - assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())); - assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser()); + assertThat(dpm.isDeviceOwnerApp(admin1.getPackageName())).isFalse(); + assertThat(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())).isFalse(); + assertThat(dpm.getDeviceOwnerComponentOnCallingUser()).isEqualTo(null); - assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())); - assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser()); - assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId()); + assertThat(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())).isFalse(); + assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(null); + assertThat(dpm.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL); } mContext.binder.callingUid = DpmMockContext.CALLER_UID; // Still with MANAGE_USERS. - assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName())); - assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())); - assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser()); + assertThat(dpm.isDeviceOwnerApp(admin1.getPackageName())).isFalse(); + assertThat(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())).isFalse(); + assertThat(dpm.getDeviceOwnerComponentOnCallingUser()).isEqualTo(null); if (hasDeviceOwner) { - assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())); - assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser()); - assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId()); + assertThat(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())).isTrue(); + assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(admin1); + assertThat(dpm.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_SYSTEM); } else { - assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())); - assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser()); - assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId()); + assertThat(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())).isFalse(); + assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(null); + assertThat(dpm.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL); } mContext.binder.callingUid = Process.SYSTEM_UID; mContext.callerPermissions.remove(permission.MANAGE_USERS); // System can still call "OnAnyUser" without MANAGE_USERS. if (hasDeviceOwner) { - assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName())); - assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())); - assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser()); + assertThat(dpm.isDeviceOwnerApp(admin1.getPackageName())).isTrue(); + assertThat(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())).isTrue(); + assertThat(dpm.getDeviceOwnerComponentOnCallingUser()).isEqualTo(admin1); - assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())); - assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser()); - assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId()); + assertThat(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())).isTrue(); + assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(admin1); + assertThat(dpm.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_SYSTEM); } else { - assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName())); - assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())); - assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser()); + assertThat(dpm.isDeviceOwnerApp(admin1.getPackageName())).isFalse(); + assertThat(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())).isFalse(); + assertThat(dpm.getDeviceOwnerComponentOnCallingUser()).isEqualTo(null); - assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())); - assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser()); - assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId()); + assertThat(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())).isFalse(); + assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(null); + assertThat(dpm.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL); } mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; // Still no MANAGE_USERS. if (hasDeviceOwner) { - assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName())); - assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())); - assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser()); + assertThat(dpm.isDeviceOwnerApp(admin1.getPackageName())).isTrue(); + assertThat(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())).isTrue(); + assertThat(dpm.getDeviceOwnerComponentOnCallingUser()).isEqualTo(admin1); } else { - assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName())); - assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())); - assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser()); + assertThat(dpm.isDeviceOwnerApp(admin1.getPackageName())).isFalse(); + assertThat(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())).isFalse(); + assertThat(dpm.getDeviceOwnerComponentOnCallingUser()).isEqualTo(null); } assertExpectException(SecurityException.class, /* messageRegex =*/ null, @@ -1108,9 +1124,9 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.binder.callingUid = DpmMockContext.CALLER_UID; // Still no MANAGE_USERS. - assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName())); - assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())); - assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser()); + assertThat(dpm.isDeviceOwnerApp(admin1.getPackageName())).isFalse(); + assertThat(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())).isFalse(); + assertThat(dpm.getDeviceOwnerComponentOnCallingUser()).isEqualTo(null); assertExpectException(SecurityException.class, /* messageRegex =*/ null, () -> dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())); @@ -1130,6 +1146,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { /** * Test for: {@link DevicePolicyManager#setDeviceOwner} Package doesn't exist. */ + @Test public void testSetDeviceOwner_noSuchPackage() { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_USERS); @@ -1144,10 +1161,12 @@ public class DevicePolicyManagerTest extends DpmTestBase { () -> dpm.setDeviceOwner(new ComponentName("a.b.c", ".def"))); } + @Test public void testSetDeviceOwner_failures() throws Exception { // TODO Test more failure cases. Basically test all chacks in enforceCanSetDeviceOwner(). } + @Test public void testClearDeviceOwner() throws Exception { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_USERS); @@ -1164,20 +1183,20 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID); dpm.setActiveAdmin(admin1, /* replace =*/ false); - assertTrue(dpm.setDeviceOwner(admin1, "owner-name")); + assertThat(dpm.setDeviceOwner(admin1, "owner-name")).isTrue(); // Verify internal calls. verify(getServices().iactivityManager, times(1)).updateDeviceOwner( eq(admin1.getPackageName())); - assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser()); + assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(admin1); dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADD_USER); when(getServices().userManager.hasUserRestriction(eq(UserManager.DISALLOW_ADD_USER), MockUtils.checkUserHandle(UserHandle.USER_SYSTEM))).thenReturn(true); - assertTrue(dpm.isAdminActive(admin1)); - assertFalse(dpm.isRemovingAdmin(admin1, UserHandle.USER_SYSTEM)); + assertThat(dpm.isAdminActive(admin1)).isTrue(); + assertThat(dpm.isRemovingAdmin(admin1, UserHandle.USER_SYSTEM)).isFalse(); // Set up other mocks. when(getServices().userManager.getUserRestrictions()).thenReturn(new Bundle()); @@ -1196,7 +1215,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm.clearDeviceOwnerApp(admin1.getPackageName()); // Now DO shouldn't be set. - assertNull(dpm.getDeviceOwnerComponentOnAnyUser()); + assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isNull(); verify(getServices().userManager).setUserRestriction(eq(UserManager.DISALLOW_ADD_USER), eq(false), @@ -1209,7 +1228,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(getServices().usageStatsManagerInternal).setActiveAdminApps( null, UserHandle.USER_SYSTEM); - assertFalse(dpm.isAdminActiveAsUser(admin1, UserHandle.USER_SYSTEM)); + assertThat(dpm.isAdminActiveAsUser(admin1, UserHandle.USER_SYSTEM)).isFalse(); // ACTION_DEVICE_OWNER_CHANGED should be sent twice, once for setting the device owner // and once for clearing it. @@ -1219,6 +1238,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { // TODO Check other calls. } + @Test public void testDeviceOwnerBackupActivateDeactivate() throws Exception { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); @@ -1227,7 +1247,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID); dpm.setActiveAdmin(admin1, /* replace =*/ false); - assertTrue(dpm.setDeviceOwner(admin1, "owner-name")); + assertThat(dpm.setDeviceOwner(admin1, "owner-name")).isTrue(); verify(getServices().ibackupManager, times(1)).setBackupServiceActive( eq(UserHandle.USER_SYSTEM), eq(false)); @@ -1238,6 +1258,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { eq(UserHandle.USER_SYSTEM), eq(true)); } + @Test public void testProfileOwnerBackupActivateDeactivate() throws Exception { setAsProfileOwner(admin1); @@ -1250,6 +1271,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { eq(CALLER_USER_HANDLE), eq(true)); } + @Test public void testClearDeviceOwner_fromDifferentUser() throws Exception { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_USERS); @@ -1266,13 +1288,13 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID); dpm.setActiveAdmin(admin1, /* replace =*/ false); - assertTrue(dpm.setDeviceOwner(admin1, "owner-name")); + assertThat(dpm.setDeviceOwner(admin1, "owner-name")).isTrue(); // Verify internal calls. verify(getServices().iactivityManager, times(1)).updateDeviceOwner( eq(admin1.getPackageName())); - assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser()); + assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(admin1); // Now call clear from the secondary user, which should throw. mContext.binder.callingUid = DpmMockContext.CALLER_UID; @@ -1286,7 +1308,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { () -> dpm.clearDeviceOwnerApp(admin1.getPackageName())); // DO shouldn't be removed. - assertTrue(dpm.isDeviceManaged()); + assertThat(dpm.isDeviceManaged()).isTrue(); } /** @@ -1294,6 +1316,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { * * Validates that when the device owner is removed, the reset password token is cleared */ + @Test public void testClearDeviceOwner_clearResetPasswordToken() throws Exception { mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); @@ -1312,13 +1335,13 @@ public class DevicePolicyManagerTest extends DpmTestBase { when(getServices().lockPatternUtils.addEscrowToken(eq(token), eq(UserHandle.USER_SYSTEM), nullable(EscrowTokenStateChangeCallback.class))) .thenReturn(handle); - assertTrue(dpm.setResetPasswordToken(admin1, token)); + assertThat(dpm.setResetPasswordToken(admin1, token)).isTrue(); // Assert reset password token is active when(getServices().lockPatternUtils.isEscrowTokenActive(eq(handle), eq(UserHandle.USER_SYSTEM))) .thenReturn(true); - assertTrue(dpm.isResetPasswordTokenActive(admin1)); + assertThat(dpm.isResetPasswordTokenActive(admin1)).isTrue(); // Remove the device owner dpm.clearDeviceOwnerApp(admin1.getPackageName()); @@ -1328,12 +1351,13 @@ public class DevicePolicyManagerTest extends DpmTestBase { eq(UserHandle.USER_SYSTEM)); } + @Test public void testSetProfileOwner() throws Exception { setAsProfileOwner(admin1); // PO admin can't be deactivated. dpm.removeActiveAdmin(admin1); - assertTrue(dpm.isAdminActive(admin1)); + assertThat(dpm.isAdminActive(admin1)).isTrue(); // Try setting DO on the same user, which should fail. setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID); @@ -1347,13 +1371,14 @@ public class DevicePolicyManagerTest extends DpmTestBase { }); } + @Test public void testClearProfileOwner() throws Exception { setAsProfileOwner(admin1); mContext.binder.callingUid = DpmMockContext.CALLER_UID; - assertTrue(dpm.isProfileOwnerApp(admin1.getPackageName())); - assertFalse(dpm.isRemovingAdmin(admin1, CALLER_USER_HANDLE)); + assertThat(dpm.isProfileOwnerApp(admin1.getPackageName())).isTrue(); + assertThat(dpm.isRemovingAdmin(admin1, CALLER_USER_HANDLE)).isFalse(); // First try when the user is locked, which should fail. when(getServices().userManager.isUserUnlocked(anyInt())) @@ -1367,16 +1392,18 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm.clearProfileOwner(admin1); // Check - assertFalse(dpm.isProfileOwnerApp(admin1.getPackageName())); - assertFalse(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE)); + assertThat(dpm.isProfileOwnerApp(admin1.getPackageName())).isFalse(); + assertThat(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE)).isFalse(); verify(getServices().usageStatsManagerInternal).setActiveAdminApps( null, CALLER_USER_HANDLE); } + @Test public void testSetProfileOwner_failures() throws Exception { // TODO Test more failure cases. Basically test all chacks in enforceCanSetProfileOwner(). } + @Test public void testGetDeviceOwnerAdminLocked() throws Exception { checkDeviceOwnerWithMultipleDeviceAdmins(); } @@ -1421,13 +1448,13 @@ public class DevicePolicyManagerTest extends DpmTestBase { // Set DO on the first non-system user. getServices().setUserRunning(CALLER_USER_HANDLE, true); - assertTrue(dpm.setDeviceOwner(admin2, "owner-name", CALLER_USER_HANDLE)); + assertThat(dpm.setDeviceOwner(admin2, "owner-name", CALLER_USER_HANDLE)).isTrue(); - assertEquals(admin2, dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false)); + assertThat(dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false)).isEqualTo(admin2); // Then check getDeviceOwnerAdminLocked(). - assertEquals(admin2, getDeviceOwner().info.getComponent()); - assertEquals(DpmMockContext.CALLER_UID, getDeviceOwner().getUid()); + assertThat(getDeviceOwner().info.getComponent()).isEqualTo(admin2); + assertThat(getDeviceOwner().getUid()).isEqualTo(DpmMockContext.CALLER_UID); } /** @@ -1438,6 +1465,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { * We didn't use to persist the DO component class name, but now we do, and the above method * finds the right component from a package name upon migration. */ + @Test public void testDeviceOwnerMigration() throws Exception { when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(true); checkDeviceOwnerWithMultipleDeviceAdmins(); @@ -1449,7 +1477,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpms.mOwners.writeDeviceOwner(); // Make sure the DO component name doesn't have a class name. - assertEquals("", dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false).getClassName()); + assertThat(dpms.getDeviceOwnerComponent(/* callingUserOnly= */ false).getClassName()) + .isEmpty(); // Then create a new DPMS to have it load the settings from files. when(getServices().userManager.getUserRestrictions(any(UserHandle.class))) @@ -1459,9 +1488,10 @@ public class DevicePolicyManagerTest extends DpmTestBase { // Now the DO component name is a full name. // *BUT* because both admin1 and admin2 belong to the same package, we think admin1 is the // DO. - assertEquals(admin1, dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false)); + assertThat(dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false)).isEqualTo(admin1); } + @Test public void testSetGetApplicationRestriction() { setAsProfileOwner(admin1); mContext.packageName = admin1.getPackageName(); @@ -1480,20 +1510,20 @@ public class DevicePolicyManagerTest extends DpmTestBase { { Bundle returned = dpm.getApplicationRestrictions(admin1, "pkg1"); - assertNotNull(returned); - assertEquals(returned.size(), 1); - assertEquals(returned.get("KEY_STRING"), "Foo1"); + assertThat(returned).isNotNull(); + assertThat(returned.size()).isEqualTo(1); + assertThat("Foo1").isEqualTo(returned.get("KEY_STRING")); } { Bundle returned = dpm.getApplicationRestrictions(admin1, "pkg2"); - assertNotNull(returned); - assertEquals(returned.size(), 1); - assertEquals(returned.get("KEY_STRING"), "Foo2"); + assertThat(returned).isNotNull(); + assertThat(returned.size()).isEqualTo(1); + assertThat("Foo2").isEqualTo(returned.get("KEY_STRING")); } dpm.setApplicationRestrictions(admin1, "pkg2", new Bundle()); - assertEquals(0, dpm.getApplicationRestrictions(admin1, "pkg2").size()); + assertThat(dpm.getApplicationRestrictions(admin1, "pkg2").size()).isEqualTo(0); } /** @@ -1546,6 +1576,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { return uid; } + @Test public void testCertificateDisclosure() throws Exception { final int userId = CALLER_USER_HANDLE; final UserHandle user = UserHandle.of(userId); @@ -1571,7 +1602,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { .cancelAsUser(anyString(), anyInt(), eq(user)); // Given that we have four certificates installed, - when(getServices().keyChainConnection.getService().getUserCaAliases()).thenReturn(fourCerts); + when(getServices().keyChainConnection.getService().getUserCaAliases()) + .thenReturn(fourCerts); // when two of them are approved (one of them approved twice hence no action), dpms.approveCaCert(fourCerts.getList().get(0), userId, true); dpms.approveCaCert(fourCerts.getList().get(1), userId, true); @@ -1586,6 +1618,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { * Simple test for delegate set/get and general delegation. Tests verifying that delegated * privileges can acually be exercised by a delegate are not covered here. */ + @Test public void testDelegation() throws Exception { setAsProfileOwner(admin1); @@ -1606,17 +1639,18 @@ public class DevicePolicyManagerTest extends DpmTestBase { // DPMS correctly stores and retrieves the delegates DevicePolicyData policy = dpms.mUserData.get(userHandle); - assertEquals(2, policy.mDelegationMap.size()); + assertThat(policy.mDelegationMap.size()).isEqualTo(2); MoreAsserts.assertContentsInAnyOrder(policy.mDelegationMap.get(CERT_DELEGATE), DELEGATION_CERT_INSTALL); MoreAsserts.assertContentsInAnyOrder(dpm.getDelegatedScopes(admin1, CERT_DELEGATE), DELEGATION_CERT_INSTALL); - assertEquals(CERT_DELEGATE, dpm.getCertInstallerPackage(admin1)); + assertThat(dpm.getCertInstallerPackage(admin1)).isEqualTo(CERT_DELEGATE); MoreAsserts.assertContentsInAnyOrder(policy.mDelegationMap.get(RESTRICTIONS_DELEGATE), DELEGATION_APP_RESTRICTIONS); MoreAsserts.assertContentsInAnyOrder(dpm.getDelegatedScopes(admin1, RESTRICTIONS_DELEGATE), DELEGATION_APP_RESTRICTIONS); - assertEquals(RESTRICTIONS_DELEGATE, dpm.getApplicationRestrictionsManagingPackage(admin1)); + assertThat(dpm.getApplicationRestrictionsManagingPackage(admin1)) + .isEqualTo(RESTRICTIONS_DELEGATE); // On calling install certificate APIs from an unauthorized process mContext.binder.callingUid = RESTRICTIONS_DELEGATE_UID; @@ -1658,6 +1692,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { } } + @Test public void testApplicationRestrictionsManagingApp() throws Exception { setAsProfileOwner(admin1); @@ -1673,7 +1708,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { // delegated that permission yet. mContext.binder.callingUid = DpmMockContext.CALLER_UID; mContext.packageName = admin1.getPackageName(); - assertFalse(dpm.isCallerApplicationRestrictionsManagingPackage()); + assertThat(dpm.isCallerApplicationRestrictionsManagingPackage()).isFalse(); final Bundle rest = new Bundle(); rest.putString("KEY_STRING", "Foo1"); assertExpectException(SecurityException.class, INVALID_CALLING_IDENTITY_MSG, @@ -1682,7 +1717,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { // Check via the profile owner that no restrictions were set. mContext.binder.callingUid = DpmMockContext.CALLER_UID; mContext.packageName = admin1.getPackageName(); - assertEquals(0, dpm.getApplicationRestrictions(admin1, "pkg1").size()); + assertThat(dpm.getApplicationRestrictions(admin1, "pkg1").size()).isEqualTo(0); // Check the API does not allow setting a non-existent package assertExpectException(PackageManager.NameNotFoundException.class, @@ -1692,22 +1727,22 @@ public class DevicePolicyManagerTest extends DpmTestBase { // Let appRestrictionsManagerPackage manage app restrictions dpm.setApplicationRestrictionsManagingPackage(admin1, appRestrictionsManagerPackage); - assertEquals(appRestrictionsManagerPackage, - dpm.getApplicationRestrictionsManagingPackage(admin1)); + assertThat(dpm.getApplicationRestrictionsManagingPackage(admin1)) + .isEqualTo(appRestrictionsManagerPackage); // Now that package should be able to set and retrieve app restrictions. mContext.binder.callingUid = appRestrictionsManagerUid; mContext.packageName = appRestrictionsManagerPackage; - assertTrue(dpm.isCallerApplicationRestrictionsManagingPackage()); + assertThat(dpm.isCallerApplicationRestrictionsManagingPackage()).isTrue(); dpm.setApplicationRestrictions(null, "pkg1", rest); Bundle returned = dpm.getApplicationRestrictions(null, "pkg1"); - assertEquals(1, returned.size(), 1); - assertEquals("Foo1", returned.get("KEY_STRING")); + assertThat(returned.size()).isEqualTo(1); + assertThat(returned.get("KEY_STRING")).isEqualTo("Foo1"); // The same app running on a separate user shouldn't be able to manage app restrictions. mContext.binder.callingUid = UserHandle.getUid( UserHandle.USER_SYSTEM, appRestrictionsManagerAppId); - assertFalse(dpm.isCallerApplicationRestrictionsManagingPackage()); + assertThat(dpm.isCallerApplicationRestrictionsManagingPackage()).isFalse(); assertExpectException(SecurityException.class, nonDelegateExceptionMessageRegex, () -> dpm.setApplicationRestrictions(null, "pkg1", rest)); @@ -1715,20 +1750,21 @@ public class DevicePolicyManagerTest extends DpmTestBase { // too. mContext.binder.callingUid = DpmMockContext.CALLER_UID; mContext.packageName = admin1.getPackageName(); - assertEquals(returned, dpm.getApplicationRestrictions(admin1, "pkg1")); + assertThat(dpm.getApplicationRestrictions(admin1, "pkg1")).isEqualTo(returned); dpm.setApplicationRestrictions(admin1, "pkg1", null); - assertEquals(0, dpm.getApplicationRestrictions(admin1, "pkg1").size()); + assertThat(dpm.getApplicationRestrictions(admin1, "pkg1").size()).isEqualTo(0); // Removing the ability for the package to manage app restrictions. dpm.setApplicationRestrictionsManagingPackage(admin1, null); - assertNull(dpm.getApplicationRestrictionsManagingPackage(admin1)); + assertThat(dpm.getApplicationRestrictionsManagingPackage(admin1)).isNull(); mContext.binder.callingUid = appRestrictionsManagerUid; mContext.packageName = appRestrictionsManagerPackage; - assertFalse(dpm.isCallerApplicationRestrictionsManagingPackage()); + assertThat(dpm.isCallerApplicationRestrictionsManagingPackage()).isFalse(); assertExpectException(SecurityException.class, INVALID_CALLING_IDENTITY_MSG, () -> dpm.setApplicationRestrictions(null, "pkg1", null)); } + @Test public void testSetUserRestriction_asDo() throws Exception { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_USERS); @@ -1745,8 +1781,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { // Call. dpm.setActiveAdmin(admin1, /* replace =*/ false, UserHandle.USER_SYSTEM); - assertTrue(dpm.setDeviceOwner(admin1, "owner-name", - UserHandle.USER_SYSTEM)); + assertThat(dpm.setDeviceOwner(admin1, "owner-name", + UserHandle.USER_SYSTEM)).isTrue(); assertNoDeviceOwnerRestrictions(); reset(getServices().userManagerInternal); @@ -1859,6 +1895,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { return null; } + @Test public void testDaDisallowedPolicies_SecurityException() throws Exception { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL); @@ -1869,25 +1906,28 @@ public class DevicePolicyManagerTest extends DpmTestBase { boolean originalCameraDisabled = dpm.getCameraDisabled(admin1); assertExpectException(SecurityException.class, /* messageRegex= */ null, () -> dpm.setCameraDisabled(admin1, true)); - assertEquals(originalCameraDisabled, dpm.getCameraDisabled(admin1)); + assertThat(dpm.getCameraDisabled(admin1)).isEqualTo(originalCameraDisabled); int originalKeyguardDisabledFeatures = dpm.getKeyguardDisabledFeatures(admin1); assertExpectException(SecurityException.class, /* messageRegex= */ null, () -> dpm.setKeyguardDisabledFeatures(admin1, DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_ALL)); - assertEquals(originalKeyguardDisabledFeatures, dpm.getKeyguardDisabledFeatures(admin1)); + assertThat(dpm.getKeyguardDisabledFeatures(admin1)) + .isEqualTo(originalKeyguardDisabledFeatures); long originalPasswordExpirationTimeout = dpm.getPasswordExpirationTimeout(admin1); assertExpectException(SecurityException.class, /* messageRegex= */ null, () -> dpm.setPasswordExpirationTimeout(admin1, 1234)); - assertEquals(originalPasswordExpirationTimeout, dpm.getPasswordExpirationTimeout(admin1)); + assertThat(dpm.getPasswordExpirationTimeout(admin1)) + .isEqualTo(originalPasswordExpirationTimeout); int originalPasswordQuality = dpm.getPasswordQuality(admin1); assertExpectException(SecurityException.class, /* messageRegex= */ null, () -> dpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_NUMERIC)); - assertEquals(originalPasswordQuality, dpm.getPasswordQuality(admin1)); + assertThat(dpm.getPasswordQuality(admin1)).isEqualTo(originalPasswordQuality); } + @Test public void testSetUserRestriction_asPo() { setAsProfileOwner(admin1); @@ -2023,6 +2063,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { UserManager.DISALLOW_UNMUTE_MICROPHONE ); + @Test public void testSetUserRestriction_asPoOfOrgOwnedDevice() throws Exception { final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(CALLER_USER_HANDLE, DpmMockContext.SYSTEM_UID); @@ -2097,6 +2138,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { ); } + @Test public void testNoDefaultEnabledUserRestrictions() throws Exception { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_USERS); @@ -2112,8 +2154,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID); dpm.setActiveAdmin(admin1, /* replace =*/ false, UserHandle.USER_SYSTEM); - assertTrue(dpm.setDeviceOwner(admin1, "owner-name", - UserHandle.USER_SYSTEM)); + assertThat(dpm.setDeviceOwner(admin1, "owner-name", + UserHandle.USER_SYSTEM)).isTrue(); assertNoDeviceOwnerRestrictions(); @@ -2132,6 +2174,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { ); } + @Test public void testSetFactoryResetProtectionPolicyWithDO() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); @@ -2156,6 +2199,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { eq(android.Manifest.permission.MANAGE_FACTORY_RESET_PROTECTION)); } + @Test public void testSetFactoryResetProtectionPolicyFailWithPO() throws Exception { setupProfileOwner(); @@ -2167,6 +2211,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { () -> dpm.setFactoryResetProtectionPolicy(admin1, policy)); } + @Test public void testSetFactoryResetProtectionPolicyWithPOOfOrganizationOwnedDevice() throws Exception { setupProfileOwner(); @@ -2204,6 +2249,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { eq(android.Manifest.permission.MANAGE_FACTORY_RESET_PROTECTION)); } + @Test public void testGetFactoryResetProtectionPolicyWithFrpManagementAgent() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; @@ -2245,6 +2291,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertThat(actualAccounts).containsExactlyElementsIn(expectedAccounts); } + @Test public void testSetKeyguardDisabledFeaturesWithDO() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); @@ -2255,6 +2302,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA); } + @Test public void testSetKeyguardDisabledFeaturesWithPO() throws Exception { setupProfileOwner(); @@ -2264,6 +2312,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT); } + @Test public void testSetKeyguardDisabledFeaturesWithPOOfOrganizationOwnedDevice() throws Exception { final int MANAGED_PROFILE_USER_ID = CALLER_USER_HANDLE; @@ -2281,6 +2330,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA); } + @Test public void testSetApplicationHiddenWithDO() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); @@ -2304,6 +2354,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { UserHandle.USER_SYSTEM); } + @Test public void testSetApplicationHiddenWithPOOfOrganizationOwnedDevice() throws Exception { final int MANAGED_PROFILE_USER_ID = CALLER_USER_HANDLE; final int MANAGED_PROFILE_ADMIN_UID = @@ -2334,6 +2385,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { false, UserHandle.USER_SYSTEM); } + @Test public void testGetMacAddress() throws Exception { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); @@ -2351,7 +2403,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { // DO needs to be an DA. dpm.setActiveAdmin(admin1, /* replace =*/ false); - assertTrue(dpm.isAdminActive(admin1)); + assertThat(dpm.isAdminActive(admin1)).isTrue(); // Test 2. Caller has DA, but not DO. assertExpectException(SecurityException.class, @@ -2359,7 +2411,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { () -> dpm.getWifiMacAddress(admin1)); // Test 3. Caller has PO, but not DO. - assertTrue(dpm.setProfileOwner(admin1, null, UserHandle.USER_SYSTEM)); + assertThat(dpm.setProfileOwner(admin1, null, UserHandle.USER_SYSTEM)).isTrue(); assertExpectException(SecurityException.class, /* messageRegex= */ INVALID_CALLING_IDENTITY_MSG, () -> dpm.getWifiMacAddress(admin1)); @@ -2368,30 +2420,32 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm.clearProfileOwner(admin1); dpm.setActiveAdmin(admin1, false); // Test 4, Caller is DO now. - assertTrue(dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM)); + assertThat(dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM)).isTrue(); // 4-1. But WifiManager is not ready. - assertNull(dpm.getWifiMacAddress(admin1)); + assertThat(dpm.getWifiMacAddress(admin1)).isNull(); // 4-2. When WifiManager returns an empty array, dpm should also output null. when(getServices().wifiManager.getFactoryMacAddresses()).thenReturn(new String[0]); - assertNull(dpm.getWifiMacAddress(admin1)); + assertThat(dpm.getWifiMacAddress(admin1)).isNull(); // 4-3. With a real MAC address. final String[] macAddresses = new String[]{"11:22:33:44:55:66"}; when(getServices().wifiManager.getFactoryMacAddresses()).thenReturn(macAddresses); - assertEquals("11:22:33:44:55:66", dpm.getWifiMacAddress(admin1)); + assertThat(dpm.getWifiMacAddress(admin1)).isEqualTo("11:22:33:44:55:66"); } + @Test public void testGetMacAddressByOrgOwnedPO() throws Exception { setupProfileOwner(); configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE); final String[] macAddresses = new String[]{"11:22:33:44:55:66"}; when(getServices().wifiManager.getFactoryMacAddresses()).thenReturn(macAddresses); - assertEquals("11:22:33:44:55:66", dpm.getWifiMacAddress(admin1)); + assertThat(dpm.getWifiMacAddress(admin1)).isEqualTo("11:22:33:44:55:66"); } + @Test public void testReboot() throws Exception { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); @@ -2404,19 +2458,19 @@ public class DevicePolicyManagerTest extends DpmTestBase { // Set admin1 as DA. dpm.setActiveAdmin(admin1, false); - assertTrue(dpm.isAdminActive(admin1)); + assertThat(dpm.isAdminActive(admin1)).isTrue(); assertExpectException(SecurityException.class, /* messageRegex= */ INVALID_CALLING_IDENTITY_MSG, () -> dpm.reboot(admin1)); // Set admin1 as PO. - assertTrue(dpm.setProfileOwner(admin1, null, UserHandle.USER_SYSTEM)); + assertThat(dpm.setProfileOwner(admin1, null, UserHandle.USER_SYSTEM)).isTrue(); assertExpectException(SecurityException.class, /* messageRegex= */ INVALID_CALLING_IDENTITY_MSG, () -> dpm.reboot(admin1)); // Remove PO and add DO. dpm.clearProfileOwner(admin1); dpm.setActiveAdmin(admin1, false); - assertTrue(dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM)); + assertThat(dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM)).isTrue(); // admin1 is DO. // Set current call state of device to ringing. @@ -2432,10 +2486,12 @@ public class DevicePolicyManagerTest extends DpmTestBase { () -> dpm.reboot(admin1)); // Set current call state of device to idle. - when(getServices().telephonyManager.getCallState()).thenReturn(TelephonyManager.CALL_STATE_IDLE); + when(getServices().telephonyManager.getCallState()) + .thenReturn(TelephonyManager.CALL_STATE_IDLE); dpm.reboot(admin1); } + @Test public void testSetGetSupportText() { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); dpm.setActiveAdmin(admin1, true); @@ -2444,11 +2500,11 @@ public class DevicePolicyManagerTest extends DpmTestBase { // Null default support messages. { - assertNull(dpm.getLongSupportMessage(admin1)); - assertNull(dpm.getShortSupportMessage(admin1)); + assertThat(dpm.getLongSupportMessage(admin1)).isNull(); + assertThat(dpm.getShortSupportMessage(admin1)).isNull(); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; - assertNull(dpm.getShortSupportMessageForUser(admin1, CALLER_USER_HANDLE)); - assertNull(dpm.getLongSupportMessageForUser(admin1, CALLER_USER_HANDLE)); + assertThat(dpm.getShortSupportMessageForUser(admin1, CALLER_USER_HANDLE)).isNull(); + assertThat(dpm.getLongSupportMessageForUser(admin1, CALLER_USER_HANDLE)).isNull(); mMockContext.binder.callingUid = DpmMockContext.CALLER_UID; } @@ -2473,46 +2529,46 @@ public class DevicePolicyManagerTest extends DpmTestBase { { final String supportText = "Some text to test with."; dpm.setShortSupportMessage(admin1, supportText); - assertEquals(supportText, dpm.getShortSupportMessage(admin1)); - assertNull(dpm.getLongSupportMessage(admin1)); - assertNull(dpm.getShortSupportMessage(admin2)); + assertThat(dpm.getShortSupportMessage(admin1)).isEqualTo(supportText); + assertThat(dpm.getLongSupportMessage(admin1)).isNull(); + assertThat(dpm.getShortSupportMessage(admin2)).isNull(); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; - assertEquals(supportText, dpm.getShortSupportMessageForUser(admin1, - CALLER_USER_HANDLE)); - assertNull(dpm.getShortSupportMessageForUser(admin2, CALLER_USER_HANDLE)); - assertNull(dpm.getLongSupportMessageForUser(admin1, CALLER_USER_HANDLE)); + assertThat(dpm.getShortSupportMessageForUser(admin1, + CALLER_USER_HANDLE)).isEqualTo(supportText); + assertThat(dpm.getShortSupportMessageForUser(admin2, CALLER_USER_HANDLE)).isNull(); + assertThat(dpm.getLongSupportMessageForUser(admin1, CALLER_USER_HANDLE)).isNull(); mMockContext.binder.callingUid = DpmMockContext.CALLER_UID; dpm.setShortSupportMessage(admin1, null); - assertNull(dpm.getShortSupportMessage(admin1)); + assertThat(dpm.getShortSupportMessage(admin1)).isNull(); } // Set/Get long returns what it sets and other admins text isn't changed. { final String supportText = "Some text to test with.\nWith more text."; dpm.setLongSupportMessage(admin1, supportText); - assertEquals(supportText, dpm.getLongSupportMessage(admin1)); - assertNull(dpm.getShortSupportMessage(admin1)); - assertNull(dpm.getLongSupportMessage(admin2)); + assertThat(dpm.getLongSupportMessage(admin1)).isEqualTo(supportText); + assertThat(dpm.getShortSupportMessage(admin1)).isNull(); + assertThat(dpm.getLongSupportMessage(admin2)).isNull(); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; - assertEquals(supportText, dpm.getLongSupportMessageForUser(admin1, - CALLER_USER_HANDLE)); - assertNull(dpm.getLongSupportMessageForUser(admin2, CALLER_USER_HANDLE)); - assertNull(dpm.getShortSupportMessageForUser(admin1, CALLER_USER_HANDLE)); + assertThat(dpm.getLongSupportMessageForUser(admin1, + CALLER_USER_HANDLE)).isEqualTo(supportText); + assertThat(dpm.getLongSupportMessageForUser(admin2, CALLER_USER_HANDLE)).isNull(); + assertThat(dpm.getShortSupportMessageForUser(admin1, CALLER_USER_HANDLE)).isNull(); mMockContext.binder.callingUid = DpmMockContext.CALLER_UID; dpm.setLongSupportMessage(admin1, null); - assertNull(dpm.getLongSupportMessage(admin1)); + assertThat(dpm.getLongSupportMessage(admin1)).isNull(); } } + @Test public void testSetGetMeteredDataDisabledPackages() throws Exception { setAsProfileOwner(admin1); - final ArrayList<String> emptyList = new ArrayList<>(); - assertEquals(emptyList, dpm.getMeteredDataDisabledPackages(admin1)); + assertThat(dpm.getMeteredDataDisabledPackages(admin1)).isEmpty(); // Setup final ArrayList<String> pkgsToRestrict = new ArrayList<>(); @@ -2525,8 +2581,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { List<String> excludedPkgs = dpm.setMeteredDataDisabledPackages(admin1, pkgsToRestrict); // Verify - assertEquals(emptyList, excludedPkgs); - assertEquals(pkgsToRestrict, dpm.getMeteredDataDisabledPackages(admin1)); + assertThat(excludedPkgs).isEmpty(); + assertThat(dpm.getMeteredDataDisabledPackages(admin1)).isEqualTo(pkgsToRestrict); verify(getServices().networkPolicyManagerInternal).setMeteredRestrictedPackages( MockUtils.checkApps(pkgsToRestrict.toArray(new String[0])), eq(CALLER_USER_HANDLE)); @@ -2536,17 +2592,18 @@ public class DevicePolicyManagerTest extends DpmTestBase { excludedPkgs = dpm.setMeteredDataDisabledPackages(admin1, pkgsToRestrict); // Verify - assertEquals(emptyList, excludedPkgs); - assertEquals(pkgsToRestrict, dpm.getMeteredDataDisabledPackages(admin1)); + assertThat(excludedPkgs).isEmpty(); + assertThat(dpm.getMeteredDataDisabledPackages(admin1)).isEqualTo(pkgsToRestrict); verify(getServices().networkPolicyManagerInternal).setMeteredRestrictedPackages( MockUtils.checkApps(pkgsToRestrict.toArray(new String[0])), eq(CALLER_USER_HANDLE)); } + @Test public void testSetGetMeteredDataDisabledPackages_deviceAdmin() { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); dpm.setActiveAdmin(admin1, true); - assertTrue(dpm.isAdminActive(admin1)); + assertThat(dpm.isAdminActive(admin1)).isTrue(); mContext.callerPermissions.remove(permission.MANAGE_DEVICE_ADMINS); assertExpectException(SecurityException.class, /* messageRegex= */ NOT_PROFILE_OWNER_MSG, @@ -2555,11 +2612,11 @@ public class DevicePolicyManagerTest extends DpmTestBase { () -> dpm.getMeteredDataDisabledPackages(admin1)); } + @Test public void testIsMeteredDataDisabledForUserPackage() throws Exception { setAsProfileOwner(admin1); // Setup - final ArrayList<String> emptyList = new ArrayList<>(); final ArrayList<String> pkgsToRestrict = new ArrayList<>(); final String package1 = "com.example.one"; final String package2 = "com.example.two"; @@ -2571,16 +2628,20 @@ public class DevicePolicyManagerTest extends DpmTestBase { List<String> excludedPkgs = dpm.setMeteredDataDisabledPackages(admin1, pkgsToRestrict); // Verify - assertEquals(emptyList, excludedPkgs); + assertThat(excludedPkgs).isEmpty(); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; - assertTrue(package1 + "should be restricted", - dpm.isMeteredDataDisabledPackageForUser(admin1, package1, CALLER_USER_HANDLE)); - assertTrue(package2 + "should be restricted", - dpm.isMeteredDataDisabledPackageForUser(admin1, package2, CALLER_USER_HANDLE)); - assertFalse(package3 + "should not be restricted", - dpm.isMeteredDataDisabledPackageForUser(admin1, package3, CALLER_USER_HANDLE)); - } - + assertWithMessage("%s should be restricted", package1) + .that(dpm.isMeteredDataDisabledPackageForUser(admin1, package1, CALLER_USER_HANDLE)) + .isTrue(); + assertWithMessage("%s should be restricted", package2) + .that(dpm.isMeteredDataDisabledPackageForUser(admin1, package2, CALLER_USER_HANDLE)) + .isTrue(); + assertWithMessage("%s should not be restricted", package3) + .that(dpm.isMeteredDataDisabledPackageForUser(admin1, package3, CALLER_USER_HANDLE)) + .isFalse(); + } + + @Test public void testIsMeteredDataDisabledForUserPackage_nonSystemUidCaller() throws Exception { setAsProfileOwner(admin1); assertExpectException(SecurityException.class, @@ -2597,6 +2658,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { clearDeviceOwner(); } + @Test public void testCreateAdminSupportIntent() throws Exception { // Setup device owner. mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; @@ -2604,11 +2666,11 @@ public class DevicePolicyManagerTest extends DpmTestBase { // Nonexisting permission returns null Intent intent = dpm.createAdminSupportIntent("disallow_nothing"); - assertNull(intent); + assertThat(intent).isNull(); // Existing permission that is not set returns null intent = dpm.createAdminSupportIntent(UserManager.DISALLOW_ADJUST_VOLUME); - assertNull(intent); + assertThat(intent).isNull(); // Existing permission that is not set by device/profile owner returns null when(getServices().userManager.hasUserRestriction( @@ -2616,7 +2678,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid)))) .thenReturn(true); intent = dpm.createAdminSupportIntent(UserManager.DISALLOW_ADJUST_VOLUME); - assertNull(intent); + assertThat(intent).isNull(); // UM.getUserRestrictionSources() will return a list of size 1 with the caller resource. doAnswer((Answer<List<UserManager.EnforcingUser>>) invocation -> Collections.singletonList( @@ -2626,51 +2688,53 @@ public class DevicePolicyManagerTest extends DpmTestBase { eq(UserManager.DISALLOW_ADJUST_VOLUME), eq(UserHandle.of(UserHandle.myUserId()))); intent = dpm.createAdminSupportIntent(UserManager.DISALLOW_ADJUST_VOLUME); - assertNotNull(intent); - assertEquals(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS, intent.getAction()); - assertEquals(UserHandle.getUserId(DpmMockContext.CALLER_SYSTEM_USER_UID), - intent.getIntExtra(Intent.EXTRA_USER_ID, -1)); - assertEquals(admin1, intent.getParcelableExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN)); - assertEquals(UserManager.DISALLOW_ADJUST_VOLUME, - intent.getStringExtra(DevicePolicyManager.EXTRA_RESTRICTION)); + assertThat(intent).isNotNull(); + assertThat(intent.getAction()).isEqualTo(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS); + assertThat(intent.getIntExtra(Intent.EXTRA_USER_ID, -1)) + .isEqualTo(UserHandle.getUserId(DpmMockContext.CALLER_SYSTEM_USER_UID)); + assertThat( + (ComponentName) intent.getParcelableExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN)) + .isEqualTo(admin1); + assertThat(intent.getStringExtra(DevicePolicyManager.EXTRA_RESTRICTION)) + .isEqualTo(UserManager.DISALLOW_ADJUST_VOLUME); // Try with POLICY_DISABLE_CAMERA and POLICY_DISABLE_SCREEN_CAPTURE, which are not // user restrictions // Camera is not disabled intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_CAMERA); - assertNull(intent); + assertThat(intent).isNull(); // Camera is disabled dpm.setCameraDisabled(admin1, true); intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_CAMERA); - assertNotNull(intent); - assertEquals(DevicePolicyManager.POLICY_DISABLE_CAMERA, - intent.getStringExtra(DevicePolicyManager.EXTRA_RESTRICTION)); + assertThat(intent).isNotNull(); + assertThat(intent.getStringExtra(DevicePolicyManager.EXTRA_RESTRICTION)) + .isEqualTo(DevicePolicyManager.POLICY_DISABLE_CAMERA); // Screen capture is not disabled intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE); - assertNull(intent); + assertThat(intent).isNull(); // Screen capture is disabled dpm.setScreenCaptureDisabled(admin1, true); intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE); - assertNotNull(intent); - assertEquals(DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE, - intent.getStringExtra(DevicePolicyManager.EXTRA_RESTRICTION)); + assertThat(intent).isNotNull(); + assertThat(intent.getStringExtra(DevicePolicyManager.EXTRA_RESTRICTION)) + .isEqualTo(DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE); // Same checks for different user mContext.binder.callingUid = DpmMockContext.CALLER_UID; // Camera should be disabled by device owner intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_CAMERA); - assertNotNull(intent); - assertEquals(DevicePolicyManager.POLICY_DISABLE_CAMERA, - intent.getStringExtra(DevicePolicyManager.EXTRA_RESTRICTION)); - assertEquals(UserHandle.getUserId(DpmMockContext.CALLER_SYSTEM_USER_UID), - intent.getIntExtra(Intent.EXTRA_USER_ID, -1)); + assertThat(intent).isNotNull(); + assertThat(intent.getStringExtra(DevicePolicyManager.EXTRA_RESTRICTION)) + .isEqualTo(DevicePolicyManager.POLICY_DISABLE_CAMERA); + assertThat(intent.getIntExtra(Intent.EXTRA_USER_ID, -1)) + .isEqualTo(UserHandle.getUserId(DpmMockContext.CALLER_SYSTEM_USER_UID)); // ScreenCapture should not be disabled by device owner intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE); - assertNull(intent); + assertThat(intent).isNull(); } /** @@ -2679,6 +2743,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { * {@link DevicePolicyManager#getAffiliationIds} * {@link DevicePolicyManager#isAffiliatedUser} */ + @Test public void testUserAffiliation() throws Exception { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); @@ -2686,20 +2751,20 @@ public class DevicePolicyManagerTest extends DpmTestBase { // Check that the system user is unaffiliated. mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; - assertFalse(dpm.isAffiliatedUser()); + assertThat(dpm.isAffiliatedUser()).isFalse(); // Set a device owner on the system user. Check that the system user becomes affiliated. setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID); dpm.setActiveAdmin(admin1, /* replace =*/ false); - assertTrue(dpm.setDeviceOwner(admin1, "owner-name")); - assertTrue(dpm.isAffiliatedUser()); - assertTrue(dpm.getAffiliationIds(admin1).isEmpty()); + assertThat(dpm.setDeviceOwner(admin1, "owner-name")).isTrue(); + assertThat(dpm.isAffiliatedUser()).isTrue(); + assertThat(dpm.getAffiliationIds(admin1).isEmpty()).isTrue(); // Install a profile owner. Check that the test user is unaffiliated. mContext.binder.callingUid = DpmMockContext.CALLER_UID; setAsProfileOwner(admin2); - assertFalse(dpm.isAffiliatedUser()); - assertTrue(dpm.getAffiliationIds(admin2).isEmpty()); + assertThat(dpm.isAffiliatedUser()).isFalse(); + assertThat(dpm.getAffiliationIds(admin2).isEmpty()).isTrue(); // Have the profile owner specify a set of affiliation ids. Check that the test user remains // unaffiliated. @@ -2709,7 +2774,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { userAffiliationIds.add("blue"); dpm.setAffiliationIds(admin2, userAffiliationIds); MoreAsserts.assertContentsInAnyOrder(dpm.getAffiliationIds(admin2), "red", "green", "blue"); - assertFalse(dpm.isAffiliatedUser()); + assertThat(dpm.isAffiliatedUser()).isFalse(); // Have the device owner specify a set of affiliation ids that do not intersect with those // specified by the profile owner. Check that the test user remains unaffiliated. @@ -2722,7 +2787,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { MoreAsserts.assertContentsInAnyOrder( dpm.getAffiliationIds(admin1), "cyan", "yellow", "magenta"); mContext.binder.callingUid = DpmMockContext.CALLER_UID; - assertFalse(dpm.isAffiliatedUser()); + assertThat(dpm.isAffiliatedUser()).isFalse(); // Have the profile owner specify a set of affiliation ids that intersect with those // specified by the device owner. Check that the test user becomes affiliated. @@ -2730,33 +2795,36 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm.setAffiliationIds(admin2, userAffiliationIds); MoreAsserts.assertContentsInAnyOrder( dpm.getAffiliationIds(admin2), "red", "green", "blue", "yellow"); - assertTrue(dpm.isAffiliatedUser()); + assertThat(dpm.isAffiliatedUser()).isTrue(); // Clear affiliation ids for the profile owner. The user becomes unaffiliated. dpm.setAffiliationIds(admin2, Collections.emptySet()); - assertTrue(dpm.getAffiliationIds(admin2).isEmpty()); - assertFalse(dpm.isAffiliatedUser()); + assertThat(dpm.getAffiliationIds(admin2).isEmpty()).isTrue(); + assertThat(dpm.isAffiliatedUser()).isFalse(); // Set affiliation ids again, then clear PO to check that the user becomes unaffiliated dpm.setAffiliationIds(admin2, userAffiliationIds); - assertTrue(dpm.isAffiliatedUser()); + assertThat(dpm.isAffiliatedUser()).isTrue(); dpm.clearProfileOwner(admin2); - assertFalse(dpm.isAffiliatedUser()); + assertThat(dpm.isAffiliatedUser()).isFalse(); // Check that the system user remains affiliated. mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; - assertTrue(dpm.isAffiliatedUser()); + assertThat(dpm.isAffiliatedUser()).isTrue(); // Clear the device owner - the user becomes unaffiliated. clearDeviceOwner(); - assertFalse(dpm.isAffiliatedUser()); + assertThat(dpm.isAffiliatedUser()).isFalse(); } + @Test public void testGetUserProvisioningState_defaultResult() { mContext.callerPermissions.add(permission.MANAGE_USERS); - assertEquals(DevicePolicyManager.STATE_USER_UNMANAGED, dpm.getUserProvisioningState()); + assertThat(dpm.getUserProvisioningState()) + .isEqualTo(DevicePolicyManager.STATE_USER_UNMANAGED); } + @Test public void testSetUserProvisioningState_permission() throws Exception { setupProfileOwner(); @@ -2764,6 +2832,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { DevicePolicyManager.STATE_USER_SETUP_FINALIZED); } + @Test public void testSetUserProvisioningState_unprivileged() throws Exception { setupProfileOwner(); assertExpectException(SecurityException.class, /* messageRegex =*/ null, @@ -2771,6 +2840,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { CALLER_USER_HANDLE)); } + @Test public void testSetUserProvisioningState_noManagement() { mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); mContext.callerPermissions.add(permission.MANAGE_USERS); @@ -2778,9 +2848,11 @@ public class DevicePolicyManagerTest extends DpmTestBase { /* messageRegex= */ "change provisioning state unless a .* owner is set", () -> dpm.setUserProvisioningState(DevicePolicyManager.STATE_USER_SETUP_FINALIZED, CALLER_USER_HANDLE)); - assertEquals(DevicePolicyManager.STATE_USER_UNMANAGED, dpm.getUserProvisioningState()); + assertThat(dpm.getUserProvisioningState()) + .isEqualTo(DevicePolicyManager.STATE_USER_UNMANAGED); } + @Test public void testSetUserProvisioningState_deviceOwnerFromSetupWizard() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); @@ -2790,6 +2862,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { DevicePolicyManager.STATE_USER_SETUP_FINALIZED); } + @Test public void testSetUserProvisioningState_deviceOwnerFromSetupWizardAlternative() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; @@ -2800,6 +2873,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { DevicePolicyManager.STATE_USER_SETUP_FINALIZED); } + @Test public void testSetUserProvisioningState_deviceOwnerWithoutSetupWizard() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); @@ -2808,6 +2882,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { DevicePolicyManager.STATE_USER_SETUP_FINALIZED); } + @Test public void testSetUserProvisioningState_managedProfileFromSetupWizard_primaryUser() throws Exception { setupProfileOwner(); @@ -2817,6 +2892,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { DevicePolicyManager.STATE_USER_PROFILE_FINALIZED); } + @Test public void testSetUserProvisioningState_managedProfileFromSetupWizard_managedProfile() throws Exception { setupProfileOwner(); @@ -2826,6 +2902,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { DevicePolicyManager.STATE_USER_SETUP_FINALIZED); } + @Test public void testSetUserProvisioningState_managedProfileWithoutSetupWizard() throws Exception { setupProfileOwner(); @@ -2833,6 +2910,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { DevicePolicyManager.STATE_USER_SETUP_FINALIZED); } + @Test public void testSetUserProvisioningState_illegalTransitionOutOfFinalized1() throws Exception { setupProfileOwner(); @@ -2843,6 +2921,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { DevicePolicyManager.STATE_USER_UNMANAGED)); } + @Test public void testSetUserProvisioningState_illegalTransitionToAnotherInProgressState() throws Exception { setupProfileOwner(); @@ -2858,10 +2937,11 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); mContext.callerPermissions.add(permission.MANAGE_USERS); - assertEquals(DevicePolicyManager.STATE_USER_UNMANAGED, dpm.getUserProvisioningState()); + assertThat(dpm.getUserProvisioningState()) + .isEqualTo(DevicePolicyManager.STATE_USER_UNMANAGED); for (int state : states) { dpm.setUserProvisioningState(state, userId); - assertEquals(state, dpm.getUserProvisioningState()); + assertThat(dpm.getUserProvisioningState()).isEqualTo(state); } } @@ -2870,7 +2950,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID); dpm.setActiveAdmin(admin1, false); - assertTrue(dpm.setProfileOwner(admin1, null, CALLER_USER_HANDLE)); + assertThat(dpm.setProfileOwner(admin1, null, CALLER_USER_HANDLE)).isTrue(); mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS); } @@ -2880,7 +2960,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { setUpPackageManagerForAdmin(admin1, DpmMockContext.SYSTEM_UID); dpm.setActiveAdmin(admin1, false); - assertTrue(dpm.setProfileOwner(admin1, null, UserHandle.USER_SYSTEM)); + assertThat(dpm.setProfileOwner(admin1, null, UserHandle.USER_SYSTEM)).isTrue(); mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS); } @@ -2890,11 +2970,12 @@ public class DevicePolicyManagerTest extends DpmTestBase { setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID); dpm.setActiveAdmin(admin1, false); - assertTrue(dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM)); + assertThat(dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM)).isTrue(); mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS); } + @Test public void testSetMaximumTimeToLock() { mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); @@ -2956,6 +3037,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { verifyStayOnWhilePluggedCleared(false); } + @Test public void testIsActiveSupervisionApp() throws Exception { when(mServiceContext.resources .getString(R.string.config_defaultSupervisionProfileOwnerComponent)) @@ -2968,11 +3050,12 @@ public class DevicePolicyManagerTest extends DpmTestBase { final DevicePolicyManagerInternal dpmi = LocalServices.getService(DevicePolicyManagerInternal.class); - assertTrue(dpmi.isActiveSupervisionApp(PROFILE_ADMIN)); + assertThat(dpmi.isActiveSupervisionApp(PROFILE_ADMIN)).isTrue(); } // Test if lock timeout on managed profile is handled correctly depending on whether profile // uses separate challenge. + @Test public void testSetMaximumTimeToLockProfile() throws Exception { final int PROFILE_USER = 15; final int PROFILE_ADMIN = UserHandle.getUid(PROFILE_USER, 19436); @@ -3039,6 +3122,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { verifyScreenTimeoutCall(Long.MAX_VALUE, UserHandle.USER_SYSTEM); } + @Test public void testSetRequiredStrongAuthTimeout_DeviceOwner() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); @@ -3055,8 +3139,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { getServices().buildMock.isDebuggable = false; dpm.setRequiredStrongAuthTimeout(admin1, MAX_MINUS_ONE_MINUTE); - assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), MAX_MINUS_ONE_MINUTE); - assertEquals(dpm.getRequiredStrongAuthTimeout(null), MAX_MINUS_ONE_MINUTE); + assertThat(MAX_MINUS_ONE_MINUTE).isEqualTo(dpm.getRequiredStrongAuthTimeout(admin1)); + assertThat(MAX_MINUS_ONE_MINUTE).isEqualTo(dpm.getRequiredStrongAuthTimeout(null)); verify(getServices().systemProperties, never()).getLong(anyString(), anyLong()); @@ -3067,45 +3151,47 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm.setRequiredStrongAuthTimeout(admin1, 0); // aggregation should be the default if unset by any admin - assertEquals(dpm.getRequiredStrongAuthTimeout(null), - DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS); + assertThat(DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS) + .isEqualTo(dpm.getRequiredStrongAuthTimeout(null)); // admin not participating by default - assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), 0); + assertThat(dpm.getRequiredStrongAuthTimeout(admin1)).isEqualTo(0); //clamping from the top dpm.setRequiredStrongAuthTimeout(admin1, DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS + ONE_MINUTE); - assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), - DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS); - assertEquals(dpm.getRequiredStrongAuthTimeout(null), - DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS); + assertThat(DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS) + .isEqualTo(dpm.getRequiredStrongAuthTimeout(admin1)); + assertThat(DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS) + .isEqualTo(dpm.getRequiredStrongAuthTimeout(null)); // 0 means the admin is not participating, so default should be returned dpm.setRequiredStrongAuthTimeout(admin1, 0); - assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), 0); - assertEquals(dpm.getRequiredStrongAuthTimeout(null), - DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS); + assertThat(dpm.getRequiredStrongAuthTimeout(admin1)).isEqualTo(0); + assertThat(DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS) + .isEqualTo(dpm.getRequiredStrongAuthTimeout(null)); // clamping from the bottom dpm.setRequiredStrongAuthTimeout(admin1, MINIMUM_STRONG_AUTH_TIMEOUT_MS - ONE_MINUTE); - assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), MINIMUM_STRONG_AUTH_TIMEOUT_MS); - assertEquals(dpm.getRequiredStrongAuthTimeout(null), MINIMUM_STRONG_AUTH_TIMEOUT_MS); + assertThat(dpm.getRequiredStrongAuthTimeout(admin1)) + .isEqualTo(MINIMUM_STRONG_AUTH_TIMEOUT_MS); + assertThat(dpm.getRequiredStrongAuthTimeout(null)) + .isEqualTo(MINIMUM_STRONG_AUTH_TIMEOUT_MS); // values within range dpm.setRequiredStrongAuthTimeout(admin1, MIN_PLUS_ONE_MINUTE); - assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), MIN_PLUS_ONE_MINUTE); - assertEquals(dpm.getRequiredStrongAuthTimeout(null), MIN_PLUS_ONE_MINUTE); + assertThat(dpm.getRequiredStrongAuthTimeout(admin1)).isEqualTo(MIN_PLUS_ONE_MINUTE); + assertThat(dpm.getRequiredStrongAuthTimeout(null)).isEqualTo(MIN_PLUS_ONE_MINUTE); dpm.setRequiredStrongAuthTimeout(admin1, MAX_MINUS_ONE_MINUTE); - assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), MAX_MINUS_ONE_MINUTE); - assertEquals(dpm.getRequiredStrongAuthTimeout(null), MAX_MINUS_ONE_MINUTE); + assertThat(dpm.getRequiredStrongAuthTimeout(admin1)).isEqualTo(MAX_MINUS_ONE_MINUTE); + assertThat(dpm.getRequiredStrongAuthTimeout(null)).isEqualTo(MAX_MINUS_ONE_MINUTE); // reset to default dpm.setRequiredStrongAuthTimeout(admin1, 0); - assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), 0); - assertEquals(dpm.getRequiredStrongAuthTimeout(null), - DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS); + assertThat(dpm.getRequiredStrongAuthTimeout(admin1)).isEqualTo(0); + assertThat(DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS) + .isEqualTo(dpm.getRequiredStrongAuthTimeout(null)); // negative value assertExpectException(IllegalArgumentException.class, /* messageRegex= */ null, @@ -3130,8 +3216,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { private void setup_DeviceAdminFeatureOff() throws Exception { when(getServices().packageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)) .thenReturn(false); - when(getServices().ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)) - .thenReturn(false); + when(getServices().ipackageManager + .hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)).thenReturn(false); initializeDpms(); when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(false); when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true)) @@ -3141,6 +3227,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; } + @Test public void testIsProvisioningAllowed_DeviceAdminFeatureOff() throws Exception { setup_DeviceAdminFeatureOff(); mContext.packageName = admin1.getPackageName(); @@ -3153,6 +3240,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false); } + @Test public void testCheckProvisioningPreCondition_DeviceAdminFeatureOff() throws Exception { setup_DeviceAdminFeatureOff(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); @@ -3170,8 +3258,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { } private void setup_ManagedProfileFeatureOff() throws Exception { - when(getServices().ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)) - .thenReturn(false); + when(getServices().ipackageManager + .hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)).thenReturn(false); initializeDpms(); when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(false); when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true)) @@ -3181,6 +3269,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; } + @Test public void testIsProvisioningAllowed_ManagedProfileFeatureOff() throws Exception { setup_ManagedProfileFeatureOff(); mContext.packageName = admin1.getPackageName(); @@ -3202,6 +3291,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, false); } + @Test public void testCheckProvisioningPreCondition_ManagedProfileFeatureOff() throws Exception { setup_ManagedProfileFeatureOff(); mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); @@ -3233,8 +3323,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { } private void setup_nonSplitUser_firstBoot_primaryUser() throws Exception { - when(getServices().ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)) - .thenReturn(true); + 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)) .thenReturn(true); @@ -3244,6 +3334,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; } + @Test public void testIsProvisioningAllowed_nonSplitUser_firstBoot_primaryUser() throws Exception { setup_nonSplitUser_firstBoot_primaryUser(); mContext.packageName = admin1.getPackageName(); @@ -3257,6 +3348,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { false /* because of non-split user */); } + @Test public void testCheckProvisioningPreCondition_nonSplitUser_firstBoot_primaryUser() throws Exception { setup_nonSplitUser_firstBoot_primaryUser(); @@ -3275,8 +3367,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { } private void setup_nonSplitUser_afterDeviceSetup_primaryUser() throws Exception { - when(getServices().ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)) - .thenReturn(true); + 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)) .thenReturn(true); @@ -3302,6 +3394,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { true)).thenReturn(true); } + @Test public void testIsProvisioningAllowed_nonSplitUser_afterDeviceSetup_primaryUser() throws Exception { setup_nonSplitUser_afterDeviceSetup_primaryUser(); @@ -3318,6 +3411,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { false/* because of non-split user */); } + @Test public void testCheckProvisioningPreCondition_nonSplitUser_afterDeviceSetup_primaryUser() throws Exception { setup_nonSplitUser_afterDeviceSetup_primaryUser(); @@ -3335,6 +3429,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { DevicePolicyManager.CODE_NOT_SYSTEM_USER_SPLIT); } + @Test public void testProvisioning_nonSplitUser_withDo_primaryUser() throws Exception { setup_nonSplitUser_withDo_primaryUser(); mContext.packageName = admin1.getPackageName(); @@ -3361,6 +3456,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID); } + @Test public void testProvisioning_nonSplitUser_withDo_primaryUser_restrictedBySystem() throws Exception { setup_nonSplitUser_withDo_primaryUser(); @@ -3388,6 +3484,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID); } + @Test public void testCheckCannotSetProfileOwnerWithDeviceOwner() throws Exception { setup_nonSplitUser_withDo_primaryUser(); final int managedProfileUserId = 18; @@ -3399,10 +3496,11 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.callerPermissions.addAll(OWNER_SETUP_PERMISSIONS); setUpPackageManagerForFakeAdmin(admin1, managedProfileAdminUid, admin1); dpm.setActiveAdmin(admin1, false, userId); - assertFalse(dpm.setProfileOwner(admin1, null, userId)); + assertThat(dpm.setProfileOwner(admin1, null, userId)).isFalse(); mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS); } + @Test public void testCheckProvisioningPreCondition_nonSplitUser_attemptingComp() throws Exception { setup_nonSplitUser_withDo_primaryUser_ManagedProfile(); mContext.packageName = admin1.getPackageName(); @@ -3420,6 +3518,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { DpmMockContext.ANOTHER_PACKAGE_NAME, DpmMockContext.ANOTHER_UID); } + @Test public void testCheckProvisioningPreCondition_nonSplitUser_comp_cannot_remove_profile() throws Exception { setup_nonSplitUser_withDo_primaryUser_ManagedProfile(); @@ -3449,8 +3548,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { } private void setup_splitUser_firstBoot_systemUser() throws Exception { - when(getServices().ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)) - .thenReturn(true); + 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)) .thenReturn(false); @@ -3459,6 +3558,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; } + @Test public void testIsProvisioningAllowed_splitUser_firstBoot_systemUser() throws Exception { setup_splitUser_firstBoot_systemUser(); mContext.packageName = admin1.getPackageName(); @@ -3473,6 +3573,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { false/* because calling uid is system user */); } + @Test public void testCheckProvisioningPreCondition_splitUser_firstBoot_systemUser() throws Exception { setup_splitUser_firstBoot_systemUser(); @@ -3491,8 +3592,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { } private void setup_splitUser_afterDeviceSetup_systemUser() throws Exception { - when(getServices().ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)) - .thenReturn(true); + 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)) .thenReturn(false); @@ -3501,6 +3602,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; } + @Test public void testIsProvisioningAllowed_splitUser_afterDeviceSetup_systemUser() throws Exception { setup_splitUser_afterDeviceSetup_systemUser(); mContext.packageName = admin1.getPackageName(); @@ -3517,6 +3619,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { false/* because calling uid is system user */); } + @Test public void testCheckProvisioningPreCondition_splitUser_afterDeviceSetup_systemUser() throws Exception { setup_splitUser_afterDeviceSetup_systemUser(); @@ -3535,8 +3638,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { } private void setup_splitUser_firstBoot_primaryUser() throws Exception { - when(getServices().ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)) - .thenReturn(true); + when(getServices().ipackageManager + .hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)).thenReturn(true); when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(true); when(getServices().userManager.canAddMoreManagedProfiles(CALLER_USER_HANDLE, true)).thenReturn(true); @@ -3545,6 +3648,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.binder.callingUid = DpmMockContext.CALLER_UID; } + @Test public void testIsProvisioningAllowed_splitUser_firstBoot_primaryUser() throws Exception { setup_splitUser_firstBoot_primaryUser(); mContext.packageName = admin1.getPackageName(); @@ -3557,6 +3661,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, true); } + @Test public void testCheckProvisioningPreCondition_splitUser_firstBoot_primaryUser() throws Exception { setup_splitUser_firstBoot_primaryUser(); @@ -3575,8 +3680,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { } private void setup_splitUser_afterDeviceSetup_primaryUser() throws Exception { - when(getServices().ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)) - .thenReturn(true); + when(getServices().ipackageManager + .hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)).thenReturn(true); when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(true); when(getServices().userManager.canAddMoreManagedProfiles(CALLER_USER_HANDLE, true)).thenReturn(true); @@ -3585,6 +3690,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.binder.callingUid = DpmMockContext.CALLER_UID; } + @Test public void testIsProvisioningAllowed_splitUser_afterDeviceSetup_primaryUser() throws Exception { setup_splitUser_afterDeviceSetup_primaryUser(); @@ -3601,6 +3707,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { false/* because user setup completed */); } + @Test public void testCheckProvisioningPreCondition_splitUser_afterDeviceSetup_primaryUser() throws Exception { setup_splitUser_afterDeviceSetup_primaryUser(); @@ -3621,8 +3728,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { private void setup_provisionManagedProfileWithDeviceOwner_systemUser() throws Exception { setDeviceOwner(); - when(getServices().ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)) - .thenReturn(true); + 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)) .thenReturn(false); @@ -3631,6 +3738,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; } + @Test public void testIsProvisioningAllowed_provisionManagedProfileWithDeviceOwner_systemUser() throws Exception { setup_provisionManagedProfileWithDeviceOwner_systemUser(); @@ -3640,6 +3748,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { false /* can't provision managed profile on system user */); } + @Test public void testCheckProvisioningPreCondition_provisionManagedProfileWithDeviceOwner_systemUser() throws Exception { setup_provisionManagedProfileWithDeviceOwner_systemUser(); @@ -3651,8 +3760,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { private void setup_provisionManagedProfileWithDeviceOwner_primaryUser() throws Exception { setDeviceOwner(); - when(getServices().ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)) - .thenReturn(true); + when(getServices().ipackageManager + .hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)).thenReturn(true); when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(false); when(getServices().userManager.getProfileParent(CALLER_USER_HANDLE)) .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0)); @@ -3663,6 +3772,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.binder.callingUid = DpmMockContext.ANOTHER_UID; } + @Test public void testIsProvisioningAllowed_provisionManagedProfileWithDeviceOwner_primaryUser() throws Exception { setup_provisionManagedProfileWithDeviceOwner_primaryUser(); @@ -3671,6 +3781,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false); } + @Test public void testCheckProvisioningPreCondition_provisionManagedProfileWithDeviceOwner_primaryUser() throws Exception { setup_provisionManagedProfileWithDeviceOwner_primaryUser(); @@ -3684,8 +3795,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { private void setup_provisionManagedProfileCantRemoveUser_primaryUser() throws Exception { setDeviceOwner(); - when(getServices().ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)) - .thenReturn(true); + when(getServices().ipackageManager + .hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0)).thenReturn(true); when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(true); when(getServices().userManager.hasUserRestriction( eq(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE), @@ -3700,6 +3811,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.binder.callingUid = DpmMockContext.CALLER_UID; } + @Test public void testIsProvisioningAllowed_provisionManagedProfileCantRemoveUser_primaryUser() throws Exception { setup_provisionManagedProfileCantRemoveUser_primaryUser(); @@ -3708,6 +3820,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false); } + @Test public void testCheckProvisioningPreCondition_provisionManagedProfileCantRemoveUser_primaryUser() throws Exception { setup_provisionManagedProfileCantRemoveUser_primaryUser(); @@ -3716,6 +3829,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE); } + @Test public void testCheckProvisioningPreCondition_permission() { // GIVEN the permission MANAGE_PROFILE_AND_DEVICE_OWNERS is not granted assertExpectException(SecurityException.class, /* messageRegex =*/ null, @@ -3723,12 +3837,14 @@ public class DevicePolicyManagerTest extends DpmTestBase { DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, "some.package")); } + @Test public void testForceUpdateUserSetupComplete_permission() { // GIVEN the permission MANAGE_PROFILE_AND_DEVICE_OWNERS is not granted assertExpectException(SecurityException.class, /* messageRegex =*/ null, () -> dpm.forceUpdateUserSetupComplete()); } + @Test public void testForceUpdateUserSetupComplete_systemUser() { mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); // GIVEN calling from user 20 @@ -3737,6 +3853,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { () -> dpm.forceUpdateUserSetupComplete()); } + @Test public void testForceUpdateUserSetupComplete_userbuild() { mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; @@ -3753,14 +3870,15 @@ public class DevicePolicyManagerTest extends DpmTestBase { // GIVEN it's user build getServices().buildMock.isDebuggable = false; - assertTrue(dpms.hasUserSetupCompleted()); + assertThat(dpms.hasUserSetupCompleted()).isTrue(); dpm.forceUpdateUserSetupComplete(); // THEN the state in dpms is not changed - assertTrue(dpms.hasUserSetupCompleted()); + assertThat(dpms.hasUserSetupCompleted()).isTrue(); } + @Test public void testForceUpdateUserSetupComplete_userDebugbuild() { mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; @@ -3777,12 +3895,12 @@ public class DevicePolicyManagerTest extends DpmTestBase { // GIVEN it's userdebug build getServices().buildMock.isDebuggable = true; - assertTrue(dpms.hasUserSetupCompleted()); + assertThat(dpms.hasUserSetupCompleted()).isTrue(); dpm.forceUpdateUserSetupComplete(); // THEN the state in dpms is not changed - assertFalse(dpms.hasUserSetupCompleted()); + assertThat(dpms.hasUserSetupCompleted()).isFalse(); } private void clearDeviceOwner() throws Exception { @@ -3795,6 +3913,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { }); } + @Test public void testGetLastSecurityLogRetrievalTime() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); @@ -3806,7 +3925,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { .thenReturn(true); // No logs were retrieved so far. - assertEquals(-1, dpm.getLastSecurityLogRetrievalTime()); + assertThat(dpm.getLastSecurityLogRetrievalTime()).isEqualTo(-1); // Enabling logging should not change the timestamp. dpm.setSecurityLoggingEnabled(admin1, true); @@ -3814,55 +3933,56 @@ public class DevicePolicyManagerTest extends DpmTestBase { .securityLogSetLoggingEnabledProperty(true); when(getServices().settings.securityLogGetLoggingEnabledProperty()) .thenReturn(true); - assertEquals(-1, dpm.getLastSecurityLogRetrievalTime()); + assertThat(dpm.getLastSecurityLogRetrievalTime()).isEqualTo(-1); // Retrieving the logs should update the timestamp. final long beforeRetrieval = System.currentTimeMillis(); dpm.retrieveSecurityLogs(admin1); final long firstSecurityLogRetrievalTime = dpm.getLastSecurityLogRetrievalTime(); final long afterRetrieval = System.currentTimeMillis(); - assertTrue(firstSecurityLogRetrievalTime >= beforeRetrieval); - assertTrue(firstSecurityLogRetrievalTime <= afterRetrieval); + assertThat(firstSecurityLogRetrievalTime >= beforeRetrieval).isTrue(); + assertThat(firstSecurityLogRetrievalTime <= afterRetrieval).isTrue(); // Retrieving the pre-boot logs should update the timestamp. Thread.sleep(2); dpm.retrievePreRebootSecurityLogs(admin1); final long secondSecurityLogRetrievalTime = dpm.getLastSecurityLogRetrievalTime(); - assertTrue(secondSecurityLogRetrievalTime > firstSecurityLogRetrievalTime); + assertThat(secondSecurityLogRetrievalTime > firstSecurityLogRetrievalTime).isTrue(); // Checking the timestamp again should not change it. Thread.sleep(2); - assertEquals(secondSecurityLogRetrievalTime, dpm.getLastSecurityLogRetrievalTime()); + assertThat(dpm.getLastSecurityLogRetrievalTime()).isEqualTo(secondSecurityLogRetrievalTime); // Retrieving the logs again should update the timestamp. dpm.retrieveSecurityLogs(admin1); final long thirdSecurityLogRetrievalTime = dpm.getLastSecurityLogRetrievalTime(); - assertTrue(thirdSecurityLogRetrievalTime > secondSecurityLogRetrievalTime); + assertThat(thirdSecurityLogRetrievalTime > secondSecurityLogRetrievalTime).isTrue(); // Disabling logging should not change the timestamp. Thread.sleep(2); dpm.setSecurityLoggingEnabled(admin1, false); - assertEquals(thirdSecurityLogRetrievalTime, dpm.getLastSecurityLogRetrievalTime()); + assertThat(dpm.getLastSecurityLogRetrievalTime()).isEqualTo(thirdSecurityLogRetrievalTime); // Restarting the DPMS should not lose the timestamp. initializeDpms(); - assertEquals(thirdSecurityLogRetrievalTime, dpm.getLastSecurityLogRetrievalTime()); + assertThat(dpm.getLastSecurityLogRetrievalTime()).isEqualTo(thirdSecurityLogRetrievalTime); // Any uid holding MANAGE_USERS permission can retrieve the timestamp. mContext.binder.callingUid = 1234567; mContext.callerPermissions.add(permission.MANAGE_USERS); - assertEquals(thirdSecurityLogRetrievalTime, dpm.getLastSecurityLogRetrievalTime()); + assertThat(dpm.getLastSecurityLogRetrievalTime()).isEqualTo(thirdSecurityLogRetrievalTime); mContext.callerPermissions.remove(permission.MANAGE_USERS); // System can retrieve the timestamp. mContext.binder.clearCallingIdentity(); - assertEquals(thirdSecurityLogRetrievalTime, dpm.getLastSecurityLogRetrievalTime()); + assertThat(dpm.getLastSecurityLogRetrievalTime()).isEqualTo(thirdSecurityLogRetrievalTime); // Removing the device owner should clear the timestamp. clearDeviceOwner(); - assertEquals(-1, dpm.getLastSecurityLogRetrievalTime()); + assertThat(dpm.getLastSecurityLogRetrievalTime()).isEqualTo(-1); } + @Test public void testSetConfiguredNetworksLockdownStateWithDO() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); @@ -3875,6 +3995,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0); } + @Test public void testSetConfiguredNetworksLockdownStateWithPO() throws Exception { setupProfileOwner(); assertExpectException(SecurityException.class, null, @@ -3883,6 +4004,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0); } + @Test public void testSetConfiguredNetworksLockdownStateWithPOOfOrganizationOwnedDevice() throws Exception { setupProfileOwner(); @@ -3896,6 +4018,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0); } + @Test public void testSetSystemSettingFailWithNonWhitelistedSettings() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); @@ -3903,6 +4026,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm.setSystemSetting(admin1, Settings.System.SCREEN_BRIGHTNESS_FOR_VR, "0")); } + @Test public void testSetSystemSettingWithDO() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); @@ -3911,6 +4035,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { Settings.System.SCREEN_BRIGHTNESS, "0", UserHandle.USER_SYSTEM); } + @Test public void testSetSystemSettingWithPO() throws Exception { setupProfileOwner(); dpm.setSystemSetting(admin1, Settings.System.SCREEN_BRIGHTNESS, "0"); @@ -3918,6 +4043,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { Settings.System.SCREEN_BRIGHTNESS, "0", CALLER_USER_HANDLE); } + @Test public void testSetAutoTimeEnabledModifiesSetting() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); @@ -3928,6 +4054,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 0); } + @Test public void testSetAutoTimeEnabledWithPOOnUser0() throws Exception { mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; setupProfileOwnerOnUser0(); @@ -3938,6 +4065,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 0); } + @Test public void testSetAutoTimeEnabledFailWithPONotOnUser0() throws Exception { setupProfileOwner(); assertExpectException(SecurityException.class, null, @@ -3945,6 +4073,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(getServices().settings, never()).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 0); } + @Test public void testSetAutoTimeEnabledWithPOOfOrganizationOwnedDevice() throws Exception { setupProfileOwner(); configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE); @@ -3956,6 +4085,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 0); } + @Test public void testSetAutoTimeZoneEnabledModifiesSetting() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); @@ -3966,6 +4096,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 0); } + @Test public void testSetAutoTimeZoneEnabledWithPOOnUser0() throws Exception { mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; setupProfileOwnerOnUser0(); @@ -3976,6 +4107,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 0); } + @Test public void testSetAutoTimeZoneEnabledFailWithPONotOnUser0() throws Exception { setupProfileOwner(); assertExpectException(SecurityException.class, null, @@ -3984,6 +4116,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { 0); } + @Test public void testSetAutoTimeZoneEnabledWithPOOfOrganizationOwnedDevice() throws Exception { setupProfileOwner(); configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE); @@ -3995,12 +4128,13 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 0); } + @Test public void testIsOrganizationOwnedDevice() throws Exception { // Set up the user manager to return correct user info addManagedProfile(admin1, DpmMockContext.CALLER_UID, admin1); // Any caller should be able to call this method. - assertFalse(dpm.isOrganizationOwnedDeviceWithManagedProfile()); + assertThat(dpm.isOrganizationOwnedDeviceWithManagedProfile()).isFalse(); configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE); verify(getServices().userManager).setUserRestriction( @@ -4008,13 +4142,14 @@ public class DevicePolicyManagerTest extends DpmTestBase { eq(true), eq(UserHandle.of(UserHandle.USER_SYSTEM))); - assertTrue(dpm.isOrganizationOwnedDeviceWithManagedProfile()); + assertThat(dpm.isOrganizationOwnedDeviceWithManagedProfile()).isTrue(); // A random caller from another user should also be able to get the right result. mContext.binder.callingUid = DpmMockContext.ANOTHER_UID; - assertTrue(dpm.isOrganizationOwnedDeviceWithManagedProfile()); + assertThat(dpm.isOrganizationOwnedDeviceWithManagedProfile()).isTrue(); } + @Test public void testMarkOrganizationOwnedDevice_baseRestrictionsAdded() throws Exception { addManagedProfile(admin1, DpmMockContext.CALLER_UID, admin1); @@ -4044,6 +4179,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { parentDpm.clearUserRestriction(admin1, UserManager.DISALLOW_ADD_USER)); } + @Test public void testSetTime() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); @@ -4051,11 +4187,13 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(getServices().alarmManager).setTime(0); } + @Test public void testSetTimeFailWithPO() throws Exception { setupProfileOwner(); assertExpectException(SecurityException.class, null, () -> dpm.setTime(admin1, 0)); } + @Test public void testSetTimeWithPOOfOrganizationOwnedDevice() throws Exception { setupProfileOwner(); configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE); @@ -4063,14 +4201,16 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(getServices().alarmManager).setTime(0); } + @Test public void testSetTimeWithAutoTimeOn() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); when(getServices().settings.settingsGlobalGetInt(Settings.Global.AUTO_TIME, 0)) .thenReturn(1); - assertFalse(dpm.setTime(admin1, 0)); + assertThat(dpm.setTime(admin1, 0)).isFalse(); } + @Test public void testSetTimeZone() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); @@ -4078,12 +4218,14 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(getServices().alarmManager).setTimeZone("Asia/Shanghai"); } + @Test public void testSetTimeZoneFailWithPO() throws Exception { setupProfileOwner(); assertExpectException(SecurityException.class, null, () -> dpm.setTimeZone(admin1, "Asia/Shanghai")); } + @Test public void testSetTimeZoneWithPOOfOrganizationOwnedDevice() throws Exception { setupProfileOwner(); configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE); @@ -4091,14 +4233,16 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(getServices().alarmManager).setTimeZone("Asia/Shanghai"); } + @Test public void testSetTimeZoneWithAutoTimeZoneOn() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); when(getServices().settings.settingsGlobalGetInt(Settings.Global.AUTO_TIME_ZONE, 0)) .thenReturn(1); - assertFalse(dpm.setTimeZone(admin1, "Asia/Shanghai")); + assertThat(dpm.setTimeZone(admin1, "Asia/Shanghai")).isFalse(); } + @Test public void testGetLastBugReportRequestTime() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); @@ -4115,39 +4259,40 @@ public class DevicePolicyManagerTest extends DpmTestBase { getServices().removeUser(CALLER_USER_HANDLE); // No bug reports were requested so far. - assertEquals(-1, dpm.getLastBugReportRequestTime()); + assertThat(dpm.getLastBugReportRequestTime()).isEqualTo(-1); // Requesting a bug report should update the timestamp. final long beforeRequest = System.currentTimeMillis(); dpm.requestBugreport(admin1); final long bugReportRequestTime = dpm.getLastBugReportRequestTime(); final long afterRequest = System.currentTimeMillis(); - assertTrue(bugReportRequestTime >= beforeRequest); - assertTrue(bugReportRequestTime <= afterRequest); + assertThat(bugReportRequestTime).isAtLeast(beforeRequest); + assertThat(bugReportRequestTime).isAtMost(afterRequest); // Checking the timestamp again should not change it. Thread.sleep(2); - assertEquals(bugReportRequestTime, dpm.getLastBugReportRequestTime()); + assertThat(dpm.getLastBugReportRequestTime()).isEqualTo(bugReportRequestTime); // Restarting the DPMS should not lose the timestamp. initializeDpms(); - assertEquals(bugReportRequestTime, dpm.getLastBugReportRequestTime()); + assertThat(dpm.getLastBugReportRequestTime()).isEqualTo(bugReportRequestTime); // Any uid holding MANAGE_USERS permission can retrieve the timestamp. mContext.binder.callingUid = 1234567; mContext.callerPermissions.add(permission.MANAGE_USERS); - assertEquals(bugReportRequestTime, dpm.getLastBugReportRequestTime()); + assertThat(dpm.getLastBugReportRequestTime()).isEqualTo(bugReportRequestTime); mContext.callerPermissions.remove(permission.MANAGE_USERS); // System can retrieve the timestamp. mContext.binder.clearCallingIdentity(); - assertEquals(bugReportRequestTime, dpm.getLastBugReportRequestTime()); + assertThat(dpm.getLastBugReportRequestTime()).isEqualTo(bugReportRequestTime); // Removing the device owner should clear the timestamp. clearDeviceOwner(); - assertEquals(-1, dpm.getLastBugReportRequestTime()); + assertThat(dpm.getLastBugReportRequestTime()).isEqualTo(-1); } + @Test public void testGetLastNetworkLogRetrievalTime() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); @@ -4165,57 +4310,58 @@ public class DevicePolicyManagerTest extends DpmTestBase { .thenReturn(true); // No logs were retrieved so far. - assertEquals(-1, dpm.getLastNetworkLogRetrievalTime()); + assertThat(dpm.getLastNetworkLogRetrievalTime()).isEqualTo(-1); // Attempting to retrieve logs without enabling logging should not change the timestamp. dpm.retrieveNetworkLogs(admin1, 0 /* batchToken */); - assertEquals(-1, dpm.getLastNetworkLogRetrievalTime()); + assertThat(dpm.getLastNetworkLogRetrievalTime()).isEqualTo(-1); // Enabling logging should not change the timestamp. dpm.setNetworkLoggingEnabled(admin1, true); - assertEquals(-1, dpm.getLastNetworkLogRetrievalTime()); + assertThat(dpm.getLastNetworkLogRetrievalTime()).isEqualTo(-1); // Retrieving the logs should update the timestamp. final long beforeRetrieval = System.currentTimeMillis(); dpm.retrieveNetworkLogs(admin1, 0 /* batchToken */); final long firstNetworkLogRetrievalTime = dpm.getLastNetworkLogRetrievalTime(); final long afterRetrieval = System.currentTimeMillis(); - assertTrue(firstNetworkLogRetrievalTime >= beforeRetrieval); - assertTrue(firstNetworkLogRetrievalTime <= afterRetrieval); + assertThat(firstNetworkLogRetrievalTime >= beforeRetrieval).isTrue(); + assertThat(firstNetworkLogRetrievalTime <= afterRetrieval).isTrue(); // Checking the timestamp again should not change it. Thread.sleep(2); - assertEquals(firstNetworkLogRetrievalTime, dpm.getLastNetworkLogRetrievalTime()); + assertThat(dpm.getLastNetworkLogRetrievalTime()).isEqualTo(firstNetworkLogRetrievalTime); // Retrieving the logs again should update the timestamp. dpm.retrieveNetworkLogs(admin1, 0 /* batchToken */); final long secondNetworkLogRetrievalTime = dpm.getLastNetworkLogRetrievalTime(); - assertTrue(secondNetworkLogRetrievalTime > firstNetworkLogRetrievalTime); + assertThat(secondNetworkLogRetrievalTime > firstNetworkLogRetrievalTime).isTrue(); // Disabling logging should not change the timestamp. Thread.sleep(2); dpm.setNetworkLoggingEnabled(admin1, false); - assertEquals(secondNetworkLogRetrievalTime, dpm.getLastNetworkLogRetrievalTime()); + assertThat(dpm.getLastNetworkLogRetrievalTime()).isEqualTo(secondNetworkLogRetrievalTime); // Restarting the DPMS should not lose the timestamp. initializeDpms(); - assertEquals(secondNetworkLogRetrievalTime, dpm.getLastNetworkLogRetrievalTime()); + assertThat(dpm.getLastNetworkLogRetrievalTime()).isEqualTo(secondNetworkLogRetrievalTime); // Any uid holding MANAGE_USERS permission can retrieve the timestamp. mContext.binder.callingUid = 1234567; mContext.callerPermissions.add(permission.MANAGE_USERS); - assertEquals(secondNetworkLogRetrievalTime, dpm.getLastNetworkLogRetrievalTime()); + assertThat(dpm.getLastNetworkLogRetrievalTime()).isEqualTo(secondNetworkLogRetrievalTime); mContext.callerPermissions.remove(permission.MANAGE_USERS); // System can retrieve the timestamp. mContext.binder.clearCallingIdentity(); - assertEquals(secondNetworkLogRetrievalTime, dpm.getLastNetworkLogRetrievalTime()); + assertThat(dpm.getLastNetworkLogRetrievalTime()).isEqualTo(secondNetworkLogRetrievalTime); // Removing the device owner should clear the timestamp. clearDeviceOwner(); - assertEquals(-1, dpm.getLastNetworkLogRetrievalTime()); + assertThat(dpm.getLastNetworkLogRetrievalTime()).isEqualTo(-1); } + @Test public void testGetBindDeviceAdminTargetUsers() throws Exception { // Setup device owner. mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; @@ -4268,9 +4414,9 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm.setLockTaskPackages(who, packages); MoreAsserts.assertEquals(packages, dpm.getLockTaskPackages(who)); for (String p : packages) { - assertTrue(dpm.isLockTaskPermitted(p)); + assertThat(dpm.isLockTaskPermitted(p)).isTrue(); } - assertFalse(dpm.isLockTaskPermitted("anotherPackage")); + assertThat(dpm.isLockTaskPermitted("anotherPackage")).isFalse(); // Test to see if set lock task features can be set dpm.setLockTaskFeatures(who, flags); verifyLockTaskState(userId, packages, flags); @@ -4283,11 +4429,12 @@ public class DevicePolicyManagerTest extends DpmTestBase { () -> dpm.setLockTaskPackages(who, packages)); assertExpectException(SecurityException.class, /* messageRegex =*/ null, () -> dpm.getLockTaskPackages(who)); - assertFalse(dpm.isLockTaskPermitted("doPackage1")); + assertThat(dpm.isLockTaskPermitted("doPackage1")).isFalse(); assertExpectException(SecurityException.class, /* messageRegex =*/ null, () -> dpm.setLockTaskFeatures(who, flags)); } + @Test public void testLockTaskPolicyForProfileOwner() throws Exception { // Setup a PO mContext.binder.callingUid = DpmMockContext.CALLER_UID; @@ -4315,9 +4462,11 @@ public class DevicePolicyManagerTest extends DpmTestBase { final int mpoFlags = DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS | DevicePolicyManager.LOCK_TASK_FEATURE_HOME | DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW; - verifyCanNotSetLockTask(MANAGED_PROFILE_ADMIN_UID, adminDifferentPackage, mpoPackages, mpoFlags); + verifyCanNotSetLockTask(MANAGED_PROFILE_ADMIN_UID, adminDifferentPackage, mpoPackages, + mpoFlags); } + @Test public void testLockTaskFeatures_IllegalArgumentException() throws Exception { // Setup a device owner. mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; @@ -4332,12 +4481,13 @@ public class DevicePolicyManagerTest extends DpmTestBase { () -> dpm.setLockTaskFeatures(admin1, flags)); } + @Test public void testSecondaryLockscreen_profileOwner() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_UID; // Initial state is disabled. - assertFalse(dpm.isSecondaryLockscreenEnabled(UserHandle.of( - CALLER_USER_HANDLE))); + assertThat(dpm.isSecondaryLockscreenEnabled(UserHandle.of( + CALLER_USER_HANDLE))).isFalse(); // Profile owner can set enabled state. setAsProfileOwner(admin1); @@ -4345,8 +4495,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { .getString(R.string.config_defaultSupervisionProfileOwnerComponent)) .thenReturn(admin1.flattenToString()); dpm.setSecondaryLockscreenEnabled(admin1, true); - assertTrue(dpm.isSecondaryLockscreenEnabled(UserHandle.of( - CALLER_USER_HANDLE))); + assertThat(dpm.isSecondaryLockscreenEnabled(UserHandle.of( + CALLER_USER_HANDLE))).isTrue(); // Managed profile managed by different package is unaffiliated - cannot set enabled. final int managedProfileUserId = 15; @@ -4359,11 +4509,13 @@ public class DevicePolicyManagerTest extends DpmTestBase { () -> dpm.setSecondaryLockscreenEnabled(adminDifferentPackage, false)); } + @Test public void testSecondaryLockscreen_deviceOwner() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; // Initial state is disabled. - assertFalse(dpm.isSecondaryLockscreenEnabled(UserHandle.of(UserHandle.USER_SYSTEM))); + assertThat(dpm.isSecondaryLockscreenEnabled(UserHandle.of(UserHandle.USER_SYSTEM))) + .isFalse(); // Device owners can set enabled state. setupDeviceOwner(); @@ -4371,14 +4523,16 @@ public class DevicePolicyManagerTest extends DpmTestBase { .getString(R.string.config_defaultSupervisionProfileOwnerComponent)) .thenReturn(admin1.flattenToString()); dpm.setSecondaryLockscreenEnabled(admin1, true); - assertTrue(dpm.isSecondaryLockscreenEnabled(UserHandle.of(UserHandle.USER_SYSTEM))); + assertThat(dpm.isSecondaryLockscreenEnabled(UserHandle.of(UserHandle.USER_SYSTEM))) + .isTrue(); } + @Test public void testSecondaryLockscreen_nonOwner() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_UID; // Initial state is disabled. - assertFalse(dpm.isSecondaryLockscreenEnabled(UserHandle.of(CALLER_USER_HANDLE))); + assertThat(dpm.isSecondaryLockscreenEnabled(UserHandle.of(CALLER_USER_HANDLE))).isFalse(); // Non-DO/PO cannot set enabled state. when(mServiceContext.resources @@ -4386,9 +4540,10 @@ public class DevicePolicyManagerTest extends DpmTestBase { .thenReturn(admin1.flattenToString()); assertExpectException(SecurityException.class, /* messageRegex= */ null, () -> dpm.setSecondaryLockscreenEnabled(admin1, true)); - assertFalse(dpm.isSecondaryLockscreenEnabled(UserHandle.of(CALLER_USER_HANDLE))); + assertThat(dpm.isSecondaryLockscreenEnabled(UserHandle.of(CALLER_USER_HANDLE))).isFalse(); } + @Test public void testSecondaryLockscreen_nonSupervisionApp() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_UID; @@ -4403,13 +4558,13 @@ public class DevicePolicyManagerTest extends DpmTestBase { eq(CALLER_USER_HANDLE)); // Initial state is disabled. - assertFalse(dpm.isSecondaryLockscreenEnabled(UserHandle.of(CALLER_USER_HANDLE))); + assertThat(dpm.isSecondaryLockscreenEnabled(UserHandle.of(CALLER_USER_HANDLE))).isFalse(); // Caller is Profile Owner, but no supervision app is configured. setAsProfileOwner(admin1); assertExpectException(SecurityException.class, "is not the default supervision component", () -> dpm.setSecondaryLockscreenEnabled(admin1, true)); - assertFalse(dpm.isSecondaryLockscreenEnabled(UserHandle.of(CALLER_USER_HANDLE))); + assertThat(dpm.isSecondaryLockscreenEnabled(UserHandle.of(CALLER_USER_HANDLE))).isFalse(); // Caller is Profile Owner, but is not the default configured supervision app. when(mServiceContext.resources @@ -4417,22 +4572,23 @@ public class DevicePolicyManagerTest extends DpmTestBase { .thenReturn(admin2.flattenToString()); assertExpectException(SecurityException.class, "is not the default supervision component", () -> dpm.setSecondaryLockscreenEnabled(admin1, true)); - assertFalse(dpm.isSecondaryLockscreenEnabled(UserHandle.of(CALLER_USER_HANDLE))); + assertThat(dpm.isSecondaryLockscreenEnabled(UserHandle.of(CALLER_USER_HANDLE))).isFalse(); } + @Test public void testIsDeviceManaged() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); // The device owner itself, any uid holding MANAGE_USERS permission and the system can // find out that the device has a device owner. - assertTrue(dpm.isDeviceManaged()); + assertThat(dpm.isDeviceManaged()).isTrue(); mContext.binder.callingUid = 1234567; mContext.callerPermissions.add(permission.MANAGE_USERS); - assertTrue(dpm.isDeviceManaged()); + assertThat(dpm.isDeviceManaged()).isTrue(); mContext.callerPermissions.remove(permission.MANAGE_USERS); mContext.binder.clearCallingIdentity(); - assertTrue(dpm.isDeviceManaged()); + assertThat(dpm.isDeviceManaged()).isTrue(); clearDeviceOwner(); @@ -4440,12 +4596,13 @@ public class DevicePolicyManagerTest extends DpmTestBase { // not have a device owner. mContext.binder.callingUid = 1234567; mContext.callerPermissions.add(permission.MANAGE_USERS); - assertFalse(dpm.isDeviceManaged()); + assertThat(dpm.isDeviceManaged()).isFalse(); mContext.callerPermissions.remove(permission.MANAGE_USERS); mContext.binder.clearCallingIdentity(); - assertFalse(dpm.isDeviceManaged()); + assertThat(dpm.isDeviceManaged()).isFalse(); } + @Test public void testDeviceOwnerOrganizationName() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); @@ -4453,23 +4610,24 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm.setOrganizationName(admin1, "organization"); // Device owner can retrieve organization managing the device. - assertEquals("organization", dpm.getDeviceOwnerOrganizationName()); + assertThat(dpm.getDeviceOwnerOrganizationName()).isEqualTo("organization"); // Any uid holding MANAGE_USERS permission can retrieve organization managing the device. mContext.binder.callingUid = 1234567; mContext.callerPermissions.add(permission.MANAGE_USERS); - assertEquals("organization", dpm.getDeviceOwnerOrganizationName()); + assertThat(dpm.getDeviceOwnerOrganizationName()).isEqualTo("organization"); mContext.callerPermissions.remove(permission.MANAGE_USERS); // System can retrieve organization managing the device. mContext.binder.clearCallingIdentity(); - assertEquals("organization", dpm.getDeviceOwnerOrganizationName()); + assertThat(dpm.getDeviceOwnerOrganizationName()).isEqualTo("organization"); // Removing the device owner clears the organization managing the device. clearDeviceOwner(); - assertNull(dpm.getDeviceOwnerOrganizationName()); + assertThat(dpm.getDeviceOwnerOrganizationName()).isNull(); } + @Test public void testWipeDataManagedProfile() throws Exception { final int MANAGED_PROFILE_USER_ID = 15; final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 19436); @@ -4489,6 +4647,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { MANAGED_PROFILE_USER_ID); } + @Test public void testWipeDataManagedProfileDisallowed() throws Exception { final int MANAGED_PROFILE_USER_ID = 15; final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 19436); @@ -4512,6 +4671,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { () -> dpm.wipeData(0)); } + @Test public void testWipeDataDeviceOwner() throws Exception { setDeviceOwner(); when(getServices().userManager.getUserRestrictionSource( @@ -4527,6 +4687,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { /*wipeEuicc=*/ eq(false)); } + @Test public void testWipeEuiccDataEnabled() throws Exception { setDeviceOwner(); when(getServices().userManager.getUserRestrictionSource( @@ -4542,6 +4703,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { /*wipeEuicc=*/ eq(true)); } + @Test public void testWipeDataDeviceOwnerDisallowed() throws Exception { setDeviceOwner(); when(getServices().userManager.getUserRestrictionSource( @@ -4556,6 +4718,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { () -> dpm.wipeData(0)); } + @Test public void testMaximumFailedPasswordAttemptsReachedManagedProfile() throws Exception { final int MANAGED_PROFILE_USER_ID = 15; final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 19436); @@ -4588,6 +4751,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { verifyZeroInteractions(getServices().recoverySystem); } + @Test public void testMaximumFailedPasswordAttemptsReachedManagedProfileDisallowed() throws Exception { final int MANAGED_PROFILE_USER_ID = 15; @@ -4621,6 +4785,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { verifyZeroInteractions(getServices().recoverySystem); } + @Test public void testMaximumFailedPasswordAttemptsReachedDeviceOwner() throws Exception { setDeviceOwner(); when(getServices().userManager.getUserRestrictionSource( @@ -4643,6 +4808,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { /*wipeEuicc=*/ eq(false)); } + @Test public void testMaximumFailedPasswordAttemptsReachedDeviceOwnerDisallowed() throws Exception { setDeviceOwner(); when(getServices().userManager.getUserRestrictionSource( @@ -4664,6 +4830,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { .removeUserEvenWhenDisallowed(anyInt()); } + @Test public void testMaximumFailedDevicePasswordAttemptsReachedOrgOwnedManagedProfile() throws Exception { final int MANAGED_PROFILE_USER_ID = 15; @@ -4679,16 +4846,16 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; dpm.setMaximumFailedPasswordsForWipe(admin1, 3); - assertEquals(3, dpm.getMaximumFailedPasswordsForWipe(admin1)); - assertEquals(3, dpm.getMaximumFailedPasswordsForWipe(null)); + assertThat(dpm.getMaximumFailedPasswordsForWipe(admin1)).isEqualTo(3); + assertThat(dpm.getMaximumFailedPasswordsForWipe(null)).isEqualTo(3); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; mContext.callerPermissions.add(permission.BIND_DEVICE_ADMIN); - assertEquals(3, dpm.getMaximumFailedPasswordsForWipe(null, UserHandle.USER_SYSTEM)); + assertThat(dpm.getMaximumFailedPasswordsForWipe(null, UserHandle.USER_SYSTEM)).isEqualTo(3); // Check that primary will be wiped as a result of failed primary user unlock attempts. - assertEquals(UserHandle.USER_SYSTEM, - dpm.getProfileWithMinimumFailedPasswordsForWipe(UserHandle.USER_SYSTEM)); + assertThat(dpm.getProfileWithMinimumFailedPasswordsForWipe(UserHandle.USER_SYSTEM)) + .isEqualTo(UserHandle.USER_SYSTEM); // Failed password attempts on the parent user are taken into account, as there isn't a // separate work challenge. @@ -4702,6 +4869,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { /*wipeEuicc=*/ eq(false)); } + @Test public void testMaximumFailedProfilePasswordAttemptsReachedOrgOwnedManagedProfile() throws Exception { final int MANAGED_PROFILE_USER_ID = 15; @@ -4724,14 +4892,15 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; mContext.callerPermissions.add(permission.BIND_DEVICE_ADMIN); - assertEquals(0, dpm.getMaximumFailedPasswordsForWipe(null, UserHandle.USER_SYSTEM)); - assertEquals(3, dpm.getMaximumFailedPasswordsForWipe(null, MANAGED_PROFILE_USER_ID)); + assertThat(dpm.getMaximumFailedPasswordsForWipe(null, UserHandle.USER_SYSTEM)).isEqualTo(0); + assertThat(dpm.getMaximumFailedPasswordsForWipe(null, MANAGED_PROFILE_USER_ID)) + .isEqualTo(3); // Check that the policy is not affecting primary profile challenge. - assertEquals(UserHandle.USER_NULL, - dpm.getProfileWithMinimumFailedPasswordsForWipe(UserHandle.USER_SYSTEM)); + assertThat(dpm.getProfileWithMinimumFailedPasswordsForWipe(UserHandle.USER_SYSTEM)) + .isEqualTo(UserHandle.USER_NULL); // Check that primary will be wiped as a result of failed profile unlock attempts. - assertEquals(UserHandle.USER_SYSTEM, - dpm.getProfileWithMinimumFailedPasswordsForWipe(MANAGED_PROFILE_USER_ID)); + assertThat(dpm.getProfileWithMinimumFailedPasswordsForWipe(MANAGED_PROFILE_USER_ID)) + .isEqualTo(UserHandle.USER_SYSTEM); // Simulate three failed attempts at solving the separate challenge. dpm.reportFailedPasswordAttempt(MANAGED_PROFILE_USER_ID); @@ -4744,6 +4913,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { /*wipeEuicc=*/ eq(false)); } + @Test public void testGetPermissionGrantState() throws Exception { final String permission = "some.permission"; final String app1 = "com.example.app1"; @@ -4766,10 +4936,10 @@ public class DevicePolicyManagerTest extends DpmTestBase { // System can retrieve permission grant state. mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; mContext.packageName = "android"; - assertEquals(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED, - dpm.getPermissionGrantState(null, app1, permission)); - assertEquals(DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT, - dpm.getPermissionGrantState(null, app2, permission)); + assertThat(dpm.getPermissionGrantState(null, app1, permission)) + .isEqualTo(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED); + assertThat(dpm.getPermissionGrantState(null, app2, permission)) + .isEqualTo(DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT); // A regular app cannot retrieve permission grant state. mContext.binder.callingUid = setupPackageInPackageManager(app1, 1); @@ -4781,12 +4951,13 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.binder.callingUid = DpmMockContext.CALLER_UID; mContext.packageName = admin1.getPackageName(); setAsProfileOwner(admin1); - assertEquals(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED, - dpm.getPermissionGrantState(admin1, app1, permission)); - assertEquals(DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT, - dpm.getPermissionGrantState(admin1, app2, permission)); + assertThat(dpm.getPermissionGrantState(admin1, app1, permission)) + .isEqualTo(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED); + assertThat(dpm.getPermissionGrantState(admin1, app2, permission)) + .isEqualTo(DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT); } + @Test public void testResetPasswordWithToken() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); @@ -4801,27 +4972,26 @@ public class DevicePolicyManagerTest extends DpmTestBase { when(getServices().lockPatternUtils.addEscrowToken(eq(token), eq(UserHandle.USER_SYSTEM), nullable(EscrowTokenStateChangeCallback.class))) .thenReturn(handle); - assertTrue(dpm.setResetPasswordToken(admin1, token)); + assertThat(dpm.setResetPasswordToken(admin1, token)).isTrue(); // test password activation - when(getServices().lockPatternUtils.isEscrowTokenActive(eq(handle), eq(UserHandle.USER_SYSTEM))) - .thenReturn(true); - assertTrue(dpm.isResetPasswordTokenActive(admin1)); + when(getServices().lockPatternUtils.isEscrowTokenActive(handle, UserHandle.USER_SYSTEM)) + .thenReturn(true); + assertThat(dpm.isResetPasswordTokenActive(admin1)).isTrue(); // test reset password with token when(getServices().lockPatternUtils.setLockCredentialWithToken( - eq(LockscreenCredential.createPassword(password)), - eq(handle), eq(token), - eq(UserHandle.USER_SYSTEM))) - .thenReturn(true); - assertTrue(dpm.resetPasswordWithToken(admin1, password, token, 0)); + LockscreenCredential.createPassword(password), handle, token, + UserHandle.USER_SYSTEM)).thenReturn(true); + assertThat(dpm.resetPasswordWithToken(admin1, password, token, 0)).isTrue(); // test removing a token - when(getServices().lockPatternUtils.removeEscrowToken(eq(handle), eq(UserHandle.USER_SYSTEM))) + when(getServices().lockPatternUtils.removeEscrowToken(handle, UserHandle.USER_SYSTEM)) .thenReturn(true); - assertTrue(dpm.clearResetPasswordToken(admin1)); + assertThat(dpm.clearResetPasswordToken(admin1)).isTrue(); } + @Test public void testIsActivePasswordSufficient() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; mContext.packageName = admin1.getPackageName(); @@ -4841,11 +5011,11 @@ public class DevicePolicyManagerTest extends DpmTestBase { PasswordMetrics passwordMetricsNoSymbols = computeForPassword("abcdXYZ5".getBytes()); setActivePasswordState(passwordMetricsNoSymbols); - assertTrue(dpm.isActivePasswordSufficient()); + assertThat(dpm.isActivePasswordSufficient()).isTrue(); initializeDpms(); reset(mContext.spiedContext); - assertTrue(dpm.isActivePasswordSufficient()); + assertThat(dpm.isActivePasswordSufficient()).isTrue(); // This call simulates the user entering the password for the first time after a reboot. // This causes password metrics to be reloaded into memory. Until this happens, @@ -4854,23 +5024,24 @@ public class DevicePolicyManagerTest extends DpmTestBase { // requirements. This is a known limitation of the current implementation of // isActivePasswordSufficient() - see b/34218769. setActivePasswordState(passwordMetricsNoSymbols); - assertTrue(dpm.isActivePasswordSufficient()); + assertThat(dpm.isActivePasswordSufficient()).isTrue(); dpm.setPasswordMinimumSymbols(admin1, 1); // This assertion would fail if we had not called setActivePasswordState() again after // initializeDpms() - see previous comment. - assertFalse(dpm.isActivePasswordSufficient()); + assertThat(dpm.isActivePasswordSufficient()).isFalse(); initializeDpms(); reset(mContext.spiedContext); - assertFalse(dpm.isActivePasswordSufficient()); + assertThat(dpm.isActivePasswordSufficient()).isFalse(); PasswordMetrics passwordMetricsWithSymbols = computeForPassword("abcd.XY5".getBytes()); setActivePasswordState(passwordMetricsWithSymbols); - assertTrue(dpm.isActivePasswordSufficient()); + assertThat(dpm.isActivePasswordSufficient()).isTrue(); } + @Test public void testIsActivePasswordSufficient_noLockScreen() throws Exception { // If there is no lock screen, the password is considered empty no matter what, because // it provides no security. @@ -4885,7 +5056,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { .thenReturn(new PasswordMetrics(CREDENTIAL_TYPE_NONE)); // If no password requirements are set, isActivePasswordSufficient should succeed. - assertTrue(dpm.isActivePasswordSufficient()); + assertThat(dpm.isActivePasswordSufficient()).isTrue(); // Now set some password quality requirements. dpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); @@ -4900,9 +5071,10 @@ public class DevicePolicyManagerTest extends DpmTestBase { MockUtils.checkUserHandle(userHandle)); // The active (nonexistent) password doesn't comply with the requirements. - assertFalse(dpm.isActivePasswordSufficient()); + assertThat(dpm.isActivePasswordSufficient()).isFalse(); } + @Test public void testIsPasswordSufficientAfterProfileUnification() throws Exception { final int managedProfileUserId = CALLER_USER_HANDLE; final int managedProfileAdminUid = @@ -4921,13 +5093,13 @@ public class DevicePolicyManagerTest extends DpmTestBase { // Numeric password is compliant with current requirement (QUALITY_NUMERIC set explicitly // on the parent admin) - assertTrue(dpm.isPasswordSufficientAfterProfileUnification(UserHandle.USER_SYSTEM, - UserHandle.USER_NULL)); + assertThat(dpm.isPasswordSufficientAfterProfileUnification(UserHandle.USER_SYSTEM, + UserHandle.USER_NULL)).isTrue(); // Numeric password is not compliant if profile is to be unified: the profile has a // QUALITY_ALPHABETIC policy on itself which will be enforced on the password after // unification. - assertFalse(dpm.isPasswordSufficientAfterProfileUnification(UserHandle.USER_SYSTEM, - managedProfileUserId)); + assertThat(dpm.isPasswordSufficientAfterProfileUnification(UserHandle.USER_SYSTEM, + managedProfileUserId)).isFalse(); } private void setActivePasswordState(PasswordMetrics passwordMetrics) @@ -4961,6 +5133,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.binder.restoreCallingIdentity(ident); } + @Test public void testIsCurrentInputMethodSetByOwnerForDeviceOwner() throws Exception { final String currentIme = Settings.Secure.DEFAULT_INPUT_METHOD; final Uri currentImeUri = Settings.Secure.getUriFor(currentIme); @@ -4976,70 +5149,71 @@ public class DevicePolicyManagerTest extends DpmTestBase { // First and second user set IMEs manually. mContext.binder.callingUid = firstUserSystemUid; - assertFalse(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse(); mContext.binder.callingUid = secondUserSystemUid; - assertFalse(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse(); // Device owner changes IME for first user. mContext.binder.callingUid = deviceOwnerUid; - when(getServices().settings.settingsSecureGetStringForUser(currentIme, UserHandle.USER_SYSTEM)) - .thenReturn("ime1"); + when(getServices().settings.settingsSecureGetStringForUser(currentIme, + UserHandle.USER_SYSTEM)).thenReturn("ime1"); dpm.setSecureSetting(admin1, currentIme, "ime2"); verify(getServices().settings).settingsSecurePutStringForUser(currentIme, "ime2", UserHandle.USER_SYSTEM); reset(getServices().settings); dpms.notifyChangeToContentObserver(currentImeUri, UserHandle.USER_SYSTEM); mContext.binder.callingUid = firstUserSystemUid; - assertTrue(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isTrue(); mContext.binder.callingUid = secondUserSystemUid; - assertFalse(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse(); // Second user changes IME manually. dpms.notifyChangeToContentObserver(currentImeUri, CALLER_USER_HANDLE); mContext.binder.callingUid = firstUserSystemUid; - assertTrue(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isTrue(); mContext.binder.callingUid = secondUserSystemUid; - assertFalse(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse(); // First user changes IME manually. dpms.notifyChangeToContentObserver(currentImeUri, UserHandle.USER_SYSTEM); mContext.binder.callingUid = firstUserSystemUid; - assertFalse(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse(); mContext.binder.callingUid = secondUserSystemUid; - assertFalse(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse(); // Device owner changes IME for first user again. mContext.binder.callingUid = deviceOwnerUid; - when(getServices().settings.settingsSecureGetStringForUser(currentIme, UserHandle.USER_SYSTEM)) - .thenReturn("ime2"); + when(getServices().settings.settingsSecureGetStringForUser(currentIme, + UserHandle.USER_SYSTEM)).thenReturn("ime2"); dpm.setSecureSetting(admin1, currentIme, "ime3"); verify(getServices().settings).settingsSecurePutStringForUser(currentIme, "ime3", UserHandle.USER_SYSTEM); dpms.notifyChangeToContentObserver(currentImeUri, UserHandle.USER_SYSTEM); mContext.binder.callingUid = firstUserSystemUid; - assertTrue(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isTrue(); mContext.binder.callingUid = secondUserSystemUid; - assertFalse(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse(); // Restarting the DPMS should not lose information. initializeDpms(); mContext.binder.callingUid = firstUserSystemUid; - assertTrue(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isTrue(); mContext.binder.callingUid = secondUserSystemUid; - assertFalse(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse(); // Device owner can find out whether it set the current IME itself. mContext.binder.callingUid = deviceOwnerUid; - assertTrue(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isTrue(); // Removing the device owner should clear the information that it set the current IME. clearDeviceOwner(); mContext.binder.callingUid = firstUserSystemUid; - assertFalse(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse(); mContext.binder.callingUid = secondUserSystemUid; - assertFalse(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse(); } + @Test public void testIsCurrentInputMethodSetByOwnerForProfileOwner() throws Exception { final String currentIme = Settings.Secure.DEFAULT_INPUT_METHOD; final Uri currentImeUri = Settings.Secure.getUriFor(currentIme); @@ -5055,9 +5229,9 @@ public class DevicePolicyManagerTest extends DpmTestBase { // First and second user set IMEs manually. mContext.binder.callingUid = firstUserSystemUid; - assertFalse(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse(); mContext.binder.callingUid = secondUserSystemUid; - assertFalse(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse(); // Profile owner changes IME for second user. mContext.binder.callingUid = profileOwnerUid; @@ -5069,23 +5243,23 @@ public class DevicePolicyManagerTest extends DpmTestBase { reset(getServices().settings); dpms.notifyChangeToContentObserver(currentImeUri, CALLER_USER_HANDLE); mContext.binder.callingUid = firstUserSystemUid; - assertFalse(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse(); mContext.binder.callingUid = secondUserSystemUid; - assertTrue(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isTrue(); // First user changes IME manually. dpms.notifyChangeToContentObserver(currentImeUri, UserHandle.USER_SYSTEM); mContext.binder.callingUid = firstUserSystemUid; - assertFalse(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse(); mContext.binder.callingUid = secondUserSystemUid; - assertTrue(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isTrue(); // Second user changes IME manually. dpms.notifyChangeToContentObserver(currentImeUri, CALLER_USER_HANDLE); mContext.binder.callingUid = firstUserSystemUid; - assertFalse(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse(); mContext.binder.callingUid = secondUserSystemUid; - assertFalse(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse(); // Profile owner changes IME for second user again. mContext.binder.callingUid = profileOwnerUid; @@ -5096,29 +5270,30 @@ public class DevicePolicyManagerTest extends DpmTestBase { CALLER_USER_HANDLE); dpms.notifyChangeToContentObserver(currentImeUri, CALLER_USER_HANDLE); mContext.binder.callingUid = firstUserSystemUid; - assertFalse(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse(); mContext.binder.callingUid = secondUserSystemUid; - assertTrue(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isTrue(); // Restarting the DPMS should not lose information. initializeDpms(); mContext.binder.callingUid = firstUserSystemUid; - assertFalse(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse(); mContext.binder.callingUid = secondUserSystemUid; - assertTrue(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isTrue(); // Profile owner can find out whether it set the current IME itself. mContext.binder.callingUid = profileOwnerUid; - assertTrue(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isTrue(); // Removing the profile owner should clear the information that it set the current IME. dpm.clearProfileOwner(admin1); mContext.binder.callingUid = firstUserSystemUid; - assertFalse(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse(); mContext.binder.callingUid = secondUserSystemUid; - assertFalse(dpm.isCurrentInputMethodSetByOwner()); + assertThat(dpm.isCurrentInputMethodSetByOwner()).isFalse(); } + @Test public void testSetPermittedCrossProfileNotificationListeners_unavailableForDo() throws Exception { // Set up a device owner. @@ -5127,6 +5302,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertSetPermittedCrossProfileNotificationListenersUnavailable(mContext.binder.callingUid); } + @Test public void testSetPermittedCrossProfileNotificationListeners_unavailableForPoOnUser() throws Exception { // Set up a profile owner. @@ -5141,23 +5317,24 @@ public class DevicePolicyManagerTest extends DpmTestBase { final int userId = UserHandle.getUserId(adminUid); final String packageName = "some.package"; - assertFalse(dpms.setPermittedCrossProfileNotificationListeners( - admin1, Collections.singletonList(packageName))); - assertNull(dpms.getPermittedCrossProfileNotificationListeners(admin1)); + assertThat(dpms.setPermittedCrossProfileNotificationListeners( + admin1, Collections.singletonList(packageName))).isFalse(); + assertThat(dpms.getPermittedCrossProfileNotificationListeners(admin1)).isNull(); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; - assertTrue(dpms.isNotificationListenerServicePermitted(packageName, userId)); + assertThat(dpms.isNotificationListenerServicePermitted(packageName, userId)).isTrue(); // Attempt to set to empty list (which means no listener is allowlisted) mContext.binder.callingUid = adminUid; - assertFalse(dpms.setPermittedCrossProfileNotificationListeners( - admin1, Collections.emptyList())); - assertNull(dpms.getPermittedCrossProfileNotificationListeners(admin1)); + assertThat(dpms.setPermittedCrossProfileNotificationListeners( + admin1, Collections.emptyList())).isFalse(); + assertThat(dpms.getPermittedCrossProfileNotificationListeners(admin1)).isNull(); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; - assertTrue(dpms.isNotificationListenerServicePermitted(packageName, userId)); + assertThat(dpms.isNotificationListenerServicePermitted(packageName, userId)).isTrue(); } + @Test public void testIsNotificationListenerServicePermitted_onlySystemCanCall() throws Exception { // Set up a managed profile final int MANAGED_PROFILE_USER_ID = 15; @@ -5171,8 +5348,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { UserHandle.USER_SYSTEM, // We check the packageInfo from the primary user. /*appId=*/ 12345, /*flags=*/ 0); - assertTrue(dpms.setPermittedCrossProfileNotificationListeners( - admin1, Collections.singletonList(permittedListener))); + assertThat(dpms.setPermittedCrossProfileNotificationListeners( + admin1, Collections.singletonList(permittedListener))).isTrue(); // isNotificationListenerServicePermitted should throw if not called from System. assertExpectException(SecurityException.class, /* messageRegex= */ null, @@ -5180,10 +5357,11 @@ public class DevicePolicyManagerTest extends DpmTestBase { permittedListener, MANAGED_PROFILE_USER_ID)); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; - assertTrue(dpms.isNotificationListenerServicePermitted( - permittedListener, MANAGED_PROFILE_USER_ID)); + assertThat(dpms.isNotificationListenerServicePermitted( + permittedListener, MANAGED_PROFILE_USER_ID)).isTrue(); } + @Test public void testSetPermittedCrossProfileNotificationListeners_managedProfile() throws Exception { // Set up a managed profile @@ -5212,63 +5390,64 @@ public class DevicePolicyManagerTest extends DpmTestBase { ++appId, ApplicationInfo.FLAG_SYSTEM); // By default all packages are allowed - assertNull(dpms.getPermittedCrossProfileNotificationListeners(admin1)); + assertThat(dpms.getPermittedCrossProfileNotificationListeners(admin1)).isNull(); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; - assertTrue(dpms.isNotificationListenerServicePermitted( - permittedListener, MANAGED_PROFILE_USER_ID)); - assertTrue(dpms.isNotificationListenerServicePermitted( - notPermittedListener, MANAGED_PROFILE_USER_ID)); - assertTrue(dpms.isNotificationListenerServicePermitted( - systemListener, MANAGED_PROFILE_USER_ID)); + assertThat(dpms.isNotificationListenerServicePermitted( + permittedListener, MANAGED_PROFILE_USER_ID)).isTrue(); + assertThat(dpms.isNotificationListenerServicePermitted( + notPermittedListener, MANAGED_PROFILE_USER_ID)).isTrue(); + assertThat(dpms.isNotificationListenerServicePermitted( + systemListener, MANAGED_PROFILE_USER_ID)).isTrue(); // Setting only one package in the allowlist mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; - assertTrue(dpms.setPermittedCrossProfileNotificationListeners( - admin1, Collections.singletonList(permittedListener))); + assertThat(dpms.setPermittedCrossProfileNotificationListeners( + admin1, Collections.singletonList(permittedListener))).isTrue(); final List<String> permittedListeners = dpms.getPermittedCrossProfileNotificationListeners(admin1); - assertEquals(1, permittedListeners.size()); - assertEquals(permittedListener, permittedListeners.get(0)); + assertThat(permittedListeners.size()).isEqualTo(1); + assertThat(permittedListeners.get(0)).isEqualTo(permittedListener); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; - assertTrue(dpms.isNotificationListenerServicePermitted( - permittedListener, MANAGED_PROFILE_USER_ID)); - assertFalse(dpms.isNotificationListenerServicePermitted( - notPermittedListener, MANAGED_PROFILE_USER_ID)); + assertThat(dpms.isNotificationListenerServicePermitted( + permittedListener, MANAGED_PROFILE_USER_ID)).isTrue(); + assertThat(dpms.isNotificationListenerServicePermitted( + notPermittedListener, MANAGED_PROFILE_USER_ID)).isFalse(); // System packages are always allowed (even if not in the allowlist) - assertTrue(dpms.isNotificationListenerServicePermitted( - systemListener, MANAGED_PROFILE_USER_ID)); + assertThat(dpms.isNotificationListenerServicePermitted( + systemListener, MANAGED_PROFILE_USER_ID)).isTrue(); // Setting an empty allowlist - only system listeners allowed mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; - assertTrue(dpms.setPermittedCrossProfileNotificationListeners( - admin1, Collections.emptyList())); - assertEquals(0, dpms.getPermittedCrossProfileNotificationListeners(admin1).size()); + assertThat(dpms.setPermittedCrossProfileNotificationListeners( + admin1, Collections.emptyList())).isTrue(); + assertThat(dpms.getPermittedCrossProfileNotificationListeners(admin1).size()).isEqualTo(0); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; - assertFalse(dpms.isNotificationListenerServicePermitted( - permittedListener, MANAGED_PROFILE_USER_ID)); - assertFalse(dpms.isNotificationListenerServicePermitted( - notPermittedListener, MANAGED_PROFILE_USER_ID)); + assertThat(dpms.isNotificationListenerServicePermitted( + permittedListener, MANAGED_PROFILE_USER_ID)).isFalse(); + assertThat(dpms.isNotificationListenerServicePermitted( + notPermittedListener, MANAGED_PROFILE_USER_ID)).isFalse(); // System packages are always allowed (even if not in the allowlist) - assertTrue(dpms.isNotificationListenerServicePermitted( - systemListener, MANAGED_PROFILE_USER_ID)); + assertThat(dpms.isNotificationListenerServicePermitted( + systemListener, MANAGED_PROFILE_USER_ID)).isTrue(); // Setting a null allowlist - all listeners allowed mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; - assertTrue(dpms.setPermittedCrossProfileNotificationListeners(admin1, null)); - assertNull(dpms.getPermittedCrossProfileNotificationListeners(admin1)); + assertThat(dpms.setPermittedCrossProfileNotificationListeners(admin1, null)).isTrue(); + assertThat(dpms.getPermittedCrossProfileNotificationListeners(admin1)).isNull(); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; - assertTrue(dpms.isNotificationListenerServicePermitted( - permittedListener, MANAGED_PROFILE_USER_ID)); - assertTrue(dpms.isNotificationListenerServicePermitted( - notPermittedListener, MANAGED_PROFILE_USER_ID)); - assertTrue(dpms.isNotificationListenerServicePermitted( - systemListener, MANAGED_PROFILE_USER_ID)); + assertThat(dpms.isNotificationListenerServicePermitted( + permittedListener, MANAGED_PROFILE_USER_ID)).isTrue(); + assertThat(dpms.isNotificationListenerServicePermitted( + notPermittedListener, MANAGED_PROFILE_USER_ID)).isTrue(); + assertThat(dpms.isNotificationListenerServicePermitted( + systemListener, MANAGED_PROFILE_USER_ID)).isTrue(); } + @Test public void testSetPermittedCrossProfileNotificationListeners_doesNotAffectPrimaryProfile() throws Exception { // Set up a managed profile @@ -5291,36 +5470,37 @@ public class DevicePolicyManagerTest extends DpmTestBase { ++appId, ApplicationInfo.FLAG_SYSTEM); // By default all packages are allowed (for all profiles) - assertNull(dpms.getPermittedCrossProfileNotificationListeners(admin1)); + assertThat(dpms.getPermittedCrossProfileNotificationListeners(admin1)).isNull(); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; - assertTrue(dpms.isNotificationListenerServicePermitted( - nonSystemPackage, MANAGED_PROFILE_USER_ID)); - assertTrue(dpms.isNotificationListenerServicePermitted( - systemListener, MANAGED_PROFILE_USER_ID)); - assertTrue(dpms.isNotificationListenerServicePermitted( - nonSystemPackage, UserHandle.USER_SYSTEM)); - assertTrue(dpms.isNotificationListenerServicePermitted( - systemListener, UserHandle.USER_SYSTEM)); + assertThat(dpms.isNotificationListenerServicePermitted( + nonSystemPackage, MANAGED_PROFILE_USER_ID)).isTrue(); + assertThat(dpms.isNotificationListenerServicePermitted( + systemListener, MANAGED_PROFILE_USER_ID)).isTrue(); + assertThat(dpms.isNotificationListenerServicePermitted( + nonSystemPackage, UserHandle.USER_SYSTEM)).isTrue(); + assertThat(dpms.isNotificationListenerServicePermitted( + systemListener, UserHandle.USER_SYSTEM)).isTrue(); // Setting an empty allowlist - only system listeners allowed in managed profile, but // all allowed in primary profile mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; - assertTrue(dpms.setPermittedCrossProfileNotificationListeners( - admin1, Collections.emptyList())); - assertEquals(0, dpms.getPermittedCrossProfileNotificationListeners(admin1).size()); + assertThat(dpms.setPermittedCrossProfileNotificationListeners( + admin1, Collections.emptyList())).isTrue(); + assertThat(dpms.getPermittedCrossProfileNotificationListeners(admin1).size()).isEqualTo(0); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; - assertFalse(dpms.isNotificationListenerServicePermitted( - nonSystemPackage, MANAGED_PROFILE_USER_ID)); - assertTrue(dpms.isNotificationListenerServicePermitted( - systemListener, MANAGED_PROFILE_USER_ID)); - assertTrue(dpms.isNotificationListenerServicePermitted( - nonSystemPackage, UserHandle.USER_SYSTEM)); - assertTrue(dpms.isNotificationListenerServicePermitted( - systemListener, UserHandle.USER_SYSTEM)); + assertThat(dpms.isNotificationListenerServicePermitted( + nonSystemPackage, MANAGED_PROFILE_USER_ID)).isFalse(); + assertThat(dpms.isNotificationListenerServicePermitted( + systemListener, MANAGED_PROFILE_USER_ID)).isTrue(); + assertThat(dpms.isNotificationListenerServicePermitted( + nonSystemPackage, UserHandle.USER_SYSTEM)).isTrue(); + assertThat(dpms.isNotificationListenerServicePermitted( + systemListener, UserHandle.USER_SYSTEM)).isTrue(); } + @Test public void testGetOwnerInstalledCaCertsForDeviceOwner() throws Exception { mServiceContext.packageName = mRealTestContext.getPackageName(); mServiceContext.binder.callingUid = DpmMockContext.SYSTEM_UID; @@ -5330,6 +5510,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { verifyCanGetOwnerInstalledCaCerts(admin1, mAdmin1Context); } + @Test public void testGetOwnerInstalledCaCertsForProfileOwner() throws Exception { mServiceContext.packageName = mRealTestContext.getPackageName(); mServiceContext.binder.callingUid = DpmMockContext.SYSTEM_UID; @@ -5340,6 +5521,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { verifyCantGetOwnerInstalledCaCertsProfileOwnerRemoval(admin1, mAdmin1Context); } + @Test public void testGetOwnerInstalledCaCertsForDelegate() throws Exception { mServiceContext.packageName = mRealTestContext.getPackageName(); mServiceContext.binder.callingUid = DpmMockContext.SYSTEM_UID; @@ -5359,6 +5541,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { verifyCantGetOwnerInstalledCaCertsProfileOwnerRemoval(null, caller); } + @Test public void testDisallowSharingIntoProfileSetRestriction() { when(mServiceContext.resources.getString(R.string.config_managed_provisioning_package)) .thenReturn("com.android.managedprovisioning"); @@ -5371,6 +5554,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { verifyDataSharingChangedBroadcast(); } + @Test public void testDisallowSharingIntoProfileClearRestriction() { when(mServiceContext.resources.getString(R.string.config_managed_provisioning_package)) .thenReturn("com.android.managedprovisioning"); @@ -5383,6 +5567,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { verifyDataSharingChangedBroadcast(); } + @Test public void testDisallowSharingIntoProfileUnchanged() { RestrictionsListener listener = new RestrictionsListener(mContext); listener.onUserRestrictionsChanged(CALLER_USER_HANDLE, new Bundle(), new Bundle()); @@ -5399,6 +5584,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { MockUtils.checkUserHandle(UserHandle.USER_SYSTEM)); } + @Test public void testOverrideApnAPIsFailWithPO() throws Exception { setupProfileOwner(); ApnSetting apn = (new ApnSetting.Builder()) @@ -5446,13 +5632,14 @@ public class DevicePolicyManagerTest extends DpmTestBase { runAsCaller(callerContext, dpms, (dpm) -> { when(getServices().keyChainConnection.getService().installCaCertificate(caCert)) .thenReturn(alias); - assertTrue(dpm.installCaCert(caller, caCert)); + assertThat(dpm.installCaCert(caller, caCert)).isTrue(); when(getServices().keyChainConnection.getService().getUserCaAliases()) .thenReturn(asSlice(new String[] {alias})); }); - getServices().injectBroadcast(mServiceContext, new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED) - .putExtra(Intent.EXTRA_USER_HANDLE, callerUser.getIdentifier()), + getServices().injectBroadcast(mServiceContext, + new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED) + .putExtra(Intent.EXTRA_USER_HANDLE, callerUser.getIdentifier()), callerUser.getIdentifier()); flushTasks(dpms); @@ -5461,25 +5648,27 @@ public class DevicePolicyManagerTest extends DpmTestBase { // Device Owner / Profile Owner can find out which CA certs were installed by itself. runAsCaller(admin1Context, dpms, (dpm) -> { final List<String> installedCaCerts = dpm.getOwnerInstalledCaCerts(callerUser); - assertEquals(Collections.singletonList(alias), installedCaCerts); + assertThat(installedCaCerts).isEqualTo(Collections.singletonList(alias)); ownerInstalledCaCerts.addAll(installedCaCerts); }); // Restarting the DPMS should not lose information. initializeDpms(); - runAsCaller(admin1Context, dpms, (dpm) -> - assertEquals(ownerInstalledCaCerts, dpm.getOwnerInstalledCaCerts(callerUser))); + runAsCaller(admin1Context, dpms, + (dpm) -> assertThat(dpm.getOwnerInstalledCaCerts(callerUser)) + .isEqualTo(ownerInstalledCaCerts)); // System can find out which CA certs were installed by the Device Owner / Profile Owner. runAsCaller(serviceContext, dpms, (dpm) -> { - assertEquals(ownerInstalledCaCerts, dpm.getOwnerInstalledCaCerts(callerUser)); + assertThat(dpm.getOwnerInstalledCaCerts(callerUser)).isEqualTo(ownerInstalledCaCerts); // Remove the CA cert. reset(getServices().keyChainConnection.getService()); }); - getServices().injectBroadcast(mServiceContext, new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED) - .putExtra(Intent.EXTRA_USER_HANDLE, callerUser.getIdentifier()), + getServices().injectBroadcast(mServiceContext, + new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED) + .putExtra(Intent.EXTRA_USER_HANDLE, callerUser.getIdentifier()), callerUser.getIdentifier()); flushTasks(dpms); @@ -5516,14 +5705,15 @@ public class DevicePolicyManagerTest extends DpmTestBase { runAsCaller(callerContext, dpms, (dpm) -> { when(getServices().keyChainConnection.getService().installCaCertificate(caCert)) .thenReturn(alias); - assertTrue(dpm.installCaCert(callerName, caCert)); + assertThat(dpm.installCaCert(callerName, caCert)).isTrue(); }); // Fake the CA cert as having been installed when(getServices().keyChainConnection.getService().getUserCaAliases()) .thenReturn(asSlice(new String[] {alias})); - getServices().injectBroadcast(mServiceContext, new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED) - .putExtra(Intent.EXTRA_USER_HANDLE, callerUser.getIdentifier()), + getServices().injectBroadcast(mServiceContext, + new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED) + .putExtra(Intent.EXTRA_USER_HANDLE, callerUser.getIdentifier()), callerUser.getIdentifier()); flushTasks(dpms); @@ -5532,8 +5722,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { runAsCaller(serviceContext, dpms, (dpm) -> { final List<String> ownerInstalledCaCerts = dpm.getOwnerInstalledCaCerts(callerUser); - assertNotNull(ownerInstalledCaCerts); - assertTrue(ownerInstalledCaCerts.isEmpty()); + assertThat(ownerInstalledCaCerts).isNotNull(); + assertThat(ownerInstalledCaCerts.isEmpty()).isTrue(); }); } @@ -5541,9 +5731,10 @@ public class DevicePolicyManagerTest extends DpmTestBase { int[] gotFlags = DevicePolicyManagerService.translateIdAttestationFlags(attestationFlags); Arrays.sort(gotFlags); Arrays.sort(expectedFlags); - assertTrue(Arrays.equals(expectedFlags, gotFlags)); + assertThat(Arrays.equals(expectedFlags, gotFlags)).isTrue(); } + @Test public void testTranslationOfIdAttestationFlag() { int[] allIdTypes = new int[]{ID_TYPE_SERIAL, ID_TYPE_IMEI, ID_TYPE_MEID}; int[] correspondingAttUtilsTypes = new int[]{ @@ -5551,7 +5742,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { AttestationUtils.ID_TYPE_MEID}; // Test translation of zero flags - assertNull(DevicePolicyManagerService.translateIdAttestationFlags(0)); + assertThat(DevicePolicyManagerService.translateIdAttestationFlags(0)).isNull(); // Test translation of the ID_TYPE_BASE_INFO flag, which should yield an empty, but // non-null array @@ -5578,39 +5769,41 @@ public class DevicePolicyManagerTest extends DpmTestBase { AttestationUtils.ID_TYPE_MEID}); } + @Test public void testRevertDeviceOwnership_noMetadataFile() throws Exception { setDeviceOwner(); initializeDpms(); - assertFalse(getMockTransferMetadataManager().metadataFileExists()); - assertTrue(dpms.isDeviceOwner(admin1, UserHandle.USER_SYSTEM)); - assertTrue(dpms.isAdminActive(admin1, UserHandle.USER_SYSTEM)); - } - - // @FlakyTest(bugId = 148934649) - // public void testRevertDeviceOwnership_adminAndDeviceMigrated() throws Exception { - // DpmTestUtils.writeInputStreamToFile( - // getRawStream(com.android.frameworks.servicestests.R.raw.active_admin_migrated), - // getDeviceOwnerPoliciesFile()); - // DpmTestUtils.writeInputStreamToFile( - // getRawStream(com.android.frameworks.servicestests.R.raw.device_owner_migrated), - // getDeviceOwnerFile()); - // assertDeviceOwnershipRevertedWithFakeTransferMetadata(); - // } - - // @FlakyTest(bugId = 148934649) - // public void testRevertDeviceOwnership_deviceNotMigrated() - // throws Exception { - // DpmTestUtils.writeInputStreamToFile( - // getRawStream(com.android.frameworks.servicestests.R.raw.active_admin_migrated), - // getDeviceOwnerPoliciesFile()); - // DpmTestUtils.writeInputStreamToFile( - // getRawStream(com.android.frameworks.servicestests.R.raw.device_owner_not_migrated), - // getDeviceOwnerFile()); - // assertDeviceOwnershipRevertedWithFakeTransferMetadata(); - // } - - public void testRevertDeviceOwnership_adminAndDeviceNotMigrated() - throws Exception { + assertThat(getMockTransferMetadataManager().metadataFileExists()).isFalse(); + assertThat(dpms.isDeviceOwner(admin1, UserHandle.USER_SYSTEM)).isTrue(); + assertThat(dpms.isAdminActive(admin1, UserHandle.USER_SYSTEM)).isTrue(); + } + + @FlakyTest(bugId = 148934649) + @Test + public void testRevertDeviceOwnership_adminAndDeviceMigrated() throws Exception { + DpmTestUtils.writeInputStreamToFile( + getRawStream(com.android.frameworks.servicestests.R.raw.active_admin_migrated), + getDeviceOwnerPoliciesFile()); + DpmTestUtils.writeInputStreamToFile( + getRawStream(com.android.frameworks.servicestests.R.raw.device_owner_migrated), + getDeviceOwnerFile()); + assertDeviceOwnershipRevertedWithFakeTransferMetadata(); + } + + @FlakyTest(bugId = 148934649) + @Test + public void testRevertDeviceOwnership_deviceNotMigrated() throws Exception { + DpmTestUtils.writeInputStreamToFile( + getRawStream(com.android.frameworks.servicestests.R.raw.active_admin_migrated), + getDeviceOwnerPoliciesFile()); + DpmTestUtils.writeInputStreamToFile( + getRawStream(com.android.frameworks.servicestests.R.raw.device_owner_not_migrated), + getDeviceOwnerFile()); + assertDeviceOwnershipRevertedWithFakeTransferMetadata(); + } + + @Test + public void testRevertDeviceOwnership_adminAndDeviceNotMigrated() throws Exception { DpmTestUtils.writeInputStreamToFile( getRawStream(com.android.frameworks.servicestests.R.raw.active_admin_not_migrated), getDeviceOwnerPoliciesFile()); @@ -5620,40 +5813,44 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertDeviceOwnershipRevertedWithFakeTransferMetadata(); } + @Test public void testRevertProfileOwnership_noMetadataFile() throws Exception { setupProfileOwner(); initializeDpms(); - assertFalse(getMockTransferMetadataManager().metadataFileExists()); - assertTrue(dpms.isProfileOwner(admin1, CALLER_USER_HANDLE)); - assertTrue(dpms.isAdminActive(admin1, CALLER_USER_HANDLE)); - } - - // @FlakyTest(bugId = 148934649) - // public void testRevertProfileOwnership_adminAndProfileMigrated() throws Exception { - // getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, 0, - // UserManager.USER_TYPE_PROFILE_MANAGED, UserHandle.USER_SYSTEM); - // DpmTestUtils.writeInputStreamToFile( - // getRawStream(com.android.frameworks.servicestests.R.raw.active_admin_migrated), - // getProfileOwnerPoliciesFile()); - // DpmTestUtils.writeInputStreamToFile( - // getRawStream(com.android.frameworks.servicestests.R.raw.profile_owner_migrated), - // getProfileOwnerFile()); - // assertProfileOwnershipRevertedWithFakeTransferMetadata(); - // } - - // @FlakyTest(bugId = 148934649) - // public void testRevertProfileOwnership_profileNotMigrated() throws Exception { - // getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, 0, - // UserManager.USER_TYPE_PROFILE_MANAGED, UserHandle.USER_SYSTEM); - // DpmTestUtils.writeInputStreamToFile( - // getRawStream(com.android.frameworks.servicestests.R.raw.active_admin_migrated), - // getProfileOwnerPoliciesFile()); - // DpmTestUtils.writeInputStreamToFile( - // getRawStream(com.android.frameworks.servicestests.R.raw.profile_owner_not_migrated), - // getProfileOwnerFile()); - // assertProfileOwnershipRevertedWithFakeTransferMetadata(); - // } + assertThat(getMockTransferMetadataManager().metadataFileExists()).isFalse(); + assertThat(dpms.isProfileOwner(admin1, CALLER_USER_HANDLE)).isTrue(); + assertThat(dpms.isAdminActive(admin1, CALLER_USER_HANDLE)).isTrue(); + } + + @FlakyTest(bugId = 148934649) + @Test + public void testRevertProfileOwnership_adminAndProfileMigrated() throws Exception { + getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, 0, + UserManager.USER_TYPE_PROFILE_MANAGED, UserHandle.USER_SYSTEM); + DpmTestUtils.writeInputStreamToFile( + getRawStream(com.android.frameworks.servicestests.R.raw.active_admin_migrated), + getProfileOwnerPoliciesFile()); + DpmTestUtils.writeInputStreamToFile( + getRawStream(com.android.frameworks.servicestests.R.raw.profile_owner_migrated), + getProfileOwnerFile()); + assertProfileOwnershipRevertedWithFakeTransferMetadata(); + } + @FlakyTest(bugId = 148934649) + @Test + public void testRevertProfileOwnership_profileNotMigrated() throws Exception { + getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, 0, + UserManager.USER_TYPE_PROFILE_MANAGED, UserHandle.USER_SYSTEM); + DpmTestUtils.writeInputStreamToFile( + getRawStream(com.android.frameworks.servicestests.R.raw.active_admin_migrated), + getProfileOwnerPoliciesFile()); + DpmTestUtils.writeInputStreamToFile( + getRawStream(com.android.frameworks.servicestests.R.raw.profile_owner_not_migrated), + getProfileOwnerFile()); + assertProfileOwnershipRevertedWithFakeTransferMetadata(); + } + + @Test public void testRevertProfileOwnership_adminAndProfileNotMigrated() throws Exception { getServices().addUser(CALLER_USER_HANDLE, 0, UserManager.USER_TYPE_PROFILE_MANAGED, UserHandle.USER_SYSTEM); @@ -5666,6 +5863,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertProfileOwnershipRevertedWithFakeTransferMetadata(); } + @Test public void testGrantDeviceIdsAccess_notToProfileOwner() throws Exception { setupProfileOwner(); configureContextForAccess(mContext, false); @@ -5674,6 +5872,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { () -> dpm.markProfileOwnerOnOrganizationOwnedDevice(admin2)); } + @Test public void testGrantDeviceIdsAccess_notByAuthorizedCaller() throws Exception { setupProfileOwner(); configureContextForAccess(mContext, false); @@ -5682,6 +5881,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { () -> dpm.markProfileOwnerOnOrganizationOwnedDevice(admin1)); } + @Test public void testGrantDeviceIdsAccess_byAuthorizedSystemCaller() throws Exception { setupProfileOwner(); @@ -5700,6 +5900,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { .thenReturn(UserHandle.SYSTEM); } + @Test public void testGrantDeviceIdsAccess_byAuthorizedManagedProvisioning() throws Exception { setupProfileOwner(); @@ -5719,6 +5920,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { } } + @Test public void testEnforceCallerCanRequestDeviceIdAttestation_deviceOwnerCaller() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; @@ -5741,6 +5943,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpms.getCallerIdentity(admin2))); } + @Test public void testEnforceCallerCanRequestDeviceIdAttestation_profileOwnerCaller() throws Exception { configureContextForAccess(mContext, false); @@ -5781,6 +5984,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { } } + @Test public void testEnforceCallerCanRequestDeviceIdAttestation_delegateCaller() throws Exception { setupProfileOwner(); markDelegatedCertInstallerAsInstalled(); @@ -5800,6 +6004,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpms.getCallerIdentity(null, DpmMockContext.DELEGATE_PACKAGE_NAME))); } + @Test public void testEnforceCallerCanRequestDeviceIdAttestation_delegateCallerWithoutPermissions() throws Exception { setupProfileOwner(); @@ -5821,6 +6026,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { }); } + @Test public void testGetPasswordComplexity_securityExceptionNotThrownForParentInstance() { mContext.binder.callingUid = DpmMockContext.CALLER_UID; when(getServices().packageManager.getPackagesForUid(DpmMockContext.CALLER_UID)).thenReturn( @@ -5830,9 +6036,10 @@ public class DevicePolicyManagerTest extends DpmTestBase { parentDpm.getPasswordComplexity(); - assertEquals(PASSWORD_COMPLEXITY_NONE, dpm.getPasswordComplexity()); + assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_NONE); } + @Test public void testGetPasswordComplexity_illegalStateExceptionIfLocked() { mContext.binder.callingUid = DpmMockContext.CALLER_UID; when(getServices().packageManager.getPackagesForUid(DpmMockContext.CALLER_UID)).thenReturn( @@ -5841,6 +6048,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertThrows(IllegalStateException.class, () -> dpm.getPasswordComplexity()); } + @Test public void testGetPasswordComplexity_securityExceptionWithoutPermissions() { mContext.binder.callingUid = DpmMockContext.CALLER_UID; when(getServices().packageManager.getPackagesForUid(DpmMockContext.CALLER_UID)).thenReturn( @@ -5850,6 +6058,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { } + @Test public void testGetPasswordComplexity_currentUserNoPassword() { mContext.binder.callingUid = DpmMockContext.CALLER_UID; when(getServices().packageManager.getPackagesForUid(DpmMockContext.CALLER_UID)).thenReturn( @@ -5859,9 +6068,10 @@ public class DevicePolicyManagerTest extends DpmTestBase { when(getServices().userManager.getCredentialOwnerProfile(CALLER_USER_HANDLE)) .thenReturn(CALLER_USER_HANDLE); - assertEquals(PASSWORD_COMPLEXITY_NONE, dpm.getPasswordComplexity()); + assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_NONE); } + @Test public void testGetPasswordComplexity_currentUserHasPassword() { mContext.binder.callingUid = DpmMockContext.CALLER_UID; when(getServices().packageManager.getPackagesForUid(DpmMockContext.CALLER_UID)).thenReturn( @@ -5874,9 +6084,10 @@ public class DevicePolicyManagerTest extends DpmTestBase { .getUserPasswordMetrics(CALLER_USER_HANDLE)) .thenReturn(computeForPassword("asdf".getBytes())); - assertEquals(PASSWORD_COMPLEXITY_MEDIUM, dpm.getPasswordComplexity()); + assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_MEDIUM); } + @Test public void testGetPasswordComplexity_unifiedChallengeReturnsParentUserPassword() { mContext.binder.callingUid = DpmMockContext.CALLER_UID; when(getServices().packageManager.getPackagesForUid(DpmMockContext.CALLER_UID)).thenReturn( @@ -5896,23 +6107,25 @@ public class DevicePolicyManagerTest extends DpmTestBase { .getUserPasswordMetrics(parentUser.id)) .thenReturn(computeForPassword("parentUser".getBytes())); - assertEquals(PASSWORD_COMPLEXITY_HIGH, dpm.getPasswordComplexity()); + assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_HIGH); } + @Test public void testCrossProfileCalendarPackages_initiallyEmpty() { setAsProfileOwner(admin1); final Set<String> packages = dpm.getCrossProfileCalendarPackages(admin1); assertCrossProfileCalendarPackagesEqual(packages, Collections.emptySet()); } + @Test public void testCrossProfileCalendarPackages_reopenDpms() { setAsProfileOwner(admin1); dpm.setCrossProfileCalendarPackages(admin1, null); Set<String> packages = dpm.getCrossProfileCalendarPackages(admin1); - assertTrue(packages == null); + assertThat(packages == null).isTrue(); initializeDpms(); packages = dpm.getCrossProfileCalendarPackages(admin1); - assertTrue(packages == null); + assertThat(packages == null).isTrue(); dpm.setCrossProfileCalendarPackages(admin1, Collections.emptySet()); packages = dpm.getCrossProfileCalendarPackages(admin1); @@ -5932,21 +6145,22 @@ public class DevicePolicyManagerTest extends DpmTestBase { } private void assertCrossProfileCalendarPackagesEqual(Set<String> expected, Set<String> actual) { - assertTrue(expected != null); - assertTrue(actual != null); - assertTrue(expected.containsAll(actual)); - assertTrue(actual.containsAll(expected)); + assertThat(expected).isNotNull(); + assertThat(actual).isNotNull(); + assertThat(actual).containsExactlyElementsIn(expected); } + @Test public void testIsPackageAllowedToAccessCalendar_adminNotAllowed() { setAsProfileOwner(admin1); dpm.setCrossProfileCalendarPackages(admin1, Collections.emptySet()); when(getServices().settings.settingsSecureGetIntForUser( Settings.Secure.CROSS_PROFILE_CALENDAR_ENABLED, 0, CALLER_USER_HANDLE)).thenReturn(1); - assertFalse(dpm.isPackageAllowedToAccessCalendar("TEST_PACKAGE")); + assertThat(dpm.isPackageAllowedToAccessCalendar("TEST_PACKAGE")).isFalse(); } + @Test public void testIsPackageAllowedToAccessCalendar_settingOff() { final String testPackage = "TEST_PACKAGE"; setAsProfileOwner(admin1); @@ -5954,9 +6168,10 @@ public class DevicePolicyManagerTest extends DpmTestBase { when(getServices().settings.settingsSecureGetIntForUser( Settings.Secure.CROSS_PROFILE_CALENDAR_ENABLED, 0, CALLER_USER_HANDLE)).thenReturn(0); - assertFalse(dpm.isPackageAllowedToAccessCalendar(testPackage)); + assertThat(dpm.isPackageAllowedToAccessCalendar(testPackage)).isFalse(); } + @Test public void testIsPackageAllowedToAccessCalendar_bothAllowed() { final String testPackage = "TEST_PACKAGE"; setAsProfileOwner(admin1); @@ -5964,9 +6179,10 @@ public class DevicePolicyManagerTest extends DpmTestBase { when(getServices().settings.settingsSecureGetIntForUser( Settings.Secure.CROSS_PROFILE_CALENDAR_ENABLED, 0, CALLER_USER_HANDLE)).thenReturn(1); - assertTrue(dpm.isPackageAllowedToAccessCalendar(testPackage)); + assertThat(dpm.isPackageAllowedToAccessCalendar(testPackage)).isTrue(); } + @Test public void testSetUserControlDisabledPackages_asDO() throws Exception { final List<String> testPackages = new ArrayList<>(); testPackages.add("package_1"); @@ -5979,9 +6195,10 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(getServices().packageManagerInternal).setDeviceOwnerProtectedPackages(testPackages); - assertEquals(testPackages, dpm.getUserControlDisabledPackages(admin1)); + assertThat(dpm.getUserControlDisabledPackages(admin1)).isEqualTo(testPackages); } + @Test public void testSetUserControlDisabledPackages_failingAsPO() throws Exception { final List<String> testPackages = new ArrayList<>(); testPackages.add("package_1"); @@ -6008,28 +6225,32 @@ public class DevicePolicyManagerTest extends DpmTestBase { mServiceContext.binder.restoreCallingIdentity(ident); } + @Test public void testGetCrossProfilePackages_notSet_returnsEmpty() { setAsProfileOwner(admin1); - assertTrue(dpm.getCrossProfilePackages(admin1).isEmpty()); + assertThat(dpm.getCrossProfilePackages(admin1).isEmpty()).isTrue(); } + @Test public void testGetCrossProfilePackages_notSet_dpmsReinitialized_returnsEmpty() { setAsProfileOwner(admin1); initializeDpms(); - assertTrue(dpm.getCrossProfilePackages(admin1).isEmpty()); + assertThat(dpm.getCrossProfilePackages(admin1).isEmpty()).isTrue(); } + @Test public void testGetCrossProfilePackages_whenSet_returnsEqual() { setAsProfileOwner(admin1); Set<String> packages = Collections.singleton("TEST_PACKAGE"); dpm.setCrossProfilePackages(admin1, packages); - assertEquals(packages, dpm.getCrossProfilePackages(admin1)); + assertThat(dpm.getCrossProfilePackages(admin1)).isEqualTo(packages); } + @Test public void testGetCrossProfilePackages_whenSet_dpmsReinitialized_returnsEqual() { setAsProfileOwner(admin1); Set<String> packages = Collections.singleton("TEST_PACKAGE"); @@ -6037,9 +6258,10 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm.setCrossProfilePackages(admin1, packages); initializeDpms(); - assertEquals(packages, dpm.getCrossProfilePackages(admin1)); + assertThat(dpm.getCrossProfilePackages(admin1)).isEqualTo(packages); } + @Test public void testGetAllCrossProfilePackages_notSet_returnsEmpty() throws Exception { addManagedProfile(admin1, mServiceContext.binder.callingUid, admin1); mContext.packageName = admin1.getPackageName(); @@ -6047,9 +6269,10 @@ public class DevicePolicyManagerTest extends DpmTestBase { setCrossProfileAppsList(); setVendorCrossProfileAppsList(); - assertTrue(dpm.getAllCrossProfilePackages().isEmpty()); + assertThat(dpm.getAllCrossProfilePackages().isEmpty()).isTrue(); } + @Test public void testGetAllCrossProfilePackages_notSet_dpmsReinitialized_returnsEmpty() throws Exception { addManagedProfile(admin1, mServiceContext.binder.callingUid, admin1); @@ -6059,9 +6282,10 @@ public class DevicePolicyManagerTest extends DpmTestBase { setVendorCrossProfileAppsList(); initializeDpms(); - assertTrue(dpm.getAllCrossProfilePackages().isEmpty()); + assertThat(dpm.getAllCrossProfilePackages().isEmpty()).isTrue(); } + @Test public void testGetAllCrossProfilePackages_whenSet_returnsCombinedSet() throws Exception { addManagedProfile(admin1, mServiceContext.binder.callingUid, admin1); final Set<String> packages = Sets.newSet("TEST_PACKAGE", "TEST_COMMON_PACKAGE"); @@ -6071,13 +6295,12 @@ public class DevicePolicyManagerTest extends DpmTestBase { setCrossProfileAppsList("TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE"); setVendorCrossProfileAppsList("TEST_VENDOR_DEFAULT_PACKAGE"); - assertEquals(Sets.newSet( - "TEST_PACKAGE", "TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE", - "TEST_VENDOR_DEFAULT_PACKAGE"), - dpm.getAllCrossProfilePackages()); - + assertThat(dpm.getAllCrossProfilePackages()).containsExactly( + "TEST_PACKAGE", "TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE", + "TEST_VENDOR_DEFAULT_PACKAGE"); } + @Test public void testGetAllCrossProfilePackages_whenSet_dpmsReinitialized_returnsCombinedSet() throws Exception { addManagedProfile(admin1, mServiceContext.binder.callingUid, admin1); @@ -6089,12 +6312,12 @@ public class DevicePolicyManagerTest extends DpmTestBase { setVendorCrossProfileAppsList("TEST_VENDOR_DEFAULT_PACKAGE"); initializeDpms(); - assertEquals(Sets.newSet( + assertThat(dpm.getAllCrossProfilePackages()).containsExactly( "TEST_PACKAGE", "TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE", - "TEST_VENDOR_DEFAULT_PACKAGE"), - dpm.getAllCrossProfilePackages()); + "TEST_VENDOR_DEFAULT_PACKAGE"); } + @Test public void testGetDefaultCrossProfilePackages_noPackagesSet_returnsEmpty() { setCrossProfileAppsList(); setVendorCrossProfileAppsList(); @@ -6102,27 +6325,29 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertThat(dpm.getDefaultCrossProfilePackages()).isEmpty(); } + @Test public void testGetDefaultCrossProfilePackages_packagesSet_returnsCombinedSet() { setCrossProfileAppsList("TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE"); setVendorCrossProfileAppsList("TEST_VENDOR_DEFAULT_PACKAGE"); - assertThat(dpm.getDefaultCrossProfilePackages()).isEqualTo(Sets.newSet( - "TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE", "TEST_VENDOR_DEFAULT_PACKAGE" - )); + assertThat(dpm.getDefaultCrossProfilePackages()).containsExactly( + "TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE", "TEST_VENDOR_DEFAULT_PACKAGE"); } + @Test public void testSetCommonCriteriaMode_asDeviceOwner() throws Exception { setDeviceOwner(); - assertFalse(dpm.isCommonCriteriaModeEnabled(admin1)); - assertFalse(dpm.isCommonCriteriaModeEnabled(null)); + assertThat(dpm.isCommonCriteriaModeEnabled(admin1)).isFalse(); + assertThat(dpm.isCommonCriteriaModeEnabled(null)).isFalse(); dpm.setCommonCriteriaModeEnabled(admin1, true); - assertTrue(dpm.isCommonCriteriaModeEnabled(admin1)); - assertTrue(dpm.isCommonCriteriaModeEnabled(null)); + assertThat(dpm.isCommonCriteriaModeEnabled(admin1)).isTrue(); + assertThat(dpm.isCommonCriteriaModeEnabled(null)).isTrue(); } + @Test public void testSetCommonCriteriaMode_asPoOfOrgOwnedDevice() throws Exception { final int managedProfileUserId = 15; final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436); @@ -6130,15 +6355,16 @@ public class DevicePolicyManagerTest extends DpmTestBase { configureProfileOwnerOfOrgOwnedDevice(admin1, managedProfileUserId); mContext.binder.callingUid = managedProfileAdminUid; - assertFalse(dpm.isCommonCriteriaModeEnabled(admin1)); - assertFalse(dpm.isCommonCriteriaModeEnabled(null)); + assertThat(dpm.isCommonCriteriaModeEnabled(admin1)).isFalse(); + assertThat(dpm.isCommonCriteriaModeEnabled(null)).isFalse(); dpm.setCommonCriteriaModeEnabled(admin1, true); - assertTrue(dpm.isCommonCriteriaModeEnabled(admin1)); - assertTrue(dpm.isCommonCriteriaModeEnabled(null)); + assertThat(dpm.isCommonCriteriaModeEnabled(admin1)).isTrue(); + assertThat(dpm.isCommonCriteriaModeEnabled(null)).isTrue(); } + @Test public void testCanProfileOwnerResetPasswordWhenLocked_nonDirectBootAwarePo() throws Exception { setDeviceEncryptionPerUser(); @@ -6146,30 +6372,33 @@ public class DevicePolicyManagerTest extends DpmTestBase { setupPasswordResetToken(); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; - assertFalse("po is not direct boot aware", - dpm.canProfileOwnerResetPasswordWhenLocked(CALLER_USER_HANDLE)); + assertWithMessage("po is not direct boot aware") + .that(dpm.canProfileOwnerResetPasswordWhenLocked(CALLER_USER_HANDLE)).isFalse(); } + @Test public void testCanProfileOwnerResetPasswordWhenLocked_noActiveToken() throws Exception { setDeviceEncryptionPerUser(); setupProfileOwner(); makeAdmin1DirectBootAware(); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; - assertFalse("po doesn't have an active password reset token", - dpm.canProfileOwnerResetPasswordWhenLocked(CALLER_USER_HANDLE)); + assertWithMessage("po doesn't have an active password reset token") + .that(dpm.canProfileOwnerResetPasswordWhenLocked(CALLER_USER_HANDLE)).isFalse(); } + @Test public void testCanProfileOwnerResetPasswordWhenLocked_nonFbeDevice() throws Exception { setupProfileOwner(); makeAdmin1DirectBootAware(); setupPasswordResetToken(); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; - assertFalse("device is not FBE", - dpm.canProfileOwnerResetPasswordWhenLocked(CALLER_USER_HANDLE)); + assertWithMessage("device is not FBE") + .that(dpm.canProfileOwnerResetPasswordWhenLocked(CALLER_USER_HANDLE)).isFalse(); } + @Test public void testCanProfileOwnerResetPasswordWhenLocked() throws Exception { setDeviceEncryptionPerUser(); setupProfileOwner(); @@ -6177,8 +6406,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { setupPasswordResetToken(); mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; - assertTrue("direct boot aware po with active password reset token", - dpm.canProfileOwnerResetPasswordWhenLocked(CALLER_USER_HANDLE)); + assertWithMessage("direct boot aware po with active password reset token") + .that(dpm.canProfileOwnerResetPasswordWhenLocked(CALLER_USER_HANDLE)).isTrue(); } private void setupPasswordResetToken() { @@ -6196,7 +6425,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { .isEscrowTokenActive(eq(handle), eq(CALLER_USER_HANDLE))) .thenReturn(true); - assertTrue("failed to activate token", dpm.isResetPasswordTokenActive(admin1)); + assertWithMessage("failed to activate token").that(dpm.isResetPasswordTokenActive(admin1)) + .isTrue(); } private void makeAdmin1DirectBootAware() @@ -6231,6 +6461,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { .thenReturn(packages); } + @Test public void testSetAccountTypesWithManagementDisabledOnManagedProfile() throws Exception { setupProfileOwner(); @@ -6249,6 +6480,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertThat(dpm.getAccountTypesWithManagementDisabled()).isEmpty(); } + @Test public void testSetAccountTypesWithManagementDisabledOnOrgOwnedManagedProfile() throws Exception { final int managedProfileUserId = 15; @@ -6284,6 +6516,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { * Tests the case when the user doesn't turn the profile on in time, verifies that the user is * warned with a notification and then the apps get suspended. */ + @Test public void testMaximumProfileTimeOff_profileOffTimeExceeded() throws Exception { prepareMocksForSetMaximumProfileTimeOff(); @@ -6346,6 +6579,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { /** * Tests the case when the user turns the profile back on long before the deadline (> 1 day). */ + @Test public void testMaximumProfileTimeOff_turnOnBeforeWarning() throws Exception { prepareMocksForSetMaximumProfileTimeOff(); @@ -6366,6 +6600,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { /** * Tests the case when the user turns the profile back on after the warning notification. */ + @Test public void testMaximumProfileTimeOff_turnOnAfterWarning() throws Exception { prepareMocksForSetMaximumProfileTimeOff(); @@ -6395,6 +6630,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { /** * Tests the case when the user turns the profile back on when the apps are already suspended. */ + @Test public void testMaximumProfileTimeOff_turnOnAfterDeadline() throws Exception { prepareMocksForSetMaximumProfileTimeOff(); @@ -6482,7 +6718,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { } private static Matcher<Notification> hasExtra(String... extras) { - assertEquals("Odd number of extra key-values", 0, extras.length % 2); + assertWithMessage("Odd number of extra key-values").that(extras.length % 2).isEqualTo(0); return new BaseMatcher<Notification>() { @Override public boolean matches(Object item) { @@ -6520,17 +6756,17 @@ public class DevicePolicyManagerTest extends DpmTestBase { // To simulate a reboot, we just reinitialize dpms and call systemReady initializeDpms(); - assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName())); - assertFalse(dpm.isDeviceOwnerApp(adminAnotherPackage.getPackageName())); - assertFalse(dpm.isAdminActive(adminAnotherPackage)); - assertTrue(dpm.isAdminActive(admin1)); - assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())); - assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser()); + assertThat(dpm.isDeviceOwnerApp(admin1.getPackageName())).isTrue(); + assertThat(dpm.isDeviceOwnerApp(adminAnotherPackage.getPackageName())).isFalse(); + assertThat(dpm.isAdminActive(adminAnotherPackage)).isFalse(); + assertThat(dpm.isAdminActive(admin1)).isTrue(); + assertThat(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName())).isTrue(); + assertThat(dpm.getDeviceOwnerComponentOnCallingUser()).isEqualTo(admin1); - assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())); - assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser()); - assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId()); - assertFalse(getMockTransferMetadataManager().metadataFileExists()); + assertThat(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName())).isTrue(); + assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(admin1); + assertThat(dpm.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_SYSTEM); + assertThat(getMockTransferMetadataManager().metadataFileExists()).isFalse(); mServiceContext.binder.restoreCallingIdentity(ident); } @@ -6547,12 +6783,12 @@ public class DevicePolicyManagerTest extends DpmTestBase { // To simulate a reboot, we just reinitialize dpms and call systemReady initializeDpms(); - assertTrue(dpm.isProfileOwnerApp(admin1.getPackageName())); - assertTrue(dpm.isAdminActive(admin1)); - assertFalse(dpm.isProfileOwnerApp(adminAnotherPackage.getPackageName())); - assertFalse(dpm.isAdminActive(adminAnotherPackage)); - assertEquals(dpm.getProfileOwnerAsUser(CALLER_USER_HANDLE), admin1); - assertFalse(getMockTransferMetadataManager().metadataFileExists()); + assertThat(dpm.isProfileOwnerApp(admin1.getPackageName())).isTrue(); + assertThat(dpm.isAdminActive(admin1)).isTrue(); + assertThat(dpm.isProfileOwnerApp(adminAnotherPackage.getPackageName())).isFalse(); + assertThat(dpm.isAdminActive(adminAnotherPackage)).isFalse(); + assertThat(admin1).isEqualTo(dpm.getProfileOwnerAsUser(CALLER_USER_HANDLE)); + assertThat(getMockTransferMetadataManager().metadataFileExists()).isFalse(); } private void writeFakeTransferMetadataFile(int callerUserHandle, String adminType) { @@ -6597,8 +6833,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { } private void assertProvisioningAllowed(String action, boolean expected) { - assertEquals("isProvisioningAllowed(" + action + ") returning unexpected result", expected, - dpm.isProvisioningAllowed(action)); + assertWithMessage("isProvisioningAllowed(%s) returning unexpected result", action) + .that(dpm.isProvisioningAllowed(action)).isEqualTo(expected); } private void assertProvisioningAllowed(String action, boolean expected, String packageName, @@ -6622,9 +6858,9 @@ public class DevicePolicyManagerTest extends DpmTestBase { private void assertCheckProvisioningPreCondition( String action, String packageName, int provisioningCondition) { - assertEquals("checkProvisioningPreCondition(" - + action + ", " + packageName + ") returning unexpected result", - provisioningCondition, dpm.checkProvisioningPreCondition(action, packageName)); + assertWithMessage("checkProvisioningPreCondition(%s, %s) returning unexpected result", + action, packageName).that(dpm.checkProvisioningPreCondition(action, packageName)) + .isEqualTo(provisioningCondition); } /** @@ -6642,7 +6878,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.callerPermissions.addAll(OWNER_SETUP_PERMISSIONS); setUpPackageManagerForFakeAdmin(admin, adminUid, copyFromAdmin); dpm.setActiveAdmin(admin, false, userId); - assertTrue(dpm.setProfileOwner(admin, null, userId)); + assertThat(dpm.setProfileOwner(admin, null, userId)).isTrue(); mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS); } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java index 41d54e9010d3..81570a10fc13 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java @@ -16,6 +16,8 @@ package com.android.server.devicepolicy; +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; @@ -35,18 +37,28 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.UserHandle; -import android.test.AndroidTestCase; + +import androidx.test.InstrumentationRegistry; + +import org.junit.Before; import java.io.InputStream; import java.util.List; -public abstract class DpmTestBase extends AndroidTestCase { +/** + * Temporary copy of DpmTestBase using JUnit 4 - once all tests extend it, it should be renamed + * back to DpmTestBase (with the temporary methods removed. + * + */ +public abstract class DpmTestBase { + public static final String TAG = "DpmTest"; - protected Context mRealTestContext; + protected final Context mRealTestContext = InstrumentationRegistry.getTargetContext(); protected DpmMockContext mMockContext; private MockSystemServices mServices; + // Attributes below are public so they don't need to be prefixed with m public ComponentName admin1; public ComponentName admin2; public ComponentName admin3; @@ -54,12 +66,8 @@ public abstract class DpmTestBase extends AndroidTestCase { public ComponentName adminNoPerm; public ComponentName delegateCertInstaller; - @Override - protected void setUp() throws Exception { - super.setUp(); - - mRealTestContext = super.getContext(); - + @Before + public void setFixtures() throws Exception { mServices = new MockSystemServices(mRealTestContext, "test-data"); mMockContext = new DpmMockContext(mServices, mRealTestContext); @@ -74,8 +82,7 @@ public abstract class DpmTestBase extends AndroidTestCase { mockSystemPropertiesToReturnDefault(); } - @Override - public DpmMockContext getContext() { + protected DpmMockContext getContext() { return mMockContext; } @@ -136,20 +143,15 @@ public abstract class DpmTestBase extends AndroidTestCase { final PackageInfo pi = DpmTestUtils.cloneParcelable( mRealTestContext.getPackageManager().getPackageInfo( mRealTestContext.getPackageName(), 0)); - assertTrue(pi.applicationInfo.flags != 0); + assertThat(pi.applicationInfo.flags).isNotEqualTo(0); if (ai != null) { pi.applicationInfo = ai; } - doReturn(pi).when(mServices.ipackageManager).getPackageInfo( - eq(packageName), - eq(0), - eq(userId)); + doReturn(pi).when(mServices.ipackageManager).getPackageInfo(packageName, 0, userId); - doReturn(ai.uid).when(mServices.packageManager).getPackageUidAsUser( - eq(packageName), - eq(userId)); + doReturn(ai.uid).when(mServices.packageManager).getPackageUidAsUser(packageName, userId); } protected void markDelegatedCertInstallerAsInstalled() throws Exception { @@ -230,8 +232,8 @@ public abstract class DpmTestBase extends AndroidTestCase { mRealTestContext.getPackageManager().queryBroadcastReceivers( resolveIntent, PackageManager.GET_META_DATA); - assertNotNull(realResolveInfo); - assertEquals(1, realResolveInfo.size()); + assertThat(realResolveInfo).isNotNull(); + assertThat(realResolveInfo).hasSize(1); // We need to change AI, so set a clone. realResolveInfo.set(0, DpmTestUtils.cloneParcelable(realResolveInfo.get(0))); diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/FactoryResetProtectionPolicyTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/FactoryResetProtectionPolicyTest.java index e8818a3f4940..3aa5a80d814f 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/FactoryResetProtectionPolicyTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/FactoryResetProtectionPolicyTest.java @@ -16,8 +16,8 @@ package com.android.server.devicepolicy; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -100,7 +100,7 @@ public class FactoryResetProtectionPolicyTest { ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray()); XmlPullParser parser = Xml.newPullParser(); parser.setInput(new InputStreamReader(inStream)); - assertEquals(XmlPullParser.START_TAG, parser.next()); + assertThat(parser.next()).isEqualTo(XmlPullParser.START_TAG); assertPoliciesAreEqual(policy, policy.readFromXml(parser)); } @@ -114,7 +114,7 @@ public class FactoryResetProtectionPolicyTest { parser.setInput(new InputStreamReader(inStream)); // If deserialization fails, then null is returned. - assertNull(policy.readFromXml(parser)); + assertThat(policy.readFromXml(parser)).isNull(); } private ByteArrayOutputStream serialize(FactoryResetProtectionPolicy policy) @@ -133,17 +133,17 @@ public class FactoryResetProtectionPolicyTest { private void assertPoliciesAreEqual(FactoryResetProtectionPolicy expectedPolicy, FactoryResetProtectionPolicy actualPolicy) { - assertEquals(expectedPolicy.isFactoryResetProtectionEnabled(), - actualPolicy.isFactoryResetProtectionEnabled()); + assertThat(actualPolicy.isFactoryResetProtectionEnabled()) + .isEqualTo(expectedPolicy.isFactoryResetProtectionEnabled()); assertAccountsAreEqual(expectedPolicy.getFactoryResetProtectionAccounts(), actualPolicy.getFactoryResetProtectionAccounts()); } private void assertAccountsAreEqual(List<String> expectedAccounts, List<String> actualAccounts) { - assertEquals(expectedAccounts.size(), actualAccounts.size()); + assertThat(actualAccounts.size()).isEqualTo(expectedAccounts.size()); for (int i = 0; i < expectedAccounts.size(); i++) { - assertEquals(expectedAccounts.get(i), actualAccounts.get(i)); + assertThat(actualAccounts.get(i)).isEqualTo(expectedAccounts.get(i)); } } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java index c698312eedec..7506dd45ad82 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java @@ -17,6 +17,9 @@ package com.android.server.devicepolicy; import static com.android.server.devicepolicy.NetworkLoggingHandler.LOG_NETWORK_EVENT_MSG; +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.spy; @@ -37,8 +40,9 @@ import android.os.test.TestLooper; import android.test.suitebuilder.annotation.SmallTest; import com.android.server.LocalServices; -import com.android.server.SystemService; +import org.junit.Before; +import org.junit.Test; import org.mockito.ArgumentCaptor; import java.util.List; @@ -50,9 +54,8 @@ public class NetworkEventTest extends DpmTestBase { private DpmMockContext mSpiedDpmMockContext; private DevicePolicyManagerServiceTestable mDpmTestable; - @Override - protected void setUp() throws Exception { - super.setUp(); + @Before + public void setUp() throws Exception { mSpiedDpmMockContext = spy(mMockContext); mSpiedDpmMockContext.callerPermissions.add( android.Manifest.permission.MANAGE_DEVICE_ADMINS); @@ -64,6 +67,7 @@ public class NetworkEventTest extends DpmTestBase { mDpmTestable.setActiveAdmin(admin1, true, DpmMockContext.CALLER_USER_HANDLE); } + @Test public void testNetworkEventId_monotonicallyIncreasing() throws Exception { // GIVEN the handler has not processed any events. long startingId = 0; @@ -72,17 +76,20 @@ public class NetworkEventTest extends DpmTestBase { List<NetworkEvent> events = fillHandlerWithFullBatchOfEvents(startingId); // THEN the events are in a batch. - assertTrue("Batch not at the returned token.", - events != null && events.size() == MAX_EVENTS_PER_BATCH); + assertWithMessage("Batch not at the returned token.").that(events).isNotNull(); + assertWithMessage("Batch not at the returned token.").that(events) + .hasSize(MAX_EVENTS_PER_BATCH); + // THEN event ids are monotonically increasing. long expectedId = startingId; for (int i = 0; i < MAX_EVENTS_PER_BATCH; i++) { - assertEquals("At index " + i + ", the event has the wrong id.", expectedId, - events.get(i).getId()); + assertWithMessage("At index %s, the event has the wrong id.", i) + .that(events.get(i).getId()).isEqualTo(expectedId); expectedId++; } } + @Test public void testNetworkEventId_wrapsAround() throws Exception { // GIVEN the handler has almost processed Long.MAX_VALUE events. int gap = 5; @@ -92,24 +99,25 @@ public class NetworkEventTest extends DpmTestBase { List<NetworkEvent> events = fillHandlerWithFullBatchOfEvents(startingId); // THEN the events are in a batch. - assertTrue("Batch not at the returned token.", - events != null && events.size() == MAX_EVENTS_PER_BATCH); + assertWithMessage("Batch not at the returned token.").that(events).isNotNull(); + assertWithMessage("Batch not at the returned token.").that(events) + .hasSize(MAX_EVENTS_PER_BATCH); // THEN event ids are monotonically increasing. long expectedId = startingId; for (int i = 0; i < gap; i++) { - assertEquals("At index " + i + ", the event has the wrong id.", expectedId, - events.get(i).getId()); + assertWithMessage("At index %s, the event has the wrong id.", i) + .that(events.get(i).getId()).isEqualTo(expectedId); expectedId++; } // THEN event ids are reset when the id reaches the maximum possible value. - assertEquals("Event was not assigned the maximum id value.", Long.MAX_VALUE, - events.get(gap).getId()); - assertEquals("Event id was not reset.", 0, events.get(gap + 1).getId()); + assertWithMessage("Event was not assigned the maximum id value.") + .that(events.get(gap).getId()).isEqualTo(Long.MAX_VALUE); + assertWithMessage("Event id was not reset.").that(events.get(gap + 1).getId()).isEqualTo(0); // THEN event ids are monotonically increasing. expectedId = 0; for (int i = gap + 1; i < MAX_EVENTS_PER_BATCH; i++) { - assertEquals("At index " + i + ", the event has the wrong id.", expectedId, - events.get(i).getId()); + assertWithMessage("At index %s, the event has the wrong id.", i) + .that(events.get(i).getId()).isEqualTo(expectedId); expectedId++; } } @@ -134,8 +142,8 @@ public class NetworkEventTest extends DpmTestBase { ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); verify(mSpiedDpmMockContext).sendBroadcastAsUser(intentCaptor.capture(), any(UserHandle.class)); - assertEquals(intentCaptor.getValue().getAction(), - DeviceAdminReceiver.ACTION_NETWORK_LOGS_AVAILABLE); + assertThat(DeviceAdminReceiver.ACTION_NETWORK_LOGS_AVAILABLE) + .isEqualTo(intentCaptor.getValue().getAction()); long token = intentCaptor.getValue().getExtras().getLong( DeviceAdminReceiver.EXTRA_NETWORK_LOGS_TOKEN, 0); return handler.retrieveFullLogBatch(token); @@ -144,6 +152,7 @@ public class NetworkEventTest extends DpmTestBase { /** * Test parceling and unparceling of a ConnectEvent. */ + @Test public void testConnectEventParceling() { ConnectEvent event = new ConnectEvent("127.0.0.1", 80, "com.android.whateverdude", 100000); event.setId(5L); @@ -152,16 +161,17 @@ public class NetworkEventTest extends DpmTestBase { p.setDataPosition(0); ConnectEvent unparceledEvent = p.readParcelable(NetworkEventTest.class.getClassLoader()); p.recycle(); - assertEquals(event.getInetAddress(), unparceledEvent.getInetAddress()); - assertEquals(event.getPort(), unparceledEvent.getPort()); - assertEquals(event.getPackageName(), unparceledEvent.getPackageName()); - assertEquals(event.getTimestamp(), unparceledEvent.getTimestamp()); - assertEquals(event.getId(), unparceledEvent.getId()); + assertThat(unparceledEvent.getInetAddress()).isEqualTo(event.getInetAddress()); + assertThat(unparceledEvent.getPort()).isEqualTo(event.getPort()); + assertThat(unparceledEvent.getPackageName()).isEqualTo(event.getPackageName()); + assertThat(unparceledEvent.getTimestamp()).isEqualTo(event.getTimestamp()); + assertThat(unparceledEvent.getId()).isEqualTo(event.getId()); } /** * Test parceling and unparceling of a DnsEvent. */ + @Test public void testDnsEventParceling() { DnsEvent event = new DnsEvent("d.android.com", new String[]{"192.168.0.1", "127.0.0.1"}, 2, "com.android.whateverdude", 100000); @@ -171,13 +181,15 @@ public class NetworkEventTest extends DpmTestBase { p.setDataPosition(0); DnsEvent unparceledEvent = p.readParcelable(NetworkEventTest.class.getClassLoader()); p.recycle(); - assertEquals(event.getHostname(), unparceledEvent.getHostname()); - assertEquals(event.getInetAddresses().get(0), unparceledEvent.getInetAddresses().get(0)); - assertEquals(event.getInetAddresses().get(1), unparceledEvent.getInetAddresses().get(1)); - assertEquals(event.getTotalResolvedAddressCount(), - unparceledEvent.getTotalResolvedAddressCount()); - assertEquals(event.getPackageName(), unparceledEvent.getPackageName()); - assertEquals(event.getTimestamp(), unparceledEvent.getTimestamp()); - assertEquals(event.getId(), unparceledEvent.getId()); + assertThat(unparceledEvent.getHostname()).isEqualTo(event.getHostname()); + assertThat(unparceledEvent.getInetAddresses().get(0)) + .isEqualTo(event.getInetAddresses().get(0)); + assertThat(unparceledEvent.getInetAddresses().get(1)) + .isEqualTo(event.getInetAddresses().get(1)); + assertThat(unparceledEvent.getTotalResolvedAddressCount()) + .isEqualTo(event.getTotalResolvedAddressCount()); + assertThat(unparceledEvent.getPackageName()).isEqualTo(event.getPackageName()); + assertThat(unparceledEvent.getTimestamp()).isEqualTo(event.getTimestamp()); + assertThat(unparceledEvent.getId()).isEqualTo(event.getId()); } } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/OverlayPackagesProviderTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/OverlayPackagesProviderTest.java index a3cc915b3eba..24e226a64917 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/OverlayPackagesProviderTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/OverlayPackagesProviderTest.java @@ -20,6 +20,9 @@ import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEV import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE; import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER; +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + import static org.mockito.Matchers.eq; import static org.mockito.Mockito.when; @@ -32,16 +35,17 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.res.Resources; -import android.test.AndroidTestCase; import android.test.mock.MockPackageManager; import android.view.inputmethod.InputMethodInfo; import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; import com.android.internal.R; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -51,18 +55,23 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -public class OverlayPackagesProviderTest extends AndroidTestCase { +/** + * Run this test with: + * + * {@code atest FrameworksServicesTests:com.android.server.devicepolicy.OwnersTest} + * + */ +@RunWith(AndroidJUnit4.class) +public class OverlayPackagesProviderTest { private static final String TEST_DPC_PACKAGE_NAME = "dpc.package.name"; private static final ComponentName TEST_MDM_COMPONENT_NAME = new ComponentName( TEST_DPC_PACKAGE_NAME, "pc.package.name.DeviceAdmin"); private static final int TEST_USER_ID = 123; - private @Mock - Resources mResources; - @Mock - private OverlayPackagesProvider.Injector mInjector; - private @Mock - Context mTestContext; + private @Mock Resources mResources; + + private @Mock OverlayPackagesProvider.Injector mInjector; + private @Mock Context mTestContext; private Resources mRealResources; private FakePackageManager mPackageManager; @@ -256,12 +265,12 @@ public class OverlayPackagesProviderTest extends AndroidTestCase { ArrayList<String> required = getStringArrayInRealResources(requiredId); ArrayList<String> disallowed = getStringArrayInRealResources(disallowedId); required.retainAll(disallowed); - assertTrue(required.isEmpty()); + assertThat(required.isEmpty()).isTrue(); } private void verifyAppsAreNonRequired(String action, String... appArray) { - assertEquals(setFromArray(appArray), - mHelper.getNonRequiredApps(TEST_MDM_COMPONENT_NAME, TEST_USER_ID, action)); + assertThat(mHelper.getNonRequiredApps(TEST_MDM_COMPONENT_NAME, TEST_USER_ID, action)) + .containsExactlyElementsIn(setFromArray(appArray)); } private void setRequiredAppsManagedDevice(String... apps) { @@ -348,19 +357,19 @@ public class OverlayPackagesProviderTest extends AndroidTestCase { class FakePackageManager extends MockPackageManager { @Override public List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent, int flags, int userId) { - assertTrue("Expected an intent with action ACTION_MAIN", - Intent.ACTION_MAIN.equals(intent.getAction())); - assertEquals("Expected an intent with category CATEGORY_LAUNCHER", - setFromArray(Intent.CATEGORY_LAUNCHER), intent.getCategories()); - assertTrue("Expected the flag MATCH_UNINSTALLED_PACKAGES", - (flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0); - assertTrue("Expected the flag MATCH_DISABLED_COMPONENTS", - (flags & PackageManager.MATCH_DISABLED_COMPONENTS) != 0); - assertTrue("Expected the flag MATCH_DIRECT_BOOT_AWARE", - (flags & PackageManager.MATCH_DIRECT_BOOT_AWARE) != 0); - assertTrue("Expected the flag MATCH_DIRECT_BOOT_UNAWARE", - (flags & PackageManager.MATCH_DIRECT_BOOT_UNAWARE) != 0); - assertEquals(userId, TEST_USER_ID); + assertWithMessage("Expected an intent with action ACTION_MAIN") + .that(Intent.ACTION_MAIN.equals(intent.getAction())).isTrue(); + assertWithMessage("Expected an intent with category CATEGORY_LAUNCHER") + .that(intent.getCategories()).containsExactly(Intent.CATEGORY_LAUNCHER); + assertWithMessage("Expected the flag MATCH_UNINSTALLED_PACKAGES") + .that((flags & PackageManager.MATCH_UNINSTALLED_PACKAGES)).isNotEqualTo(0); + assertWithMessage("Expected the flag MATCH_DISABLED_COMPONENTS") + .that((flags & PackageManager.MATCH_DISABLED_COMPONENTS)).isNotEqualTo(0); + assertWithMessage("Expected the flag MATCH_DIRECT_BOOT_AWARE") + .that((flags & PackageManager.MATCH_DIRECT_BOOT_AWARE)).isNotEqualTo(0); + assertWithMessage("Expected the flag MATCH_DIRECT_BOOT_UNAWARE") + .that((flags & PackageManager.MATCH_DIRECT_BOOT_UNAWARE)).isNotEqualTo(0); + assertThat(TEST_USER_ID).isEqualTo(userId); List<ResolveInfo> result = new ArrayList<>(); if (mSystemAppsWithLauncher == null) { return result; diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java index 5899bb0e94fe..bfe183cc608b 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java @@ -16,25 +16,32 @@ package com.android.server.devicepolicy; +import static com.google.common.truth.Truth.assertThat; + import android.content.ComponentName; import android.os.UserHandle; import android.test.suitebuilder.annotation.SmallTest; +import androidx.test.runner.AndroidJUnit4; + import com.android.server.devicepolicy.DevicePolicyManagerServiceTestable.OwnersTestable; +import org.junit.Test; +import org.junit.runner.RunWith; + /** * Tests for the DeviceOwner object that saves & loads device and policy owner information. - * run this test with: - m FrameworksServicesTests && - adb install \ - -r out/target/product/hammerhead/data/app/FrameworksServicesTests/FrameworksServicesTests.apk && - adb shell am instrument -e class com.android.server.devicepolicy.OwnersTest \ - -w com.android.frameworks.servicestests/androidx.test.runner.AndroidJUnitRunner - - (mmma frameworks/base/services/tests/servicestests/ for non-ninja build) + * + * <p>Run this test with: + * + * {@code atest FrameworksServicesTests:com.android.server.devicepolicy.OwnersTest} + * */ @SmallTest +@RunWith(AndroidJUnit4.class) public class OwnersTest extends DpmTestBase { + + @Test public void testUpgrade01() throws Exception { getServices().addUsers(10, 11, 20, 21); @@ -48,26 +55,26 @@ public class OwnersTest extends DpmTestBase { owners.load(); // The legacy file should be removed. - assertFalse(owners.getLegacyConfigFile().exists()); + assertThat(owners.getLegacyConfigFile().exists()).isFalse(); // File was empty, so no new files should be created. - assertFalse(owners.getDeviceOwnerFile().exists()); - - assertFalse(owners.getProfileOwnerFile(10).exists()); - assertFalse(owners.getProfileOwnerFile(11).exists()); - assertFalse(owners.getProfileOwnerFile(20).exists()); - assertFalse(owners.getProfileOwnerFile(21).exists()); - - assertFalse(owners.hasDeviceOwner()); - assertEquals(UserHandle.USER_NULL, owners.getDeviceOwnerUserId()); - assertNull(owners.getSystemUpdatePolicy()); - assertEquals(0, owners.getProfileOwnerKeys().size()); - - assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); + assertThat(owners.getDeviceOwnerFile().exists()).isFalse(); + + assertThat(owners.getProfileOwnerFile(10).exists()).isFalse(); + assertThat(owners.getProfileOwnerFile(11).exists()).isFalse(); + assertThat(owners.getProfileOwnerFile(20).exists()).isFalse(); + assertThat(owners.getProfileOwnerFile(21).exists()).isFalse(); + + assertThat(owners.hasDeviceOwner()).isFalse(); + assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL); + assertThat(owners.getSystemUpdatePolicy()).isNull(); + assertThat(owners.getProfileOwnerKeys()).isEmpty(); + + assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse(); } // Then re-read and check. @@ -75,19 +82,20 @@ public class OwnersTest extends DpmTestBase { final OwnersTestable owners = new OwnersTestable(getServices()); owners.load(); - assertFalse(owners.hasDeviceOwner()); - assertEquals(UserHandle.USER_NULL, owners.getDeviceOwnerUserId()); - assertNull(owners.getSystemUpdatePolicy()); - assertEquals(0, owners.getProfileOwnerKeys().size()); + assertThat(owners.hasDeviceOwner()).isFalse(); + assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL); + assertThat(owners.getSystemUpdatePolicy()).isNull(); + assertThat(owners.getProfileOwnerKeys()).isEmpty(); - assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); + assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse(); } } + @Test public void testUpgrade02() throws Exception { getServices().addUsers(10, 11, 20, 21); @@ -101,28 +109,28 @@ public class OwnersTest extends DpmTestBase { owners.load(); // The legacy file should be removed. - assertFalse(owners.getLegacyConfigFile().exists()); + assertThat(owners.getLegacyConfigFile().exists()).isFalse(); - assertTrue(owners.getDeviceOwnerFile().exists()); // TODO Check content + assertThat(owners.getDeviceOwnerFile().exists()).isTrue(); // TODO Check content - assertFalse(owners.getProfileOwnerFile(10).exists()); - assertFalse(owners.getProfileOwnerFile(11).exists()); - assertFalse(owners.getProfileOwnerFile(20).exists()); - assertFalse(owners.getProfileOwnerFile(21).exists()); + assertThat(owners.getProfileOwnerFile(10).exists()).isFalse(); + assertThat(owners.getProfileOwnerFile(11).exists()).isFalse(); + assertThat(owners.getProfileOwnerFile(20).exists()).isFalse(); + assertThat(owners.getProfileOwnerFile(21).exists()).isFalse(); - assertTrue(owners.hasDeviceOwner()); - assertEquals(null, owners.getDeviceOwnerName()); - assertEquals("com.google.android.testdpc", owners.getDeviceOwnerPackageName()); - assertEquals(UserHandle.USER_SYSTEM, owners.getDeviceOwnerUserId()); + assertThat(owners.hasDeviceOwner()).isTrue(); + assertThat(owners.getDeviceOwnerName()).isEqualTo(null); + assertThat(owners.getDeviceOwnerPackageName()).isEqualTo("com.google.android.testdpc"); + assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_SYSTEM); - assertNull(owners.getSystemUpdatePolicy()); - assertEquals(0, owners.getProfileOwnerKeys().size()); + assertThat(owners.getSystemUpdatePolicy()).isNull(); + assertThat(owners.getProfileOwnerKeys()).isEmpty(); - assertTrue(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); + assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isTrue(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse(); } // Then re-read and check. @@ -130,22 +138,23 @@ public class OwnersTest extends DpmTestBase { final OwnersTestable owners = new OwnersTestable(getServices()); owners.load(); - assertTrue(owners.hasDeviceOwner()); - assertEquals(null, owners.getDeviceOwnerName()); - assertEquals("com.google.android.testdpc", owners.getDeviceOwnerPackageName()); - assertEquals(UserHandle.USER_SYSTEM, owners.getDeviceOwnerUserId()); + assertThat(owners.hasDeviceOwner()).isTrue(); + assertThat(owners.getDeviceOwnerName()).isEqualTo(null); + assertThat(owners.getDeviceOwnerPackageName()).isEqualTo("com.google.android.testdpc"); + assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_SYSTEM); - assertNull(owners.getSystemUpdatePolicy()); - assertEquals(0, owners.getProfileOwnerKeys().size()); + assertThat(owners.getSystemUpdatePolicy()).isNull(); + assertThat(owners.getProfileOwnerKeys()).isEmpty(); - assertTrue(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); + assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isTrue(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse(); } } + @Test public void testUpgrade03() throws Exception { getServices().addUsers(10, 11, 20, 21); @@ -159,36 +168,36 @@ public class OwnersTest extends DpmTestBase { owners.load(); // The legacy file should be removed. - assertFalse(owners.getLegacyConfigFile().exists()); - - assertFalse(owners.getDeviceOwnerFile().exists()); - - assertTrue(owners.getProfileOwnerFile(10).exists()); - assertTrue(owners.getProfileOwnerFile(11).exists()); - assertFalse(owners.getProfileOwnerFile(20).exists()); - assertFalse(owners.getProfileOwnerFile(21).exists()); - - assertFalse(owners.hasDeviceOwner()); - assertEquals(UserHandle.USER_NULL, owners.getDeviceOwnerUserId()); - assertNull(owners.getSystemUpdatePolicy()); - - assertEquals(2, owners.getProfileOwnerKeys().size()); - assertEquals(new ComponentName("com.google.android.testdpc", - "com.google.android.testdpc.DeviceAdminReceiver0"), - owners.getProfileOwnerComponent(10)); - assertEquals("0", owners.getProfileOwnerName(10)); - assertEquals("com.google.android.testdpc", owners.getProfileOwnerPackage(10)); - - assertEquals(new ComponentName("com.google.android.testdpc1", ""), - owners.getProfileOwnerComponent(11)); - assertEquals("1", owners.getProfileOwnerName(11)); - assertEquals("com.google.android.testdpc1", owners.getProfileOwnerPackage(11)); - - assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); - assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); - assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); + assertThat(owners.getLegacyConfigFile().exists()).isFalse(); + + assertThat(owners.getDeviceOwnerFile().exists()).isFalse(); + + assertThat(owners.getProfileOwnerFile(10).exists()).isTrue(); + assertThat(owners.getProfileOwnerFile(11).exists()).isTrue(); + assertThat(owners.getProfileOwnerFile(20).exists()).isFalse(); + assertThat(owners.getProfileOwnerFile(21).exists()).isFalse(); + + assertThat(owners.hasDeviceOwner()).isFalse(); + assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL); + assertThat(owners.getSystemUpdatePolicy()).isNull(); + + assertThat(owners.getProfileOwnerKeys()).hasSize(2); + assertThat(owners.getProfileOwnerComponent(10)) + .isEqualTo(new ComponentName("com.google.android.testdpc", + "com.google.android.testdpc.DeviceAdminReceiver0")); + assertThat(owners.getProfileOwnerName(10)).isEqualTo("0"); + assertThat(owners.getProfileOwnerPackage(10)).isEqualTo("com.google.android.testdpc"); + + assertThat(owners.getProfileOwnerComponent(11)) + .isEqualTo(new ComponentName("com.google.android.testdpc1", "")); + assertThat(owners.getProfileOwnerName(11)).isEqualTo("1"); + assertThat(owners.getProfileOwnerPackage(11)).isEqualTo("com.google.android.testdpc1"); + + assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isTrue(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isTrue(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse(); } // Then re-read and check. @@ -196,27 +205,27 @@ public class OwnersTest extends DpmTestBase { final OwnersTestable owners = new OwnersTestable(getServices()); owners.load(); - assertFalse(owners.hasDeviceOwner()); - assertEquals(UserHandle.USER_NULL, owners.getDeviceOwnerUserId()); - assertNull(owners.getSystemUpdatePolicy()); - - assertEquals(2, owners.getProfileOwnerKeys().size()); - assertEquals(new ComponentName("com.google.android.testdpc", - "com.google.android.testdpc.DeviceAdminReceiver0"), - owners.getProfileOwnerComponent(10)); - assertEquals("0", owners.getProfileOwnerName(10)); - assertEquals("com.google.android.testdpc", owners.getProfileOwnerPackage(10)); - - assertEquals(new ComponentName("com.google.android.testdpc1", ""), - owners.getProfileOwnerComponent(11)); - assertEquals("1", owners.getProfileOwnerName(11)); - assertEquals("com.google.android.testdpc1", owners.getProfileOwnerPackage(11)); - - assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); - assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); - assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); + assertThat(owners.hasDeviceOwner()).isFalse(); + assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL); + assertThat(owners.getSystemUpdatePolicy()).isNull(); + + assertThat(owners.getProfileOwnerKeys()).hasSize(2); + assertThat(owners.getProfileOwnerComponent(10)) + .isEqualTo(new ComponentName("com.google.android.testdpc", + "com.google.android.testdpc.DeviceAdminReceiver0")); + assertThat(owners.getProfileOwnerName(10)).isEqualTo("0"); + assertThat(owners.getProfileOwnerPackage(10)).isEqualTo("com.google.android.testdpc"); + + assertThat(owners.getProfileOwnerComponent(11)) + .isEqualTo(new ComponentName("com.google.android.testdpc1", "")); + assertThat(owners.getProfileOwnerName(11)).isEqualTo("1"); + assertThat(owners.getProfileOwnerPackage(11)).isEqualTo("com.google.android.testdpc1"); + + assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isTrue(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isTrue(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse(); } } @@ -224,6 +233,7 @@ public class OwnersTest extends DpmTestBase { * Note this also tests {@link Owners#setDeviceOwnerUserRestrictionsMigrated()} * and {@link Owners#setProfileOwnerUserRestrictionsMigrated(int)}. */ + @Test public void testUpgrade04() throws Exception { getServices().addUsers(10, 11, 20, 21); @@ -237,40 +247,40 @@ public class OwnersTest extends DpmTestBase { owners.load(); // The legacy file should be removed. - assertFalse(owners.getLegacyConfigFile().exists()); - - assertTrue(owners.getDeviceOwnerFile().exists()); - - assertTrue(owners.getProfileOwnerFile(10).exists()); - assertTrue(owners.getProfileOwnerFile(11).exists()); - assertFalse(owners.getProfileOwnerFile(20).exists()); - assertFalse(owners.getProfileOwnerFile(21).exists()); - - assertTrue(owners.hasDeviceOwner()); - assertEquals(null, owners.getDeviceOwnerName()); - assertEquals("com.google.android.testdpc", owners.getDeviceOwnerPackageName()); - assertEquals(UserHandle.USER_SYSTEM, owners.getDeviceOwnerUserId()); - - assertNotNull(owners.getSystemUpdatePolicy()); - assertEquals(5, owners.getSystemUpdatePolicy().getPolicyType()); - - assertEquals(2, owners.getProfileOwnerKeys().size()); - assertEquals(new ComponentName("com.google.android.testdpc", - "com.google.android.testdpc.DeviceAdminReceiver0"), - owners.getProfileOwnerComponent(10)); - assertEquals("0", owners.getProfileOwnerName(10)); - assertEquals("com.google.android.testdpc", owners.getProfileOwnerPackage(10)); - - assertEquals(new ComponentName("com.google.android.testdpc1", ""), - owners.getProfileOwnerComponent(11)); - assertEquals("1", owners.getProfileOwnerName(11)); - assertEquals("com.google.android.testdpc1", owners.getProfileOwnerPackage(11)); - - assertTrue(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); - assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); - assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); + assertThat(owners.getLegacyConfigFile().exists()).isFalse(); + + assertThat(owners.getDeviceOwnerFile().exists()).isTrue(); + + assertThat(owners.getProfileOwnerFile(10).exists()).isTrue(); + assertThat(owners.getProfileOwnerFile(11).exists()).isTrue(); + assertThat(owners.getProfileOwnerFile(20).exists()).isFalse(); + assertThat(owners.getProfileOwnerFile(21).exists()).isFalse(); + + assertThat(owners.hasDeviceOwner()).isTrue(); + assertThat(owners.getDeviceOwnerName()).isEqualTo(null); + assertThat(owners.getDeviceOwnerPackageName()).isEqualTo("com.google.android.testdpc"); + assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_SYSTEM); + + assertThat(owners.getSystemUpdatePolicy()).isNotNull(); + assertThat(owners.getSystemUpdatePolicy().getPolicyType()).isEqualTo(5); + + assertThat(owners.getProfileOwnerKeys()).hasSize(2); + assertThat(owners.getProfileOwnerComponent(10)) + .isEqualTo(new ComponentName("com.google.android.testdpc", + "com.google.android.testdpc.DeviceAdminReceiver0")); + assertThat(owners.getProfileOwnerName(10)).isEqualTo("0"); + assertThat(owners.getProfileOwnerPackage(10)).isEqualTo("com.google.android.testdpc"); + + assertThat(owners.getProfileOwnerComponent(11)) + .isEqualTo(new ComponentName("com.google.android.testdpc1", "")); + assertThat(owners.getProfileOwnerName(11)).isEqualTo("1"); + assertThat(owners.getProfileOwnerPackage(11)).isEqualTo("com.google.android.testdpc1"); + + assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isTrue(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isTrue(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isTrue(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse(); } // Then re-read and check. @@ -278,31 +288,31 @@ public class OwnersTest extends DpmTestBase { final OwnersTestable owners = new OwnersTestable(getServices()); owners.load(); - assertTrue(owners.hasDeviceOwner()); - assertEquals(null, owners.getDeviceOwnerName()); - assertEquals("com.google.android.testdpc", owners.getDeviceOwnerPackageName()); - assertEquals(UserHandle.USER_SYSTEM, owners.getDeviceOwnerUserId()); + assertThat(owners.hasDeviceOwner()).isTrue(); + assertThat(owners.getDeviceOwnerName()).isEqualTo(null); + assertThat(owners.getDeviceOwnerPackageName()).isEqualTo("com.google.android.testdpc"); + assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_SYSTEM); - assertNotNull(owners.getSystemUpdatePolicy()); - assertEquals(5, owners.getSystemUpdatePolicy().getPolicyType()); + assertThat(owners.getSystemUpdatePolicy()).isNotNull(); + assertThat(owners.getSystemUpdatePolicy().getPolicyType()).isEqualTo(5); - assertEquals(2, owners.getProfileOwnerKeys().size()); - assertEquals(new ComponentName("com.google.android.testdpc", - "com.google.android.testdpc.DeviceAdminReceiver0"), - owners.getProfileOwnerComponent(10)); - assertEquals("0", owners.getProfileOwnerName(10)); - assertEquals("com.google.android.testdpc", owners.getProfileOwnerPackage(10)); + assertThat(owners.getProfileOwnerKeys()).hasSize(2); + assertThat(owners.getProfileOwnerComponent(10)) + .isEqualTo(new ComponentName("com.google.android.testdpc", + "com.google.android.testdpc.DeviceAdminReceiver0")); + assertThat(owners.getProfileOwnerName(10)).isEqualTo("0"); + assertThat(owners.getProfileOwnerPackage(10)).isEqualTo("com.google.android.testdpc"); - assertEquals(new ComponentName("com.google.android.testdpc1", ""), - owners.getProfileOwnerComponent(11)); - assertEquals("1", owners.getProfileOwnerName(11)); - assertEquals("com.google.android.testdpc1", owners.getProfileOwnerPackage(11)); + assertThat(owners.getProfileOwnerComponent(11)) + .isEqualTo(new ComponentName("com.google.android.testdpc1", "")); + assertThat(owners.getProfileOwnerName(11)).isEqualTo("1"); + assertThat(owners.getProfileOwnerPackage(11)).isEqualTo("com.google.android.testdpc1"); - assertTrue(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); - assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); - assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); + assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isTrue(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isTrue(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isTrue(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse(); owners.setDeviceOwnerUserRestrictionsMigrated(); } @@ -311,11 +321,11 @@ public class OwnersTest extends DpmTestBase { final OwnersTestable owners = new OwnersTestable(getServices()); owners.load(); - assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); - assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); - assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); + assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isTrue(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isTrue(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse(); owners.setProfileOwnerUserRestrictionsMigrated(11); } @@ -324,16 +334,17 @@ public class OwnersTest extends DpmTestBase { final OwnersTestable owners = new OwnersTestable(getServices()); owners.load(); - assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); - assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); + assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isTrue(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse(); owners.setProfileOwnerUserRestrictionsMigrated(11); } } + @Test public void testUpgrade05() throws Exception { getServices().addUsers(10, 11, 20, 21); @@ -347,27 +358,27 @@ public class OwnersTest extends DpmTestBase { owners.load(); // The legacy file should be removed. - assertFalse(owners.getLegacyConfigFile().exists()); + assertThat(owners.getLegacyConfigFile().exists()).isFalse(); // Note device initializer is no longer supported. No need to write the DO file. - assertFalse(owners.getDeviceOwnerFile().exists()); + assertThat(owners.getDeviceOwnerFile().exists()).isFalse(); - assertFalse(owners.getProfileOwnerFile(10).exists()); - assertFalse(owners.getProfileOwnerFile(11).exists()); - assertFalse(owners.getProfileOwnerFile(20).exists()); + assertThat(owners.getProfileOwnerFile(10).exists()).isFalse(); + assertThat(owners.getProfileOwnerFile(11).exists()).isFalse(); + assertThat(owners.getProfileOwnerFile(20).exists()).isFalse(); - assertFalse(owners.hasDeviceOwner()); - assertEquals(UserHandle.USER_NULL, owners.getDeviceOwnerUserId()); + assertThat(owners.hasDeviceOwner()).isFalse(); + assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL); - assertNull(owners.getSystemUpdatePolicy()); - assertEquals(0, owners.getProfileOwnerKeys().size()); + assertThat(owners.getSystemUpdatePolicy()).isNull(); + assertThat(owners.getProfileOwnerKeys()).isEmpty(); - assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); + assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse(); } // Then re-read and check. @@ -375,21 +386,22 @@ public class OwnersTest extends DpmTestBase { final OwnersTestable owners = new OwnersTestable(getServices()); owners.load(); - assertFalse(owners.hasDeviceOwner()); - assertEquals(UserHandle.USER_NULL, owners.getDeviceOwnerUserId()); + assertThat(owners.hasDeviceOwner()).isFalse(); + assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL); - assertNull(owners.getSystemUpdatePolicy()); - assertEquals(0, owners.getProfileOwnerKeys().size()); + assertThat(owners.getSystemUpdatePolicy()).isNull(); + assertThat(owners.getProfileOwnerKeys()).isEmpty(); - assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); + assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse(); } } + @Test public void testUpgrade06() throws Exception { getServices().addUsers(10, 11, 20, 21); @@ -403,26 +415,26 @@ public class OwnersTest extends DpmTestBase { owners.load(); // The legacy file should be removed. - assertFalse(owners.getLegacyConfigFile().exists()); + assertThat(owners.getLegacyConfigFile().exists()).isFalse(); - assertTrue(owners.getDeviceOwnerFile().exists()); + assertThat(owners.getDeviceOwnerFile().exists()).isTrue(); - assertFalse(owners.getProfileOwnerFile(10).exists()); - assertFalse(owners.getProfileOwnerFile(11).exists()); - assertFalse(owners.getProfileOwnerFile(20).exists()); + assertThat(owners.getProfileOwnerFile(10).exists()).isFalse(); + assertThat(owners.getProfileOwnerFile(11).exists()).isFalse(); + assertThat(owners.getProfileOwnerFile(20).exists()).isFalse(); - assertFalse(owners.hasDeviceOwner()); - assertEquals(UserHandle.USER_NULL, owners.getDeviceOwnerUserId()); - assertEquals(0, owners.getProfileOwnerKeys().size()); + assertThat(owners.hasDeviceOwner()).isFalse(); + assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL); + assertThat(owners.getProfileOwnerKeys()).isEmpty(); - assertNotNull(owners.getSystemUpdatePolicy()); - assertEquals(5, owners.getSystemUpdatePolicy().getPolicyType()); + assertThat(owners.getSystemUpdatePolicy()).isNotNull(); + assertThat(owners.getSystemUpdatePolicy().getPolicyType()).isEqualTo(5); - assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); + assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse(); } // Then re-read and check. @@ -430,21 +442,22 @@ public class OwnersTest extends DpmTestBase { final OwnersTestable owners = new OwnersTestable(getServices()); owners.load(); - assertFalse(owners.hasDeviceOwner()); - assertEquals(UserHandle.USER_NULL, owners.getDeviceOwnerUserId()); - assertEquals(0, owners.getProfileOwnerKeys().size()); + assertThat(owners.hasDeviceOwner()).isFalse(); + assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL); + assertThat(owners.getProfileOwnerKeys()).isEmpty(); - assertNotNull(owners.getSystemUpdatePolicy()); - assertEquals(5, owners.getSystemUpdatePolicy().getPolicyType()); + assertThat(owners.getSystemUpdatePolicy()).isNotNull(); + assertThat(owners.getSystemUpdatePolicy().getPolicyType()).isEqualTo(5); - assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); - assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); + assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse(); + assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse(); } } + @Test public void testRemoveExistingFiles() throws Exception { getServices().addUsers(10, 11, 20, 21); @@ -456,11 +469,11 @@ public class OwnersTest extends DpmTestBase { owners.load(); - assertFalse(owners.getLegacyConfigFile().exists()); + assertThat(owners.getLegacyConfigFile().exists()).isFalse(); - assertTrue(owners.getDeviceOwnerFile().exists()); - assertTrue(owners.getProfileOwnerFile(10).exists()); - assertTrue(owners.getProfileOwnerFile(11).exists()); + assertThat(owners.getDeviceOwnerFile().exists()).isTrue(); + assertThat(owners.getProfileOwnerFile(10).exists()).isTrue(); + assertThat(owners.getProfileOwnerFile(11).exists()).isTrue(); // Then clear all information and save. owners.clearDeviceOwner(); @@ -475,8 +488,8 @@ public class OwnersTest extends DpmTestBase { owners.writeProfileOwner(21); // Now all files should be removed. - assertFalse(owners.getDeviceOwnerFile().exists()); - assertFalse(owners.getProfileOwnerFile(10).exists()); - assertFalse(owners.getProfileOwnerFile(11).exists()); + assertThat(owners.getDeviceOwnerFile().exists()).isFalse(); + assertThat(owners.getProfileOwnerFile(10).exists()).isFalse(); + assertThat(owners.getProfileOwnerFile(11).exists()).isFalse(); } } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/SecurityEventTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/SecurityEventTest.java index 8dcf21f9fe77..6cefaebbff7a 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/SecurityEventTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/SecurityEventTest.java @@ -1,3 +1,18 @@ +/* + * 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.devicepolicy; import static android.app.admin.SecurityLog.TAG_ADB_SHELL_CMD; @@ -11,6 +26,8 @@ import static android.app.admin.SecurityLog.TAG_KEY_INTEGRITY_VIOLATION; import static android.app.admin.SecurityLog.TAG_MEDIA_MOUNT; import static android.app.admin.SecurityLog.TAG_MEDIA_UNMOUNT; +import static com.google.common.truth.Truth.assertThat; + import android.app.admin.SecurityLog.SecurityEvent; import android.os.Parcel; import android.os.UserHandle; @@ -18,21 +35,37 @@ import android.text.TextUtils; import android.util.EventLog; import android.util.EventLog.Event; +import androidx.test.runner.AndroidJUnit4; + import junit.framework.AssertionFailedError; +import org.junit.Test; +import org.junit.runner.RunWith; + import java.util.ArrayList; import java.util.List; +/** + * Tests for the DeviceOwner object that saves & loads device and policy owner information. + * + * <p>Run this test with: + * + * {@code atest FrameworksServicesTests:com.android.server.devicepolicy.SecurityEventTest} + * + */ +@RunWith(AndroidJUnit4.class) public class SecurityEventTest extends DpmTestBase { + @Test public void testSecurityEventId() throws Exception { SecurityEvent event = createEvent(() -> { EventLog.writeEvent(TAG_ADB_SHELL_CMD, 0); }, TAG_ADB_SHELL_CMD); event.setId(20); - assertEquals(20, event.getId()); + assertThat(event.getId()).isEqualTo(20); } + @Test public void testSecurityEventParceling() throws Exception { // GIVEN an event. SecurityEvent event = createEvent(() -> { @@ -45,12 +78,13 @@ public class SecurityEventTest extends DpmTestBase { SecurityEvent unparceledEvent = p.readParcelable(SecurityEventTest.class.getClassLoader()); p.recycle(); // THEN the event state is preserved. - assertEquals(event.getTag(), unparceledEvent.getTag()); - assertEquals(event.getData(), unparceledEvent.getData()); - assertEquals(event.getTimeNanos(), unparceledEvent.getTimeNanos()); - assertEquals(event.getId(), unparceledEvent.getId()); + assertThat(unparceledEvent.getTag()).isEqualTo(event.getTag()); + assertThat(unparceledEvent.getData()).isEqualTo(event.getData()); + assertThat(unparceledEvent.getTimeNanos()).isEqualTo(event.getTimeNanos()); + assertThat(unparceledEvent.getId()).isEqualTo(event.getId()); } + @Test public void testSecurityEventRedaction() throws Exception { SecurityEvent event; @@ -58,75 +92,75 @@ public class SecurityEventTest extends DpmTestBase { event = createEvent(() -> { EventLog.writeEvent(TAG_ADB_SHELL_CMD, "command"); }, TAG_ADB_SHELL_CMD); - assertFalse(TextUtils.isEmpty((String) event.getData())); + assertThat(TextUtils.isEmpty((String) event.getData())).isFalse(); // TAG_MEDIA_MOUNT will have the volume label redacted (second data) event = createEvent(() -> { EventLog.writeEvent(TAG_MEDIA_MOUNT, new Object[] {"path", "label"}); }, TAG_MEDIA_MOUNT); - assertFalse(TextUtils.isEmpty(event.getStringData(1))); - assertTrue(TextUtils.isEmpty(event.redact(0).getStringData(1))); + assertThat(TextUtils.isEmpty(event.getStringData(1))).isFalse(); + assertThat(TextUtils.isEmpty(event.redact(0).getStringData(1))).isTrue(); // TAG_MEDIA_UNMOUNT will have the volume label redacted (second data) event = createEvent(() -> { EventLog.writeEvent(TAG_MEDIA_UNMOUNT, new Object[] {"path", "label"}); }, TAG_MEDIA_UNMOUNT); - assertFalse(TextUtils.isEmpty(event.getStringData(1))); - assertTrue(TextUtils.isEmpty(event.redact(0).getStringData(1))); + assertThat(TextUtils.isEmpty(event.getStringData(1))).isFalse(); + assertThat(TextUtils.isEmpty(event.redact(0).getStringData(1))).isTrue(); // TAG_APP_PROCESS_START will be fully redacted if user does not match event = createEvent(() -> { EventLog.writeEvent(TAG_APP_PROCESS_START, new Object[] {"process", 12345L, UserHandle.getUid(10, 123), 456, "seinfo", "hash"}); }, TAG_APP_PROCESS_START); - assertNotNull(event.redact(10)); - assertNull(event.redact(11)); + assertThat(event.redact(10)).isNotNull(); + assertThat(event.redact(11)).isNull(); // TAG_CERT_AUTHORITY_INSTALLED will be fully redacted if user does not match event = createEvent(() -> { EventLog.writeEvent(TAG_CERT_AUTHORITY_INSTALLED, new Object[] {1, "subject", 10}); }, TAG_CERT_AUTHORITY_INSTALLED); - assertNotNull(event.redact(10)); - assertNull(event.redact(11)); + assertThat(event.redact(10)).isNotNull(); + assertThat(event.redact(11)).isNull(); // TAG_CERT_AUTHORITY_REMOVED will be fully redacted if user does not match event = createEvent(() -> { EventLog.writeEvent(TAG_CERT_AUTHORITY_REMOVED, new Object[] {1, "subject", 20}); }, TAG_CERT_AUTHORITY_REMOVED); - assertNotNull(event.redact(20)); - assertNull(event.redact(0)); + assertThat(event.redact(20)).isNotNull(); + assertThat(event.redact(0)).isNull(); // TAG_KEY_GENERATED will be fully redacted if user does not match event = createEvent(() -> { EventLog.writeEvent(TAG_KEY_GENERATED, new Object[] {1, "alias", UserHandle.getUid(0, 123)}); }, TAG_KEY_GENERATED); - assertNotNull(event.redact(0)); - assertNull(event.redact(10)); + assertThat(event.redact(0)).isNotNull(); + assertThat(event.redact(10)).isNull(); // TAG_KEY_IMPORT will be fully redacted if user does not match event = createEvent(() -> { EventLog.writeEvent(TAG_KEY_IMPORT, new Object[] {1, "alias", UserHandle.getUid(1, 123)}); }, TAG_KEY_IMPORT); - assertNotNull(event.redact(1)); - assertNull(event.redact(10)); + assertThat(event.redact(1)).isNotNull(); + assertThat(event.redact(10)).isNull(); // TAG_KEY_DESTRUCTION will be fully redacted if user does not match event = createEvent(() -> { EventLog.writeEvent(TAG_KEY_DESTRUCTION, new Object[] {1, "alias", UserHandle.getUid(2, 123)}); }, TAG_KEY_DESTRUCTION); - assertNotNull(event.redact(2)); - assertNull(event.redact(10)); + assertThat(event.redact(2)).isNotNull(); + assertThat(event.redact(10)).isNull(); // TAG_KEY_INTEGRITY_VIOLATION will be fully redacted if user does not match event = createEvent(() -> { EventLog.writeEvent(TAG_KEY_INTEGRITY_VIOLATION, new Object[] {"alias", UserHandle.getUid(2, 123)}); }, TAG_KEY_INTEGRITY_VIOLATION); - assertNotNull(event.redact(2)); - assertNull(event.redact(10)); + assertThat(event.redact(2)).isNotNull(); + assertThat(event.redact(10)).isNull(); } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java index e51859b5c829..0a9aad771ff0 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java @@ -21,8 +21,9 @@ import static android.app.admin.SystemUpdatePolicy.ValidationFailedException.ERR import static android.app.admin.SystemUpdatePolicy.ValidationFailedException.ERROR_NEW_FREEZE_PERIOD_TOO_CLOSE; import static android.app.admin.SystemUpdatePolicy.ValidationFailedException.ERROR_NEW_FREEZE_PERIOD_TOO_LONG; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + import static org.junit.Assert.fail; import android.app.admin.FreezePeriod; @@ -53,10 +54,12 @@ import java.util.concurrent.TimeUnit; /** * Unit tests for {@link android.app.admin.SystemUpdatePolicy}. - * Throughout this test, we use "MM-DD" format to denote dates without year. * - * atest com.android.server.devicepolicy.SystemUpdatePolicyTest - * runtest -c com.android.server.devicepolicy.SystemUpdatePolicyTest frameworks-services + * <p>NOTE: Throughout this test, we use {@code "MM-DD"} format to denote dates without year. + * + * <p>Run this test with: + * + * {@code atest FrameworksServicesTests:com.android.server.devicepolicy.SystemUpdatePolicyTest} */ @RunWith(AndroidJUnit4.class) public final class SystemUpdatePolicyTest { @@ -224,37 +227,37 @@ public final class SystemUpdatePolicyTest { @Test public void testDistanceWithoutLeapYear() { - assertEquals(364, FreezePeriod.distanceWithoutLeapYear( - LocalDate.of(2016, 12, 31), LocalDate.of(2016, 1, 1))); - assertEquals(365, FreezePeriod.distanceWithoutLeapYear( - LocalDate.of(2017, 1, 1), LocalDate.of(2016, 1, 1))); - assertEquals(365, FreezePeriod.distanceWithoutLeapYear( - LocalDate.of(2017, 2, 28), LocalDate.of(2016, 2, 29))); - assertEquals(-365, FreezePeriod.distanceWithoutLeapYear( - LocalDate.of(2016, 1, 1), LocalDate.of(2017, 1, 1))); - assertEquals(1, FreezePeriod.distanceWithoutLeapYear( - LocalDate.of(2016, 3, 1), LocalDate.of(2016, 2, 29))); - assertEquals(1, FreezePeriod.distanceWithoutLeapYear( - LocalDate.of(2016, 3, 1), LocalDate.of(2016, 2, 28))); - assertEquals(0, FreezePeriod.distanceWithoutLeapYear( - LocalDate.of(2016, 2, 29), LocalDate.of(2016, 2, 28))); - assertEquals(0, FreezePeriod.distanceWithoutLeapYear( - LocalDate.of(2016, 2, 28), LocalDate.of(2016, 2, 28))); - - assertEquals(59, FreezePeriod.distanceWithoutLeapYear( - LocalDate.of(2016, 3, 1), LocalDate.of(2016, 1, 1))); - assertEquals(59, FreezePeriod.distanceWithoutLeapYear( - LocalDate.of(2017, 3, 1), LocalDate.of(2017, 1, 1))); - - assertEquals(365 * 40, FreezePeriod.distanceWithoutLeapYear( - LocalDate.of(2040, 1, 1), LocalDate.of(2000, 1, 1))); - - assertEquals(365 * 2, FreezePeriod.distanceWithoutLeapYear( - LocalDate.of(2019, 3, 1), LocalDate.of(2017, 3, 1))); - assertEquals(365 * 2, FreezePeriod.distanceWithoutLeapYear( - LocalDate.of(2018, 3, 1), LocalDate.of(2016, 3, 1))); - assertEquals(365 * 2, FreezePeriod.distanceWithoutLeapYear( - LocalDate.of(2017, 3, 1), LocalDate.of(2015, 3, 1))); + assertThat(FreezePeriod.distanceWithoutLeapYear( + LocalDate.of(2016, 12, 31), LocalDate.of(2016, 1, 1))).isEqualTo(364); + assertThat(FreezePeriod.distanceWithoutLeapYear( + LocalDate.of(2017, 1, 1), LocalDate.of(2016, 1, 1))).isEqualTo(365); + assertThat(FreezePeriod.distanceWithoutLeapYear( + LocalDate.of(2017, 2, 28), LocalDate.of(2016, 2, 29))).isEqualTo(365); + assertThat(FreezePeriod.distanceWithoutLeapYear( + LocalDate.of(2016, 1, 1), LocalDate.of(2017, 1, 1))).isEqualTo(-365); + assertThat(FreezePeriod.distanceWithoutLeapYear( + LocalDate.of(2016, 3, 1), LocalDate.of(2016, 2, 29))).isEqualTo(1); + assertThat(FreezePeriod.distanceWithoutLeapYear( + LocalDate.of(2016, 3, 1), LocalDate.of(2016, 2, 28))).isEqualTo(1); + assertThat(FreezePeriod.distanceWithoutLeapYear( + LocalDate.of(2016, 2, 29), LocalDate.of(2016, 2, 28))).isEqualTo(0); + assertThat(FreezePeriod.distanceWithoutLeapYear( + LocalDate.of(2016, 2, 28), LocalDate.of(2016, 2, 28))).isEqualTo(0); + + assertThat(FreezePeriod.distanceWithoutLeapYear( + LocalDate.of(2016, 3, 1), LocalDate.of(2016, 1, 1))).isEqualTo(59); + assertThat(FreezePeriod.distanceWithoutLeapYear( + LocalDate.of(2017, 3, 1), LocalDate.of(2017, 1, 1))).isEqualTo(59); + + assertThat(FreezePeriod.distanceWithoutLeapYear( + LocalDate.of(2040, 1, 1), LocalDate.of(2000, 1, 1))).isEqualTo(365 * 40); + + assertThat(FreezePeriod.distanceWithoutLeapYear( + LocalDate.of(2019, 3, 1), LocalDate.of(2017, 3, 1))).isEqualTo(365 * 2); + assertThat(FreezePeriod.distanceWithoutLeapYear( + LocalDate.of(2018, 3, 1), LocalDate.of(2016, 3, 1))).isEqualTo(365 * 2); + assertThat(FreezePeriod.distanceWithoutLeapYear( + LocalDate.of(2017, 3, 1), LocalDate.of(2015, 3, 1))).isEqualTo(365 * 2); } @@ -395,8 +398,8 @@ public final class SystemUpdatePolicyTest { private void assertInstallationOption(int expectedType, long expectedTime, long now, SystemUpdatePolicy p) { - assertEquals(expectedType, p.getInstallationOptionAt(now).getType()); - assertEquals(expectedTime, p.getInstallationOptionAt(now).getEffectiveTime()); + assertThat(p.getInstallationOptionAt(now).getType()).isEqualTo(expectedType); + assertThat(p.getInstallationOptionAt(now).getEffectiveTime()).isEqualTo(expectedTime); } private void testFreezePeriodsSucceeds(String...dates) throws Exception { @@ -410,8 +413,8 @@ public final class SystemUpdatePolicyTest { setFreezePeriods(p, dates); fail("Invalid periods (" + expectedError + ") not flagged: " + String.join(" ", dates)); } catch (SystemUpdatePolicy.ValidationFailedException e) { - assertTrue("Exception not expected: " + e.getMessage(), - e.getErrorCode() == expectedError); + assertWithMessage("Exception not expected: %s", e.getMessage()).that(e.getErrorCode()) + .isEqualTo(expectedError); } } @@ -426,8 +429,8 @@ public final class SystemUpdatePolicyTest { createPrevFreezePeriod(prevStart, prevEnd, now, dates); fail("Invalid period (" + expectedError + ") not flagged: " + String.join(" ", dates)); } catch (SystemUpdatePolicy.ValidationFailedException e) { - assertTrue("Exception not expected: " + e.getMessage(), - e.getErrorCode() == expectedError); + assertWithMessage("Exception not expected: %s", e.getMessage()).that(e.getErrorCode()) + .isEqualTo(expectedError); } } @@ -480,7 +483,7 @@ public final class SystemUpdatePolicyTest { ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray()); XmlPullParser parser = Xml.newPullParser(); parser.setInput(new InputStreamReader(inStream)); - assertEquals(XmlPullParser.START_TAG, parser.next()); + assertThat(parser.next()).isEqualTo(XmlPullParser.START_TAG); checkFreezePeriods(SystemUpdatePolicy.restoreFromXml(parser), expectedPeriods); } @@ -488,8 +491,8 @@ public final class SystemUpdatePolicyTest { List<FreezePeriod> expectedPeriods) { int i = 0; for (FreezePeriod period : policy.getFreezePeriods()) { - assertEquals(expectedPeriods.get(i).getStart(), period.getStart()); - assertEquals(expectedPeriods.get(i).getEnd(), period.getEnd()); + assertThat(period.getStart()).isEqualTo(expectedPeriods.get(i).getStart()); + assertThat(period.getEnd()).isEqualTo(expectedPeriods.get(i).getEnd()); i++; } } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/TransferOwnershipMetadataManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/TransferOwnershipMetadataManagerTest.java index 2005dd901ad1..07ea85535f50 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/TransferOwnershipMetadataManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/TransferOwnershipMetadataManagerTest.java @@ -25,14 +25,13 @@ import static com.android.server.devicepolicy.TransferOwnershipMetadataManager.T import static com.android.server.devicepolicy.TransferOwnershipMetadataManager.TAG_TARGET_COMPONENT; import static com.android.server.devicepolicy.TransferOwnershipMetadataManager.TAG_USER_ID; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static com.google.common.truth.Truth.assertThat; import android.os.Environment; -import androidx.test.runner.AndroidJUnit4; import android.util.Log; +import androidx.test.runner.AndroidJUnit4; + import com.android.server.devicepolicy.TransferOwnershipMetadataManager.Injector; import com.android.server.devicepolicy.TransferOwnershipMetadataManager.Metadata; @@ -51,12 +50,14 @@ import java.nio.file.Paths; /** * Unit tests for {@link TransferOwnershipMetadataManager}. * - * bit FrameworksServicesTests:com.android.server.devicepolicy.TransferOwnershipMetadataManagerTest - * runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/devicepolicy/TransferOwnershipMetadataManagerTest.java -* */ - + * <p>Run this test with: + * + * <pre><code> + atest FrameworksServicesTests:com.android.server.devicepolicy.TransferOwnershipMetadataManagerTest + * </code></pre> + */ @RunWith(AndroidJUnit4.class) -public class TransferOwnershipMetadataManagerTest { +public final class TransferOwnershipMetadataManagerTest { private final static String TAG = TransferOwnershipMetadataManagerTest.class.getName(); private final static String SOURCE_COMPONENT = "com.dummy.admin.package/com.dummy.admin.package.SourceClassName"; @@ -77,28 +78,27 @@ public class TransferOwnershipMetadataManagerTest { @Test public void testSave() { TransferOwnershipMetadataManager paramsManager = getOwnerTransferParams(); - assertTrue(paramsManager.saveMetadataFile(TEST_PARAMS)); - assertTrue(paramsManager.metadataFileExists()); + assertThat(paramsManager.saveMetadataFile(TEST_PARAMS)).isTrue(); + assertThat(paramsManager.metadataFileExists()).isTrue(); } @Test public void testFileContentValid() { TransferOwnershipMetadataManager paramsManager = getOwnerTransferParams(); - assertTrue(paramsManager.saveMetadataFile(TEST_PARAMS)); + assertThat(paramsManager.saveMetadataFile(TEST_PARAMS)).isTrue(); Path path = Paths.get(new File(mMockInjector.getOwnerTransferMetadataDir(), OWNER_TRANSFER_METADATA_XML).getAbsolutePath()); try { String contents = new String(Files.readAllBytes(path), Charset.forName("UTF-8")); - assertEquals( - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" - + "<" + TAG_USER_ID + ">" + USER_ID + "</" + TAG_USER_ID + ">\n" - + "<" + TAG_SOURCE_COMPONENT + ">" + SOURCE_COMPONENT + "</" - + TAG_SOURCE_COMPONENT + ">\n" - + "<" + TAG_TARGET_COMPONENT + ">" + TARGET_COMPONENT + "</" - + TAG_TARGET_COMPONENT + ">\n" - + "<" + TAG_ADMIN_TYPE + ">" + ADMIN_TYPE_DEVICE_OWNER + "</" - + TAG_ADMIN_TYPE + ">\n", - contents); + assertThat(contents).isEqualTo( + "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" + + "<" + TAG_USER_ID + ">" + USER_ID + "</" + TAG_USER_ID + ">\n" + + "<" + TAG_SOURCE_COMPONENT + ">" + SOURCE_COMPONENT + "</" + + TAG_SOURCE_COMPONENT + ">\n" + + "<" + TAG_TARGET_COMPONENT + ">" + TARGET_COMPONENT + "</" + + TAG_TARGET_COMPONENT + ">\n" + + "<" + TAG_ADMIN_TYPE + ">" + ADMIN_TYPE_DEVICE_OWNER + "</" + + TAG_ADMIN_TYPE + ">\n"); } catch (IOException e) { e.printStackTrace(); } @@ -124,7 +124,7 @@ public class TransferOwnershipMetadataManagerTest { Log.d(TAG, "testLoad: failed to get canonical file"); } paramsManager.saveMetadataFile(TEST_PARAMS); - assertEquals(TEST_PARAMS, paramsManager.loadMetadataFile()); + assertThat(paramsManager.loadMetadataFile()).isEqualTo(TEST_PARAMS); } @Test @@ -132,7 +132,7 @@ public class TransferOwnershipMetadataManagerTest { TransferOwnershipMetadataManager paramsManager = getOwnerTransferParams(); paramsManager.saveMetadataFile(TEST_PARAMS); paramsManager.deleteMetadataFile(); - assertFalse(paramsManager.metadataFileExists()); + assertThat(paramsManager.metadataFileExists()).isFalse(); } @After diff --git a/services/tests/servicestests/src/com/android/server/pm/permission/PermissionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/permission/PermissionManagerServiceTest.java index 56966776c8fb..6cea9280f080 100644 --- a/services/tests/servicestests/src/com/android/server/pm/permission/PermissionManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/permission/PermissionManagerServiceTest.java @@ -69,8 +69,7 @@ public class PermissionManagerServiceTest { MockitoAnnotations.initMocks(this); mContext = InstrumentationRegistry.getContext(); - Object lock = new Object(); - mPermissionManagerService = new PermissionManagerService(mContext, lock, mInjector); + mPermissionManagerService = new PermissionManagerService(mContext, mInjector); } @After diff --git a/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java b/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java index af161ee8b818..ca0270deb398 100644 --- a/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java +++ b/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java @@ -70,7 +70,6 @@ public class AttentionDetectorTest extends AndroidTestCase { private Runnable mOnUserAttention; private TestableAttentionDetector mAttentionDetector; private AttentionDetector mRealAttentionDetector; - private long mPreDimCheckDuration; private long mNextDimming; private int mIsSettingEnabled; @@ -342,23 +341,14 @@ public class AttentionDetectorTest extends AndroidTestCase { public void testGetPostDimCheckDurationMillis_handlesGoodFlagValue() { DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE, KEY_POST_DIM_CHECK_DURATION_MILLIS, "333", false); - assertThat(mRealAttentionDetector.getPostDimCheckDurationMillis( - DEFAULT_DIM_DURATION_MILLIS)).isEqualTo(333); - } - - @Test - public void testGetPostDimCheckDurationMillis_capsGoodFlagValueByMaxDimDuration() { - DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE, - KEY_POST_DIM_CHECK_DURATION_MILLIS, "7000", false); - assertThat(mRealAttentionDetector.getPostDimCheckDurationMillis(6500)).isEqualTo(6500); + assertThat(mRealAttentionDetector.getPostDimCheckDurationMillis()).isEqualTo(333); } @Test public void testGetPostDimCheckDurationMillis_rejectsNegativeValue() { DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE, KEY_POST_DIM_CHECK_DURATION_MILLIS, "-50", false); - assertThat(mRealAttentionDetector.getPostDimCheckDurationMillis( - DEFAULT_DIM_DURATION_MILLIS)).isEqualTo( + assertThat(mRealAttentionDetector.getPostDimCheckDurationMillis()).isEqualTo( DEFAULT_POST_DIM_CHECK_DURATION_MILLIS); } @@ -366,8 +356,7 @@ public class AttentionDetectorTest extends AndroidTestCase { public void testGetPostDimCheckDurationMillis_rejectsTooBigValue() { DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE, KEY_POST_DIM_CHECK_DURATION_MILLIS, "20000", false); - assertThat(mRealAttentionDetector.getPostDimCheckDurationMillis( - DEFAULT_DIM_DURATION_MILLIS)).isEqualTo( + assertThat(mRealAttentionDetector.getPostDimCheckDurationMillis()).isEqualTo( DEFAULT_POST_DIM_CHECK_DURATION_MILLIS); } @@ -375,14 +364,12 @@ public class AttentionDetectorTest extends AndroidTestCase { public void testGetPostDimCheckDurationMillis_handlesBadFlagValue() { DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE, KEY_POST_DIM_CHECK_DURATION_MILLIS, "20000k", false); - assertThat(mRealAttentionDetector.getPostDimCheckDurationMillis( - DEFAULT_DIM_DURATION_MILLIS)).isEqualTo( + assertThat(mRealAttentionDetector.getPostDimCheckDurationMillis()).isEqualTo( DEFAULT_POST_DIM_CHECK_DURATION_MILLIS); DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE, KEY_POST_DIM_CHECK_DURATION_MILLIS, "0.25", false); - assertThat(mRealAttentionDetector.getPostDimCheckDurationMillis( - DEFAULT_DIM_DURATION_MILLIS)).isEqualTo( + assertThat(mRealAttentionDetector.getPostDimCheckDurationMillis()).isEqualTo( DEFAULT_POST_DIM_CHECK_DURATION_MILLIS); } @@ -423,7 +410,7 @@ public class AttentionDetectorTest extends AndroidTestCase { } private long registerAttention() { - mPreDimCheckDuration = 4000L; + mAttentionDetector.mPreDimCheckDurationMillis = 4000L; mAttentionDetector.onUserActivity(SystemClock.uptimeMillis(), PowerManager.USER_ACTIVITY_EVENT_TOUCH); return mAttentionDetector.updateUserActivity(mNextDimming, DEFAULT_DIM_DURATION_MILLIS); @@ -447,10 +434,5 @@ public class AttentionDetectorTest extends AndroidTestCase { public boolean isAttentionServiceSupported() { return mAttentionServiceSupported; } - - @Override - public long getPreDimCheckDurationMillis() { - return mPreDimCheckDuration; - } } } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java index b4480aea3ce4..f1d49d5fc6c2 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java @@ -976,6 +976,21 @@ public class WindowOrganizerTests extends WindowTestsBase { }); } + @Test + public void testReparentToOrganizedTask() { + final ITaskOrganizer organizer = registerMockOrganizer(); + Task rootTask = mWm.mAtmService.mTaskOrganizerController.createRootTask( + mDisplayContent, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, null); + final Task task1 = createStack(); + final Task task2 = createTask(rootTask, false /* fakeDraw */); + WindowContainerTransaction wct = new WindowContainerTransaction(); + wct.reparent(task1.mRemoteToken.toWindowContainerToken(), + rootTask.mRemoteToken.toWindowContainerToken(), true /* onTop */); + mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); + assertTrue(task1.isOrganized()); + assertTrue(task2.isOrganized()); + } + /** * Verifies that task vanished is called for a specific task. */ diff --git a/core/tests/coretests/src/android/app/appsearch/external/app/SearchResultsTest.java b/wifi/aidl-export/android/net/wifi/aware/AwareResources.aidl index acbf11ae8669..d0bd2dda5722 100644 --- a/core/tests/coretests/src/android/app/appsearch/external/app/SearchResultsTest.java +++ b/wifi/aidl-export/android/net/wifi/aware/AwareResources.aidl @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Android Open Source Project + * 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. @@ -14,17 +14,6 @@ * limitations under the License. */ -package android.app.appsearch; +package android.net.wifi.aware; -import static org.testng.Assert.expectThrows; - -import org.junit.Test; - -public class SearchResultsTest { - @Test - public void buildSearchSpecWithoutTermMatchType() { - expectThrows(RuntimeException.class, () -> new SearchSpec.Builder() - .setSchemaTypes("testSchemaType") - .build()); - } -} +parcelable AwareResources;
\ No newline at end of file diff --git a/wifi/api/current.txt b/wifi/api/current.txt index 0bc1ff22b704..d5ef703253cb 100644 --- a/wifi/api/current.txt +++ b/wifi/api/current.txt @@ -561,6 +561,15 @@ package android.net.wifi.aware { method public void onAttached(android.net.wifi.aware.WifiAwareSession); } + public final class AwareResources implements android.os.Parcelable { + method public int describeContents(); + method public int getNumOfAvailableDataPaths(); + method public int getNumOfAvailablePublishSessions(); + method public int getNumOfAvailableSubscribeSessions(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.aware.AwareResources> CREATOR; + } + public final class Characteristics implements android.os.Parcelable { method public int describeContents(); method public int getMaxMatchFilterLength(); @@ -663,7 +672,8 @@ package android.net.wifi.aware { public class WifiAwareManager { method public void attach(@NonNull android.net.wifi.aware.AttachCallback, @Nullable android.os.Handler); method public void attach(@NonNull android.net.wifi.aware.AttachCallback, @NonNull android.net.wifi.aware.IdentityChangedListener, @Nullable android.os.Handler); - method public android.net.wifi.aware.Characteristics getCharacteristics(); + method @Nullable public android.net.wifi.aware.AwareResources getAvailableAwareResources(); + method @Nullable public android.net.wifi.aware.Characteristics getCharacteristics(); method public boolean isAvailable(); method public boolean isDeviceAttached(); method public boolean isInstantCommunicationModeEnabled(); diff --git a/wifi/api/system-current.txt b/wifi/api/system-current.txt index fa99da786ae5..edbd46300191 100644 --- a/wifi/api/system-current.txt +++ b/wifi/api/system-current.txt @@ -428,8 +428,11 @@ package android.net.wifi { method public double getSuccessfulRxPacketsPerSecond(); method public double getSuccessfulTxPacketsPerSecond(); method public boolean isEphemeral(); + method public boolean isOemPaid(); + method public boolean isOemPrivate(); method public boolean isOsuAp(); method public boolean isPasspointAp(); + method public boolean isTrusted(); method @Nullable public static String sanitizeSsid(@Nullable String); field public static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00"; field public static final int INVALID_RSSI = -127; // 0xffffff81 @@ -618,11 +621,13 @@ package android.net.wifi { public final class WifiNetworkSuggestion implements android.os.Parcelable { method @NonNull public android.net.wifi.WifiConfiguration getWifiConfiguration(); method public boolean isOemPaid(); + method public boolean isOemPrivate(); } public static final class WifiNetworkSuggestion.Builder { method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING) public android.net.wifi.WifiNetworkSuggestion.Builder setCarrierId(int); method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setOemPaid(boolean); + method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setOemPrivate(boolean); } public class WifiScanner { diff --git a/wifi/jarjar-rules.txt b/wifi/jarjar-rules.txt index b0ff4bb27e70..ff06a180b8c1 100644 --- a/wifi/jarjar-rules.txt +++ b/wifi/jarjar-rules.txt @@ -36,7 +36,7 @@ rule android.net.ipmemorystore.IOnStatusListener* com.android.wifi.x.@0 rule android.net.ipmemorystore.NetworkAttributesParcelable* com.android.wifi.x.@0 rule android.net.ipmemorystore.SameL3NetworkResponseParcelable* com.android.wifi.x.@0 rule android.net.ipmemorystore.StatusParcelable* com.android.wifi.x.@0 -rule android.net.networkstack.aidl.quirks.IPv6ProvisioningLossQuirk* com.android.wifi.x.@0 +rule android.net.networkstack.aidl.** com.android.wifi.x.@0 # Net utils (includes Network Stack helper classes). rule android.net.DhcpResults* com.android.wifi.x.@0 diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index 9ca64d2ae2ef..8103ff717ef3 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -1011,6 +1011,17 @@ public class WifiConfiguration implements Parcelable { */ public boolean oemPaid; + + /** + * Indicate whether the network is oem private or not. Networks are considered oem private + * if the corresponding connection is only available to system apps. + * + * This bit can only be used by suggestion network, see + * {@link WifiNetworkSuggestion.Builder#setOemPrivate(boolean)} + * @hide + */ + public boolean oemPrivate; + /** * True if this Wifi configuration is created from a {@link WifiNetworkSuggestion}, * false otherwise. @@ -2249,6 +2260,7 @@ public class WifiConfiguration implements Parcelable { osu = false; trusted = true; // Networks are considered trusted by default. oemPaid = false; + oemPrivate = false; fromWifiNetworkSuggestion = false; fromWifiNetworkSpecifier = false; meteredHint = false; @@ -2372,13 +2384,14 @@ public class WifiConfiguration implements Parcelable { if (this.osu) sbuf.append(" osu"); if (this.trusted) sbuf.append(" trusted"); if (this.oemPaid) sbuf.append(" oemPaid"); + if (this.oemPrivate) sbuf.append(" oemPrivate"); if (this.fromWifiNetworkSuggestion) sbuf.append(" fromWifiNetworkSuggestion"); if (this.fromWifiNetworkSpecifier) sbuf.append(" fromWifiNetworkSpecifier"); if (this.meteredHint) sbuf.append(" meteredHint"); if (this.useExternalScores) sbuf.append(" useExternalScores"); if (this.validatedInternetAccess || this.ephemeral || this.trusted || this.oemPaid - || this.fromWifiNetworkSuggestion || this.fromWifiNetworkSpecifier - || this.meteredHint || this.useExternalScores) { + || this.oemPrivate || this.fromWifiNetworkSuggestion + || this.fromWifiNetworkSpecifier || this.meteredHint || this.useExternalScores) { sbuf.append("\n"); } if (this.meteredOverride != METERED_OVERRIDE_NONE) { @@ -2943,6 +2956,7 @@ public class WifiConfiguration implements Parcelable { osu = source.osu; trusted = source.trusted; oemPaid = source.oemPaid; + oemPrivate = source.oemPrivate; fromWifiNetworkSuggestion = source.fromWifiNetworkSuggestion; fromWifiNetworkSpecifier = source.fromWifiNetworkSpecifier; meteredHint = source.meteredHint; @@ -3024,6 +3038,7 @@ public class WifiConfiguration implements Parcelable { dest.writeInt(ephemeral ? 1 : 0); dest.writeInt(trusted ? 1 : 0); dest.writeInt(oemPaid ? 1 : 0); + dest.writeInt(oemPrivate ? 1 : 0); dest.writeInt(fromWifiNetworkSuggestion ? 1 : 0); dest.writeInt(fromWifiNetworkSpecifier ? 1 : 0); dest.writeInt(meteredHint ? 1 : 0); @@ -3102,6 +3117,7 @@ public class WifiConfiguration implements Parcelable { config.ephemeral = in.readInt() != 0; config.trusted = in.readInt() != 0; config.oemPaid = in.readInt() != 0; + config.oemPrivate = in.readInt() != 0; config.fromWifiNetworkSuggestion = in.readInt() != 0; config.fromWifiNetworkSpecifier = in.readInt() != 0; config.meteredHint = in.readInt() != 0; diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java index fe5002eb8854..774c043136e7 100644 --- a/wifi/java/android/net/wifi/WifiInfo.java +++ b/wifi/java/android/net/wifi/WifiInfo.java @@ -164,6 +164,11 @@ public class WifiInfo implements Parcelable { private boolean mOemPaid; /** + * Whether the network is oem private or not. + */ + private boolean mOemPrivate; + + /** * OSU (Online Sign Up) AP for Passpoint R2. */ private boolean mOsuAp; @@ -327,6 +332,9 @@ public class WifiInfo implements Parcelable { setFrequency(-1); setMeteredHint(false); setEphemeral(false); + setTrusted(false); + setOemPaid(false); + setOemPrivate(false); setOsuAp(false); setRequestingPackageName(null); setFQDN(null); @@ -363,7 +371,8 @@ public class WifiInfo implements Parcelable { mMeteredHint = source.mMeteredHint; mEphemeral = source.mEphemeral; mTrusted = source.mTrusted; - mTrusted = source.mOemPaid; + mOemPaid = source.mOemPaid; + mOemPrivate = source.mOemPrivate; mRequestingPackageName = source.mRequestingPackageName; mOsuAp = source.mOsuAp; @@ -722,7 +731,12 @@ public class WifiInfo implements Parcelable { mTrusted = trusted; } - /** {@hide} */ + /** + * Returns true if the current Wifi network is a trusted network, false otherwise. + * @see WifiNetworkSuggestion.Builder#setUntrusted(boolean). + * {@hide} + */ + @SystemApi public boolean isTrusted() { return mTrusted; } @@ -732,12 +746,32 @@ public class WifiInfo implements Parcelable { mOemPaid = oemPaid; } - /** {@hide} */ + /** + * Returns true if the current Wifi network is an oem paid network, false otherwise. + * @see WifiNetworkSuggestion.Builder#setOemPaid(boolean). + * {@hide} + */ + @SystemApi public boolean isOemPaid() { return mOemPaid; } /** {@hide} */ + public void setOemPrivate(boolean oemPrivate) { + mOemPrivate = oemPrivate; + } + + /** + * Returns true if the current Wifi network is an oem private network, false otherwise. + * @see WifiNetworkSuggestion.Builder#setOemPrivate(boolean). + * {@hide} + */ + @SystemApi + public boolean isOemPrivate() { + return mOemPrivate; + } + + /** {@hide} */ public void setOsuAp(boolean osuAp) { mOsuAp = osuAp; } @@ -975,6 +1009,7 @@ public class WifiInfo implements Parcelable { dest.writeInt(mEphemeral ? 1 : 0); dest.writeInt(mTrusted ? 1 : 0); dest.writeInt(mOemPaid ? 1 : 0); + dest.writeInt(mOemPrivate ? 1 : 0); dest.writeInt(score); dest.writeLong(txSuccess); dest.writeDouble(mSuccessfulTxPacketsPerSecond); @@ -1021,6 +1056,7 @@ public class WifiInfo implements Parcelable { info.mEphemeral = in.readInt() != 0; info.mTrusted = in.readInt() != 0; info.mOemPaid = in.readInt() != 0; + info.mOemPrivate = in.readInt() != 0; info.score = in.readInt(); info.txSuccess = in.readLong(); info.mSuccessfulTxPacketsPerSecond = in.readDouble(); diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java index acae218b74e0..dc6ec907ab95 100644 --- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java +++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java @@ -25,6 +25,7 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.net.MacAddress; import android.net.NetworkCapabilities; +import android.net.NetworkRequest; import android.net.wifi.hotspot2.PasspointConfiguration; import android.os.Parcel; import android.os.Parcelable; @@ -180,6 +181,12 @@ public final class WifiNetworkSuggestion implements Parcelable { private boolean mIsNetworkOemPaid; /** + * Whether this network will be brought up as OEM private (OEM_PRIVATE capability bit + * added). + */ + private boolean mIsNetworkOemPrivate; + + /** * Whether this network will use enhanced MAC randomization. */ private boolean mIsEnhancedMacRandomizationEnabled; @@ -206,6 +213,7 @@ public final class WifiNetworkSuggestion implements Parcelable { mWapiEnterpriseConfig = null; mIsNetworkUntrusted = false; mIsNetworkOemPaid = false; + mIsNetworkOemPrivate = false; mPriorityGroup = 0; mIsEnhancedMacRandomizationEnabled = false; mSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; @@ -667,6 +675,9 @@ public final class WifiNetworkSuggestion implements Parcelable { * reduce it). The connectivity service may use this information to influence the overall * network configuration of the device. * <p> + * <li> These suggestions are only considered for network selection if a + * {@link NetworkRequest} without {@link NetworkCapabilities#NET_CAPABILITY_TRUSTED} + * capability is filed. * <li> An untrusted network's credentials may not be shared with the user using * {@link #setCredentialSharedWithUser(boolean)}.</li> * <li> If not set, defaults to false (i.e. network is trusted).</li> @@ -688,7 +699,7 @@ public final class WifiNetworkSuggestion implements Parcelable { * <li>The connectivity service may use this information to influence the overall * network configuration of the device. This network is typically only available to system * apps. - * <li>On devices which support only 1 concurrent connection (indicated via + * <li>On devices which do not support concurrent connection (indicated via * {@link WifiManager#isMultiStaConcurrencySupported()}, Wi-Fi network selection process may * use this information to influence priority of the suggested network for Wi-Fi network * selection (most likely to reduce it). @@ -699,6 +710,13 @@ public final class WifiNetworkSuggestion implements Parcelable { * <p> * <li> An OEM paid network's credentials may not be shared with the user using * {@link #setCredentialSharedWithUser(boolean)}.</li> + * <li> These suggestions are only considered for network selection if a + * {@link NetworkRequest} with {@link NetworkCapabilities#NET_CAPABILITY_OEM_PAID} + * capability is filed. + * <li> Each suggestion can have both {@link #setOemPaid(boolean)} and + * {@link #setOemPrivate(boolean)} set if the app wants these suggestions considered + * for creating either an OEM paid network or OEM private network determined based on + * the {@link NetworkRequest} that is active. * <li> If not set, defaults to false (i.e. network is not OEM paid).</li> * * @param isOemPaid Boolean indicating whether the network should be brought up as OEM paid @@ -715,6 +733,48 @@ public final class WifiNetworkSuggestion implements Parcelable { return this; } + /** + * Specifies whether the system will bring up the network (if selected) as OEM private. An + * OEM private network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PRIVATE} capability + * added. + * Note: + * <li>The connectivity service may use this information to influence the overall + * network configuration of the device. This network is typically only available to system + * apps. + * <li>On devices which do not support concurrent connection (indicated via + * {@link WifiManager#isMultiStaConcurrencySupported()}, Wi-Fi network selection process may + * use this information to influence priority of the suggested network for Wi-Fi network + * selection (most likely to reduce it). + * <li>On devices which support more than 1 concurrent connections (indicated via + * {@link WifiManager#isMultiStaConcurrencySupported()}, these OEM private networks will be + * brought up as a secondary concurrent connection (primary connection will be used + * for networks available to the user and all apps. + * <p> + * <li> An OEM private network's credentials may not be shared with the user using + * {@link #setCredentialSharedWithUser(boolean)}.</li> + * <li> These suggestions are only considered for network selection if a + * {@link NetworkRequest} with {@link NetworkCapabilities#NET_CAPABILITY_OEM_PRIVATE} + * capability is filed. + * <li> Each suggestion can have both {@link #setOemPaid(boolean)} and + * {@link #setOemPrivate(boolean)} set if the app wants these suggestions considered + * for creating either an OEM paid network or OEM private network determined based on + * the {@link NetworkRequest} that is active. + * <li> If not set, defaults to false (i.e. network is not OEM private).</li> + * + * @param isOemPrivate Boolean indicating whether the network should be brought up as OEM + * private (if true) or not OEM private (if false). + * @return Instance of {@link Builder} to enable chaining of the builder method. + * @hide + */ + @SystemApi + public @NonNull Builder setOemPrivate(boolean isOemPrivate) { + if (!SdkLevel.isAtLeastS()) { + throw new UnsupportedOperationException(); + } + mIsNetworkOemPrivate = isOemPrivate; + return this; + } + private void setSecurityParamsInWifiConfiguration( @NonNull WifiConfiguration configuration) { if (!TextUtils.isEmpty(mWpa2PskPassphrase)) { // WPA-PSK network. @@ -786,6 +846,7 @@ public final class WifiNetworkSuggestion implements Parcelable { wifiConfiguration.carrierId = mCarrierId; wifiConfiguration.trusted = !mIsNetworkUntrusted; wifiConfiguration.oemPaid = mIsNetworkOemPaid; + wifiConfiguration.oemPrivate = mIsNetworkOemPrivate; wifiConfiguration.macRandomizationSetting = mIsEnhancedMacRandomizationEnabled ? WifiConfiguration.RANDOMIZATION_ENHANCED : WifiConfiguration.RANDOMIZATION_PERSISTENT; @@ -819,6 +880,7 @@ public final class WifiNetworkSuggestion implements Parcelable { wifiConfiguration.meteredOverride = mMeteredOverride; wifiConfiguration.trusted = !mIsNetworkUntrusted; wifiConfiguration.oemPaid = mIsNetworkOemPaid; + wifiConfiguration.oemPrivate = mIsNetworkOemPrivate; wifiConfiguration.subscriptionId = mSubscriptionId; mPasspointConfiguration.setCarrierId(mCarrierId); mPasspointConfiguration.setSubscriptionId(mSubscriptionId); @@ -938,6 +1000,14 @@ public final class WifiNetworkSuggestion implements Parcelable { } mIsSharedWithUser = false; } + if (mIsNetworkOemPrivate) { + if (mIsSharedWithUserSet && mIsSharedWithUser) { + throw new IllegalStateException("Should not be both" + + "setCredentialSharedWithUser and +" + + "setOemPrivate to true"); + } + mIsSharedWithUser = false; + } return new WifiNetworkSuggestion( wifiConfiguration, mPasspointConfiguration, @@ -1105,6 +1175,7 @@ public final class WifiNetworkSuggestion implements Parcelable { .append(", isInitialAutoJoinEnabled=").append(isInitialAutoJoinEnabled) .append(", isUnTrusted=").append(!wifiConfiguration.trusted) .append(", isOemPaid=").append(wifiConfiguration.oemPaid) + .append(", isOemPrivate=").append(wifiConfiguration.oemPrivate) .append(", priorityGroup=").append(priorityGroup) .append(" ]"); return sb.toString(); @@ -1212,6 +1283,18 @@ public final class WifiNetworkSuggestion implements Parcelable { } /** + * @see Builder#setOemPrivate(boolean) + * @hide + */ + @SystemApi + public boolean isOemPrivate() { + if (!SdkLevel.isAtLeastS()) { + throw new UnsupportedOperationException(); + } + return wifiConfiguration.oemPrivate; + } + + /** * Get the WifiEnterpriseConfig, or null if unset. * @see Builder#setWapiEnterpriseConfig(WifiEnterpriseConfig) * @see Builder#setWpa2EnterpriseConfig(WifiEnterpriseConfig) diff --git a/wifi/java/android/net/wifi/aware/AwareResources.java b/wifi/java/android/net/wifi/aware/AwareResources.java new file mode 100644 index 000000000000..cee1f40c05cd --- /dev/null +++ b/wifi/java/android/net/wifi/aware/AwareResources.java @@ -0,0 +1,146 @@ +/* + * 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.wifi.aware; + +import android.annotation.NonNull; +import android.os.Handler; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * The resources of the Aware service. + */ +public final class AwareResources implements Parcelable { + /** + * Number of the NDPs are available. + */ + private int mNumOfAvailableNdps; + + /** + * Number of the publish sessions are available. + */ + private int mNumOfAvailablePublishSessions; + + /** + * Number of the subscribe sessions are available. + */ + private int mNumOfAvailableSubscribeSessions; + + /** + * @hide : should not be created by apps + */ + public AwareResources() { + } + + /** + * Return the number of Aware data-paths (also known as NDPs - NAN Data Paths) which an app + * could create. Please refer to the {@link WifiAwareNetworkSpecifier} to create + * a Network Specifier and request a data-path. + * <p> + * Note that these resources aren't reserved - other apps could use them by the time you + * attempt to create a data-path. + * </p> + * @return A Non-negative integer, number of data-paths that could be created. + */ + public int getNumOfAvailableDataPaths() { + return mNumOfAvailableNdps; + } + + /** + * Return the number of Aware publish sessions which an app could create. Please refer to the + * {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback, Handler)} + * to create a publish session. + * <p> + * Note that these resources aren't reserved - other apps could use them by the time you + * attempt to create a publish session. + * </p> + * @return A Non-negative integer, number of publish sessions that could be created. + */ + public int getNumOfAvailablePublishSessions() { + return mNumOfAvailablePublishSessions; + } + + /** + * Return the number of Aware subscribe sessions which an app could create. Please refer to the + * {@link WifiAwareSession#subscribe(SubscribeConfig, DiscoverySessionCallback, Handler)} + * to create a publish session. + * <p> + * Note that these resources aren't reserved - other apps could use them by the time you + * attempt to create a subscribe session. + * </p> + * @return A Non-negative integer, number of subscribe sessions that could be created. + */ + public int getNumOfAvailableSubscribeSessions() { + return mNumOfAvailableSubscribeSessions; + } + + /** + * Set the number of the available NDPs. + * @hide + * @param numOfAvailableNdps Number of available NDPs. + */ + public void setNumOfAvailableDataPaths(int numOfAvailableNdps) { + mNumOfAvailableNdps = numOfAvailableNdps; + } + + /** + * Set the number of the available publish sessions. + * @hide + * @param numOfAvailablePublishSessions Number of available publish sessions. + */ + public void setNumOfAvailablePublishSessions(int numOfAvailablePublishSessions) { + mNumOfAvailablePublishSessions = numOfAvailablePublishSessions; + } + + /** + * Set the number of the available subscribe sessions. + * @hide + * @param numOfAvailableSubscribeSessions Number of available subscribe sessions. + */ + public void setNumOfAvailableSubscribeSessions(int numOfAvailableSubscribeSessions) { + mNumOfAvailableSubscribeSessions = numOfAvailableSubscribeSessions; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mNumOfAvailableNdps); + dest.writeInt(mNumOfAvailablePublishSessions); + dest.writeInt(mNumOfAvailableSubscribeSessions); + } + + public static final @android.annotation.NonNull Creator<AwareResources> CREATOR = + new Creator<AwareResources>() { + @Override + public AwareResources createFromParcel(Parcel in) { + AwareResources awareResources = new AwareResources(); + awareResources.setNumOfAvailableDataPaths(in.readInt()); + awareResources.setNumOfAvailablePublishSessions(in.readInt()); + awareResources.setNumOfAvailableSubscribeSessions(in.readInt()); + return awareResources; + } + + @Override + public AwareResources[] newArray(int size) { + return new AwareResources[size]; + } + }; +} diff --git a/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl b/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl index cd2ca692137d..c90c4d8a27b2 100644 --- a/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl +++ b/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl @@ -25,6 +25,7 @@ import android.net.wifi.aware.IWifiAwareMacAddressProvider; import android.net.wifi.aware.PublishConfig; import android.net.wifi.aware.SubscribeConfig; import android.net.wifi.aware.Characteristics; +import android.net.wifi.aware.AwareResources; /** * Interface that WifiAwareService implements @@ -36,6 +37,7 @@ interface IWifiAwareManager // Aware API boolean isUsageEnabled(); Characteristics getCharacteristics(); + AwareResources getAvailableAwareResources(); boolean isDeviceAttached(); void enableInstantCommunicationMode(in String callingPackage, boolean enable); boolean isInstantCommunicationModeEnabled(); diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java index 67c60322e47a..e19b095b27eb 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java @@ -263,7 +263,7 @@ public class WifiAwareManager { * * @return An object specifying configuration limitations of Aware. */ - public Characteristics getCharacteristics() { + public @Nullable Characteristics getCharacteristics() { try { return mService.getCharacteristics(); } catch (RemoteException e) { @@ -272,6 +272,23 @@ public class WifiAwareManager { } /** + * Return the available resources of the Wi-Fi aware service: a set of parameters which specify + * limitations on service usage, e.g the number of data-paths which could be created.. + * + * @return An object specifying the currently available resource of the Wi-Fi Aware service. + */ + public @Nullable AwareResources getAvailableAwareResources() { + if (!SdkLevel.isAtLeastS()) { + throw new UnsupportedOperationException(); + } + try { + return mService.getAvailableAwareResources(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Attach to the Wi-Fi Aware service - enabling the application to create discovery sessions or * create connections to peers. The device will attach to an existing cluster if it can find * one or create a new cluster (if it is the first to enable Aware in its vicinity). Results diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java index b82c67b658aa..f09c37d811f9 100644 --- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java +++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java @@ -69,6 +69,7 @@ public class WifiConfigurationTest { config.setPasspointManagementObjectTree(cookie); config.trusted = false; config.oemPaid = true; + config.oemPrivate = true; config.updateIdentifier = "1234"; config.fromWifiNetworkSpecifier = true; config.fromWifiNetworkSuggestion = true; @@ -91,8 +92,10 @@ public class WifiConfigurationTest { assertEquals(macBeforeParcel, reconfig.getRandomizedMacAddress()); assertEquals(config.updateIdentifier, reconfig.updateIdentifier); assertFalse(reconfig.trusted); - assertTrue(config.fromWifiNetworkSpecifier); - assertTrue(config.fromWifiNetworkSuggestion); + assertTrue(reconfig.fromWifiNetworkSpecifier); + assertTrue(reconfig.fromWifiNetworkSuggestion); + assertTrue(reconfig.oemPaid); + assertTrue(reconfig.oemPrivate); Parcel parcelWW = Parcel.obtain(); reconfig.writeToParcel(parcelWW, 0); @@ -103,6 +106,32 @@ public class WifiConfigurationTest { } @Test + public void testWifiConfigurationCopyConstructor() { + WifiConfiguration config = new WifiConfiguration(); + config.trusted = false; + config.oemPaid = true; + config.oemPrivate = true; + config.updateIdentifier = "1234"; + config.fromWifiNetworkSpecifier = true; + config.fromWifiNetworkSuggestion = true; + config.setRandomizedMacAddress(MacAddressUtils.createRandomUnicastAddress()); + MacAddress macBeforeParcel = config.getRandomizedMacAddress(); + config.subscriptionId = 1; + config.carrierId = 1189; + + WifiConfiguration reconfig = new WifiConfiguration(config); + + // lacking a useful config.equals, check two fields near the end. + assertEquals(macBeforeParcel, reconfig.getRandomizedMacAddress()); + assertEquals(config.updateIdentifier, reconfig.updateIdentifier); + assertFalse(reconfig.trusted); + assertTrue(reconfig.fromWifiNetworkSpecifier); + assertTrue(reconfig.fromWifiNetworkSuggestion); + assertTrue(reconfig.oemPaid); + assertTrue(reconfig.oemPrivate); + } + + @Test public void testIsOpenNetwork_IsOpen_NullWepKeys() { WifiConfiguration config = new WifiConfiguration(); config.allowedKeyManagement.clear(); diff --git a/wifi/tests/src/android/net/wifi/WifiInfoTest.java b/wifi/tests/src/android/net/wifi/WifiInfoTest.java index 06ae13a21e38..c6faf66140e2 100644 --- a/wifi/tests/src/android/net/wifi/WifiInfoTest.java +++ b/wifi/tests/src/android/net/wifi/WifiInfoTest.java @@ -17,6 +17,7 @@ package android.net.wifi; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertTrue; @@ -62,6 +63,7 @@ public class WifiInfoTest { writeWifiInfo.rxSuccess = TEST_RX_SUCCESS; writeWifiInfo.setTrusted(true); writeWifiInfo.setOemPaid(true); + writeWifiInfo.setOemPrivate(true); writeWifiInfo.setOsuAp(true); writeWifiInfo.setFQDN(TEST_FQDN); writeWifiInfo.setProviderFriendlyName(TEST_PROVIDER_NAME); @@ -83,6 +85,46 @@ public class WifiInfoTest { assertEquals(TEST_RX_SUCCESS, readWifiInfo.rxSuccess); assertTrue(readWifiInfo.isTrusted()); assertTrue(readWifiInfo.isOemPaid()); + assertTrue(readWifiInfo.isOemPrivate()); + assertTrue(readWifiInfo.isOsuAp()); + assertTrue(readWifiInfo.isPasspointAp()); + assertEquals(TEST_PACKAGE_NAME, readWifiInfo.getRequestingPackageName()); + assertEquals(TEST_FQDN, readWifiInfo.getPasspointFqdn()); + assertEquals(TEST_PROVIDER_NAME, readWifiInfo.getPasspointProviderFriendlyName()); + assertEquals(TEST_WIFI_STANDARD, readWifiInfo.getWifiStandard()); + assertEquals(TEST_MAX_SUPPORTED_TX_LINK_SPEED_MBPS, + readWifiInfo.getMaxSupportedTxLinkSpeedMbps()); + assertEquals(TEST_MAX_SUPPORTED_RX_LINK_SPEED_MBPS, + readWifiInfo.getMaxSupportedRxLinkSpeedMbps()); + } + + @Test + public void testWifiInfoCopyConstructor() throws Exception { + WifiInfo writeWifiInfo = new WifiInfo(); + writeWifiInfo.txSuccess = TEST_TX_SUCCESS; + writeWifiInfo.txRetries = TEST_TX_RETRIES; + writeWifiInfo.txBad = TEST_TX_BAD; + writeWifiInfo.rxSuccess = TEST_RX_SUCCESS; + writeWifiInfo.setTrusted(true); + writeWifiInfo.setOemPaid(true); + writeWifiInfo.setOemPrivate(true); + writeWifiInfo.setOsuAp(true); + writeWifiInfo.setFQDN(TEST_FQDN); + writeWifiInfo.setProviderFriendlyName(TEST_PROVIDER_NAME); + writeWifiInfo.setRequestingPackageName(TEST_PACKAGE_NAME); + writeWifiInfo.setWifiStandard(TEST_WIFI_STANDARD); + writeWifiInfo.setMaxSupportedTxLinkSpeedMbps(TEST_MAX_SUPPORTED_TX_LINK_SPEED_MBPS); + writeWifiInfo.setMaxSupportedRxLinkSpeedMbps(TEST_MAX_SUPPORTED_RX_LINK_SPEED_MBPS); + + WifiInfo readWifiInfo = new WifiInfo(writeWifiInfo); + + assertEquals(TEST_TX_SUCCESS, readWifiInfo.txSuccess); + assertEquals(TEST_TX_RETRIES, readWifiInfo.txRetries); + assertEquals(TEST_TX_BAD, readWifiInfo.txBad); + assertEquals(TEST_RX_SUCCESS, readWifiInfo.rxSuccess); + assertTrue(readWifiInfo.isTrusted()); + assertTrue(readWifiInfo.isOemPaid()); + assertTrue(readWifiInfo.isOemPrivate()); assertTrue(readWifiInfo.isOsuAp()); assertTrue(readWifiInfo.isPasspointAp()); assertEquals(TEST_PACKAGE_NAME, readWifiInfo.getRequestingPackageName()); @@ -110,6 +152,8 @@ public class WifiInfoTest { assertEquals(WifiManager.UNKNOWN_SSID, wifiInfo.getSSID()); assertEquals(null, wifiInfo.getBSSID()); assertEquals(-1, wifiInfo.getNetworkId()); + assertFalse(wifiInfo.isOemPaid()); + assertFalse(wifiInfo.isOemPrivate()); } /** diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java index 56e79983817f..870ff0a26d58 100644 --- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java +++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java @@ -223,6 +223,34 @@ public class WifiNetworkSuggestionTest { /** * Validate correctness of WifiNetworkSuggestion object created by + * {@link WifiNetworkSuggestion.Builder#build()} for OWE network. + */ + @Test + public void testWifiNetworkSuggestionBuilderForOemPrivateEnhancedOpenNetworkWithBssid() { + assumeTrue(SdkLevel.isAtLeastS()); + + WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder() + .setSsid(TEST_SSID) + .setBssid(MacAddress.fromString(TEST_BSSID)) + .setOemPrivate(true) + .setIsEnhancedOpen(true) + .build(); + + assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID); + assertEquals(TEST_BSSID, suggestion.wifiConfiguration.BSSID); + assertTrue(suggestion.wifiConfiguration.allowedKeyManagement + .get(WifiConfiguration.KeyMgmt.OWE)); + assertNull(suggestion.wifiConfiguration.preSharedKey); + assertTrue(suggestion.wifiConfiguration.requirePmf); + assertTrue(suggestion.wifiConfiguration.oemPrivate); + assertTrue(suggestion.isOemPrivate()); + assertFalse(suggestion.isUserAllowedToManuallyConnect); + assertTrue(suggestion.isInitialAutoJoinEnabled); + assertNull(suggestion.getEnterpriseConfig()); + } + + /** + * Validate correctness of WifiNetworkSuggestion object created by * {@link WifiNetworkSuggestion.Builder#build()} for SAE network. */ @Test @@ -1285,6 +1313,41 @@ public class WifiNetworkSuggestionTest { } /** + * Validate {@link WifiNetworkSuggestion.Builder#setCredentialSharedWithUser(boolean)} set the + * correct value to the WifiConfiguration. + */ + @Test + public void testSetIsNetworkAsOemPrivate() { + assumeTrue(SdkLevel.isAtLeastS()); + + WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder() + .setSsid(TEST_SSID) + .setWpa2Passphrase(TEST_PRESHARED_KEY) + .setOemPrivate(true) + .build(); + assertTrue(suggestion.isOemPrivate()); + assertFalse(suggestion.isUserAllowedToManuallyConnect); + } + + /** + * Validate {@link WifiNetworkSuggestion.Builder#setCredentialSharedWithUser(boolean)} set the + * correct value to the WifiConfiguration. + * Also the {@link WifiNetworkSuggestion#isUserAllowedToManuallyConnect} should be false; + */ + @Test + public void testSetIsNetworkAsOemPrivateOnPasspointNetwork() { + assumeTrue(SdkLevel.isAtLeastS()); + + PasspointConfiguration passpointConfiguration = PasspointTestUtils.createConfig(); + WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder() + .setPasspointConfig(passpointConfiguration) + .setOemPrivate(true) + .build(); + assertTrue(suggestion.isOemPrivate()); + assertFalse(suggestion.isUserAllowedToManuallyConnect); + } + + /** * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception * when set {@link WifiNetworkSuggestion.Builder#setUntrusted(boolean)} to true and * set {@link WifiNetworkSuggestion.Builder#setCredentialSharedWithUser(boolean)} to true @@ -1320,6 +1383,24 @@ public class WifiNetworkSuggestionTest { /** * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception + * when set {@link WifiNetworkSuggestion.Builder#setOemPrivate(boolean)} to true and + * set {@link WifiNetworkSuggestion.Builder#setCredentialSharedWithUser(boolean)} to true + * together. + */ + @Test(expected = IllegalStateException.class) + public void testSetCredentialSharedWithUserWithSetIsNetworkAsOemPrivate() { + assumeTrue(SdkLevel.isAtLeastS()); + + new WifiNetworkSuggestion.Builder() + .setSsid(TEST_SSID) + .setWpa2Passphrase(TEST_PRESHARED_KEY) + .setCredentialSharedWithUser(true) + .setOemPrivate(true) + .build(); + } + + /** + * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception * when set both {@link WifiNetworkSuggestion.Builder#setIsInitialAutojoinEnabled(boolean)} * and {@link WifiNetworkSuggestion.Builder#setCredentialSharedWithUser(boolean)} (boolean)} * to false on a passpoint suggestion. diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java index d0d0c57008fc..1ecd32555bfe 100644 --- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java +++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java @@ -155,6 +155,7 @@ public class WifiAwareManagerTest { */ @Test public void testIsAttached() throws Exception { + assumeTrue(SdkLevel.isAtLeastS()); mDut.isDeviceAttached(); verify(mockAwareService).isDeviceAttached(); } @@ -172,6 +173,16 @@ public class WifiAwareManagerTest { verify(mockAwareService).enableInstantCommunicationMode(anyString(), eq(true)); } + /** + * Validate pass-through of getAvailableAwareResources() API. + */ + @Test + public void testGetAvailableAwareResource() throws Exception { + assumeTrue(SdkLevel.isAtLeastS()); + mDut.getAvailableAwareResources(); + verify(mockAwareService).getAvailableAwareResources(); + } + /* * WifiAwareEventCallbackProxy Tests */ |