Merge "Add Dvbc Frontend Bandwidth Settings"
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchEmail.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchEmail.java
index 5f2fabe..beb9ad3 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 @@
*
* <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 @@
}
/**
- * 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 @@
}
/**
- * 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 @@
}
/**
- * 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 @@
}
/**
- * 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 @@
}
/**
- * 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 @@
}
/**
- * 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 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 @@
}
/**
- * 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 90e4df6..3933726 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 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 @@
* @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 @@
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 @@
}
/** 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 @@
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 @@
* 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 @@
/** 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 @@
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 @@
* 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 @@
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 9fe2c67..48d3ac0 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 java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Set;
/**
@@ -65,20 +66,14 @@
/** 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 @@
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 @@
@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 @@
}
/**
- * 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 @@
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 @@
/**
* 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 @@
/**
* 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 @@
*
* @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 @@
}
/**
- * 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 @@
}
/**
- * 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 @@
}
/**
- * 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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 3c0e746..e1e0eda 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 @@
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 @@
/** 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 7e97542..1f90bc1 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 @@
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 @@
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 @@
}
/** 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 a047041..486857f 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 @@
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 @@
/** 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 758280b..99cb2f1 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 @@
@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 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 @@
}
/**
- * 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 @@
* 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 c871905..15acf10 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 @@
*/
// 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 @@
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 @@
* @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 @@
* @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 @@
* 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 @@
/**
* 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 @@
* <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");
- mBundle.putStringArray(NAMESPACE_FIELD, namespaces);
+ 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");
+ mNamespaces.addAll(namespaces);
return this;
}
@@ -224,7 +300,7 @@
/** 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 @@
* <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 @@
}
/**
- * 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 @@
* {@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 @@
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 b2e9d46..f2c8156 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.NonNull;
-import android.util.ArraySet;
+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 @@
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 d490469..15d0992 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 @@
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 7cd6ee2..f2830e5 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 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.SearchSpecProto;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -193,7 +194,12 @@
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 60f7005..2871eb6 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.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
similarity index 99%
rename from apex/appsearch/service/java/com/android/server/appsearch/external/localbackend/AppSearchImpl.java
rename to apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
index 642378d..b1a79f8 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
similarity index 69%
rename from apex/appsearch/service/java/com/android/server/appsearch/external/localbackend/converter/GenericDocumentToProtoConverter.java
rename to apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverter.java
index fdeb90d..60684f0 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 @@
@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 @@
.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 @@
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
similarity index 73%
rename from apex/appsearch/service/java/com/android/server/appsearch/external/localbackend/converter/SchemaToProtoConverter.java
rename to apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverter.java
index ca0d2ee..403711f 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.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 @@
@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 @@
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 @@
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 @@
// 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
similarity index 79%
rename from apex/appsearch/service/java/com/android/server/appsearch/external/localbackend/converter/SearchResultToProtoConverter.java
rename to apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java
index 524c80d..9f7c696 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.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
similarity index 67%
rename from apex/appsearch/service/java/com/android/server/appsearch/external/localbackend/converter/SearchSpecToProtoConverter.java
rename to apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchSpecToProtoConverter.java
index a5d913a..14822dc 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.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 @@
@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 @@
@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 @@
}
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 0c6c4c2..0000000
--- 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 b4acf128..0000000
--- 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
deleted file mode 100644
index f37d3e4..0000000
--- a/apex/extservices/com.android.extservices.avbpubkey
+++ /dev/null
Binary files differ
diff --git a/apex/extservices/com.android.extservices.pem b/apex/extservices/com.android.extservices.pem
deleted file mode 100644
index 7bfbd34..0000000
--- 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
deleted file mode 100644
index 59585a2..0000000
--- a/apex/extservices/com.android.extservices.pk8
+++ /dev/null
Binary files differ
diff --git a/apex/extservices/com.android.extservices.x509.pem b/apex/extservices/com.android.extservices.x509.pem
deleted file mode 100644
index e0343b8..0000000
--- 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 88a4724..0000000
--- 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 23a50e3..0000000
--- 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 9ff7cc2..6459eb4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11718,10 +11718,9 @@
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 @@
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 @@
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 @@
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 720bf8c..3dd05af 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5725,7 +5725,7 @@
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 @@
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 @@
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 @@
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 785463a9..edc422d 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -290,6 +290,7 @@
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 @@
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 2da4a18..406086d 100644
--- a/cmds/statsd/src/anomaly/AlarmTracker.h
+++ b/cmds/statsd/src/anomaly/AlarmTracker.h
@@ -73,6 +73,7 @@
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 619752c..6aa410b 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -37,14 +37,6 @@
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 @@
VLOG("~AnomalyTracker() called");
}
+void AnomalyTracker::onConfigUpdated() {
+ mSubscriptions.clear();
+}
+
void AnomalyTracker::resetStorage() {
VLOG("resetStorage() called.");
mPastBuckets.clear();
@@ -259,6 +255,15 @@
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 bf36a3b..9a578ee 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 @@
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 @@
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 @@
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 686d8f9..4641914 100644
--- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
@@ -34,15 +34,15 @@
// 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 a379847..ac2a8e4 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -9754,6 +9754,7 @@
/**
* 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 @@
// 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 @@
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 b2c0b32..8869241 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -234,14 +234,26 @@
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 01198a9..5feb09f 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -55,6 +55,8 @@
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 @@
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 @@
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 @@
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 95a7d40..5b321a0 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -101,6 +101,7 @@
}
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 92c1a6e..0dc8eda 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -155,6 +155,7 @@
// 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 @@
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 @@
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 @@
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 ab0d286..d80f9db 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -209,6 +209,9 @@
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 @@
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 @@
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 657b2e4..cf1f437 100644
--- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
@@ -71,7 +71,7 @@
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 @@
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 @@
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 @@
// 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 @@
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 ee4e167..62f4982 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
@@ -30,7 +30,7 @@
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 @@
// 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 2891c6e..be2707c 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
@@ -29,12 +29,10 @@
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 @@
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 0d49bbc..247e2e0 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
@@ -28,7 +28,7 @@
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 @@
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 bd8017a..6eddee7 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
@@ -31,7 +31,7 @@
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 @@
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 335f775..6372361 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 @@
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 @@
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 @@
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 @@
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 @@
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 3f1c532..178a9d2 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 @@
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 @@
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 @@
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 8fc039a..4474df4 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 @@
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 @@
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);
+ optional<sp<AnomalyTracker>> anomalyTracker = createAnomalyTracker(
+ alert, anomalyAlarmMonitor, metricProducerMap, allMetricProducers);
+ if (!anomalyTracker) {
+ return false;
+ }
+ allAnomalyTrackers.push_back(anomalyTracker.value());
}
- 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());
- return false;
- }
- const int anomalyTrackerIndex = itr->second;
- allAnomalyTrackers[anomalyTrackerIndex]->addSubscription(subscription);
+ if (!initSubscribersForSubscriptionType(config, Subscription::ALERT, alertTrackerMap,
+ allAnomalyTrackers)) {
+ return false;
}
return true;
}
@@ -1146,24 +1143,9 @@
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 e4585cd..84e1e4e 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 @@
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 @@
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 4fa9bf6..66bab4e 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 {
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 @@
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 @@
tmpTrackerToConditionMap.clear();
tmpActivationAtomTrackerToMetricMap.clear();
tmpDeactivationAtomTrackerToMetricMap.clear();
- alertTrackerMap.clear();
+ oldAlertTrackerMap.clear();
metricsWithActivation.clear();
oldStateHashes.clear();
noReportMetricIds.clear();
@@ -111,7 +115,7 @@
oldConditionTrackers, oldConditionTrackerMap, oldMetricProducers, oldMetricProducerMap,
oldAnomalyTrackers, oldAlarmTrackers, tmpConditionToMetricMap, tmpTrackerToMetricMap,
tmpTrackerToConditionMap, tmpActivationAtomTrackerToMetricMap,
- tmpDeactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation,
+ tmpDeactivationAtomTrackerToMetricMap, oldAlertTrackerMap, metricsWithActivation,
oldStateHashes, noReportMetricIds);
}
@@ -188,6 +192,32 @@
}
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 @@
// 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 0d0a896..9e2350b 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 @@
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 16a5f5e..05b57af 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -11718,10 +11718,9 @@
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 @@
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 daa5414..18fdc0f 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -5665,7 +5665,7 @@
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 @@
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 45e9c49..43b7722c 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 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 @@
launchCookies.add(cookie);
}
+ /** @hide */
+ @TestApi
+ public boolean hasParentTask() {
+ return parentTaskId != INVALID_TASK_ID;
+ }
+
/**
* Reads the TaskInfo from a parcel.
*/
@@ -283,6 +298,7 @@
source.readBinderList(launchCookies);
letterboxActivityBounds = source.readTypedObject(Rect.CREATOR);
positionInParent = source.readTypedObject(Point.CREATOR);
+ parentTaskId = source.readInt();
}
/**
@@ -316,6 +332,7 @@
dest.writeBinderList(launchCookies);
dest.writeTypedObject(letterboxActivityBounds, flags);
dest.writeTypedObject(positionInParent, flags);
+ dest.writeInt(parentTaskId);
}
@Override
@@ -338,6 +355,7 @@
+ " 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 c854aba..587e883 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -20,7 +20,6 @@
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 @@
/**
* @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 9c21e8f..7e7710b 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 f24ed80..830cbe0 100644
--- a/core/java/android/content/pm/IOnAppsChangedListener.aidl
+++ b/core/java/android/content/pm/IOnAppsChangedListener.aidl
@@ -33,5 +33,5 @@
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 ead80d0..fd96e85 100644
--- a/core/java/android/content/pm/LauncherActivityInfo.java
+++ b/core/java/android/content/pm/LauncherActivityInfo.java
@@ -91,16 +91,9 @@
}
/**
- * @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 2909d66..c964b4b 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 @@
* @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 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 @@
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 @@
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 e65d7b5..9f322fb 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -419,6 +419,8 @@
*
* @see com.android.server.locksettings.LockSettingsService
*
+ * TODO(b/171335732): should take userId
+ *
* @hide
*/
@RequiresPermission(MANAGE_BIOMETRIC)
@@ -426,7 +428,7 @@
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 @@
/**
* 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 b85b6f7..490c95b 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -32,7 +32,7 @@
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 @@
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 d2c74e9..4afe4b3 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -766,6 +766,26 @@
}
/**
+ * 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 @@
try {
mService.setUdfpsOverlayController(controller);
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ throw e.rethrowFromSystemServer();
}
}
@@ -795,7 +815,7 @@
try {
mService.onPointerDown(sensorId, x, y, minor, major);
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ throw e.rethrowFromSystemServer();
}
}
@@ -812,7 +832,7 @@
try {
mService.onPointerUp(sensorId);
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ throw e.rethrowFromSystemServer();
}
}
@@ -885,9 +905,8 @@
}
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 547de9d..5b14ef7 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -100,6 +100,9 @@
// 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 bb2357e..3d1755e 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -213,8 +213,7 @@
ic,
info,
moreArgs.argi1 == 1 /* restarting */,
- startInputToken,
- moreArgs.argi2 == 1 /* shouldPreRenderIme */);
+ startInputToken);
args.recycle();
moreArgs.recycle();
return;
@@ -340,14 +339,13 @@
@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 d290465..32a8c0a 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -19,7 +19,6 @@
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.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 @@
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 @@
@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 @@
+ " 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 @@
+ " 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 @@
* applied by {@link #updateInputViewShown()}.
*/
public boolean isInputViewShown() {
- return mCanPreRender ? mWindowVisible : mIsInputViewShown && mDecorViewVisible;
+ return mDecorViewVisible;
}
/**
@@ -2151,10 +2125,9 @@
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 @@
// 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 @@
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 @@
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 void hideWindow() {
if (DEBUG) Log.v(TAG, "CALL: hideWindow");
- mIsPreRendered = false;
mWindowVisible = false;
finishViews(false /* finishingInput */);
if (mDecorViewVisible) {
@@ -2384,32 +2327,6 @@
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 @@
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 @@
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 @@
}
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 780c4fa..cc3d92d 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9758,6 +9758,14 @@
"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 e4ba87c..f08756a 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -218,6 +218,7 @@
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 @@
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 dd1a194..5780d4f 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 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 @@
* @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 @@
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 @@
}
}
- 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 9ea4c93..d37edaa 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -135,6 +135,8 @@
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 @@
}
/**
+ * 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 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 14ba699..0e8cd54 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -187,6 +187,7 @@
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 @@
private ScrollCaptureConnection mScrollCaptureConnection;
+ private final BackgroundBlurDrawable.Aggregator mBlurRegionAggregator =
+ new BackgroundBlurDrawable.Aggregator(this);
+
/**
* @return {@link ImeFocusController} for this instance.
*/
@@ -3819,6 +3823,8 @@
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 @@
.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 @@
}
}
+ /**
+ * 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 f44ab3a..de4554b 100644
--- a/core/java/android/view/inputmethod/InputMethod.java
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -243,7 +243,7 @@
@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 1931174..6243c63 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -489,7 +489,6 @@
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 @@
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 @@
}
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 @@
}
@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 @@
// Hook 'em up and let 'er rip.
mCurrentTextBoxAttribute = tba;
- maybeCallServedViewChangedLocked(tba);
+
mServedConnecting = false;
if (mServedInputConnectionWrapper != null) {
mServedInputConnectionWrapper.deactivate();
@@ -3141,12 +3114,6 @@
}
}
- 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 c98477e..15463cb 100644
--- a/core/java/com/android/internal/BrightnessSynchronizer.java
+++ b/core/java/com/android/internal/BrightnessSynchronizer.java
@@ -22,6 +22,7 @@
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 @@
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 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 3e26679..1a93f1b 100644
--- a/core/java/com/android/internal/app/ChooserFlags.java
+++ b/core/java/com/android/internal/app/ChooserFlags.java
@@ -33,7 +33,7 @@
*/
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 a2af4d6..777534e 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 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 0000000..6ea9e66
--- /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 9a22686..f0e26cf 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 @@
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 9b1299e..d6730e8 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.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 @@
}
/**
- * 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 40e4f4d..c336373 100644
--- a/core/java/com/android/internal/view/IInputMethod.aidl
+++ b/core/java/com/android/internal/view/IInputMethod.aidl
@@ -45,7 +45,7 @@
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 c9443b0..1145f51 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 @@
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 ce8b599..832c066 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -256,11 +256,13 @@
}
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 @@
}
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 17ced9f..f1ec85a 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 @@
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 @@
(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 3b4ebb5..e5d1713 100644
--- a/core/proto/android/inputmethodservice/inputmethodservice.proto
+++ b/core/proto/android/inputmethodservice/inputmethodservice.proto
@@ -39,8 +39,8 @@
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 5bee81b..1b9aff9 100644
--- a/core/proto/android/view/imeinsetssourceconsumer.proto
+++ b/core/proto/android/view/imeinsetssourceconsumer.proto
@@ -28,6 +28,6 @@
*/
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 ffb9603..bf66e69 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 d0fceb0..393f229b 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 a3b8f64..f7f6214 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 82a27a8..53c92af 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 db5603c..e39d46d 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 b5fd7b2..915e158 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 7eff3d7..544be54e 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 e4a4e20..a294c9d 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 ac2d4b5..2f2bef8 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 @@
// 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 1f2c12b..9c29943 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 @@
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 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 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 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 @@
.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 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 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 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 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/SearchResultsTest.java b/core/tests/coretests/src/android/app/appsearch/external/app/SearchResultsTest.java
deleted file mode 100644
index acbf11a..0000000
--- a/core/tests/coretests/src/android/app/appsearch/external/app/SearchResultsTest.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch;
-
-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());
- }
-}
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 0000000..d4635fd
--- /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 2c7c35f..d56d0c3 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 @@
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 a5b7c61..db838e8 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.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.mockito.Mockito;
import org.mockito.Spy;
-import java.util.ArrayList;
-
/**
* Test {@link InsetsSourceConsumer} with IME type.
*
@@ -133,50 +128,4 @@
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
similarity index 98%
rename from core/tests/coretests/src/android/widget/TextViewOnReceiveContentCallbackTest.java
rename to core/tests/coretests/src/android/widget/TextViewOnReceiveContentTest.java
index ef659af6..8efd3b4 100644
--- a/core/tests/coretests/src/android/widget/TextViewOnReceiveContentCallbackTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewOnReceiveContentTest.java
@@ -63,12 +63,12 @@
/**
* 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 8f5982c..7abcfdc 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -49,18 +49,38 @@
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 @@
/** 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 @@
pw.close();
return bao.toByteArray();
}
+
/**
* Convert objects from PEM format, which is used for
* CA_CERTIFICATE and USER_CERTIFICATE entries.
@@ -167,7 +194,8 @@
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 d5b34c4..1c1c2ee 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 @@
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 @@
mSerialNumber = serialNumber;
mStartDate = startDate;
mEndDate = endDate;
- mFlags = flags;
}
/**
@@ -229,7 +226,7 @@
* @hide
*/
public int getFlags() {
- return mFlags;
+ return 0;
}
/**
@@ -243,9 +240,15 @@
* 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 @@
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 @@
* 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 @@
mSerialNumber,
mStartDate,
mEndDate,
- mFlags);
+ 0);
}
}
}
diff --git a/keystore/java/android/security/KeyStoreParameter.java b/keystore/java/android/security/KeyStoreParameter.java
index 66c87ed..51d29b1 100644
--- a/keystore/java/android/security/KeyStoreParameter.java
+++ b/keystore/java/android/security/KeyStoreParameter.java
@@ -48,18 +48,16 @@
*/
@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 @@
* 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 @@
*/
@Deprecated
public final static class Builder {
- private int mFlags;
/**
* Creates a new instance of the {@code Builder} with the given
@@ -126,14 +130,15 @@
* 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 @@
*/
@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 1d85e9f..b87a642 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 d4ff275..51ddb17 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 @@
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 d0ab31d..fc523aef 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 @@
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 @@
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 9240b3f..9247c68 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.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 @@
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 @@
/** 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 @@
mPipTaskOrganizer.registerPipTransitionCallback(mPipTransitionCallback);
mTemporaryBoundsPhysicsAnimator.setCustomAnimationHandler(
mSfAnimationHandlerThreadLocal.get());
+ reloadResources();
mResizePipUpdateListener = (target, values) -> {
if (!mTemporaryBounds.isEmpty()) {
@@ -198,6 +201,11 @@
};
}
+ void reloadResources() {
+ mStashOffset = mContext.getResources()
+ .getDimensionPixelSize(R.dimen.pip_stash_offset);
+ }
+
@NonNull
@Override
public Rect getFloatingBoundsOnScreen() {
@@ -414,9 +422,10 @@
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 @@
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 ef38755..f3d8c7b 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 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 @@
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 @@
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 @@
}
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 e95e4a0..d820e77 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 @@
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 @@
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 @@
}
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 @@
}
}
+ 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 @@
// 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 @@
}
if (touchState.startedDragging()) {
+ mPipBoundsState.setStashed(false);
mSavedSnapFraction = -1f;
mPipDismissTargetHandler.showDismissTargetMaybe();
}
@@ -785,12 +789,13 @@
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 @@
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 69d428a..8b616e8 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 @@
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 191a317..f709fed 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.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 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 @@
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 @@
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 @@
@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 @@
@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 @@
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 35a2293c..e4155a2 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 @@
}
@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 79b8611..610bffe 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 @@
* @hide
*/
@UnsupportedAppUsage
+ @TestApi
protected Image() {
}
@@ -387,6 +389,7 @@
* @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 9fc3a23..dd386b0 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 @@
* @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 2c3fe6a..d85e60d 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 @@
* @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 7de0035..b190a7f 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 88de33f..db014ae 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 dfa71e2..0a44fbb 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 e3fc67c..66729347 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 f108e06..c5876af 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.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.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 @@
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 @@
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 1829d34..1b300358 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 7fcc40d..a8a7b00 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 be705c3..44a6503 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 14eead9..e93ad9b 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 d1f0a4b..ad3d3e7 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 ea23a28..0107047 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 7eef297..5a52f73 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 9176676..194bf2d 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 38ef649..43886b3 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 84ba540..342230b2 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 787e496..e9e4d35 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 3dfb23f..6ae71c6 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 20005e7..10b798c 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 3f000ea..82459b2 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 4d830dd..ef02906 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 d728631..6f3f887 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 d728631..6f3f887 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 d728631..6f3f887 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 d728631..6f3f887 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 6ac3763..2e83672 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 9ec8196..aeb65be 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 cd9db07..0c3ae53 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 64968b60..ab20a04 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 7c4a67d..1863778 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 7533e71..5b0b218 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 948c333..b4315e7 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 6e2f235..973efef 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 67f7997..5422e8e 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 8ea6d1c..e24f495a 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 aec1804..6c2e673 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 efedbe8..13dc9e8 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 50ceaa1..3318d20 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 94afa3b..208ab3b 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 b0cd740..4dcc72e 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 44b4aee..2fa4f11 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 048d1bc..ef7484c 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 f70b381..c8fa41b 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 aff7c82..d9bf983 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 46c0930..2082d91 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 f841a59..e57de2c 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 d367b61..da10e9c 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 56a3716..7bb5980 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 b4063df..f41f2ef 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 24ac924..bca9e07 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 a4387e7..d2ad56a 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 f17ca16..a732aa4 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 8128eb7..b25c62a 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 cfe7a08..4ca6ace 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 21215aa..52a52a5 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 951a0b9..2504069 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 d0965d0..fe93f65 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 268e1d3..5f27af0 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 bba8b97..797152c 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 b2488ec..3ee85b2 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 36e3d69..88087e5 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 ee92678..da98fee 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 2b9fa41..5120c90 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 e0c8470..878947e 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 c5f7a3d..2695aaf 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 bc7d5fe..33592c8 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 31a9bb4..43bd021 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 d917c6a..dc29a65 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 31a9bb4..43bd021 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 c211318..c9d391a 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 bf94c99..cba9a71 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 e6a6ea2..7aab6e9 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 99390cf..61c176f 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 3ffd741..0be1248 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 704b512..43a5f7b 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 5e4540a..a5ba656 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 546ffdd..99e6752 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 53414d5..8af9ad3 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 e0aaaf7..bbe8c4e 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 d497630..4a9433e7 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 786324f..5b81a03 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 df39f7b..d6c2f15 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 1446f96..a98526e 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 9a44d97..6526787 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 48dddbe..f5e2b74 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 3f0227c..3c347e2 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 18c051c..a93d29e 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 b41d4e2..c27718e 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 c830dae..656c2af 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 e43c0f2..a6f9b56 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 4a48444..0cf79ba 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 97ff5ef..97e3559 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 541dd878..7e7710b 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 f3241ea..7e7710b 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
-# 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
+include platform/frameworks/base/services/backup:/OWNERS
+
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index baa266a..2412a32 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -229,6 +229,7 @@
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 3714db3..939c5f9 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 2e845fb..0e6bc24 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.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 @@
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 @@
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 @@
mRingerModeTracker = ringerModeTracker;
mStatusBarStateController = statusBarStateController;
mLockPatternUtils = lockPatternUtils;
+ mAuthController = authController;
dumpManager.registerDumpable(getClass().getName(), this);
mHandler = new Handler(mainLooper) {
@@ -1853,7 +1857,7 @@
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 d8e94bb..b30103e 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -188,7 +188,7 @@
* 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 64a2aca..e40185c 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.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 @@
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 @@
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 @@
}
void onConfigurationChanged(int configDiff) {
- if ((configDiff & ActivityInfo.CONFIG_DENSITY) == 0) {
+ if ((configDiff & ActivityInfo.CONFIG_DENSITY) != 0) {
+ applyResourcesValues();
+ mImageView.setImageResource(getIconResId(mMagnificationMode));
return;
}
- applyResourcesValues();
- mImageView.setImageResource(getIconResId(mMagnificationMode));
+ if ((configDiff & ActivityInfo.CONFIG_LOCALE) != 0) {
+ updateAccessibilityWindowTitle();
+ return;
+ }
+ }
+
+ private void updateAccessibilityWindowTitle() {
+ mParams.accessibilityTitle = getAccessibilityWindowTitle(mContext);
+ if (mIsVisible) {
+ mWindowManager.updateViewLayout(mImageView, mParams);
+ }
}
private void toggleMagnificationMode() {
@@ -261,14 +273,19 @@
: 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 e9e453b..98424be 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 @@
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 340ca04..fd89baa 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 @@
}
} 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 @@
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 @@
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 @@
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 @@
}
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 874c73b..c72bc25 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.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.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 @@
}
/**
+ * @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 @@
/**
* 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 3c2e008..a4b407d 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.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 @@
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 @@
* 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 @@
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 0ed3bda..7edcf66 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 @@
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 8220835..f07e5af 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 @@
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 c581e85..58e49f8 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 @@
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 @@
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 @@
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 1beb875..5eb6687 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 @@
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 6f6ee4c..c6ed9c0 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 @@
// 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 18cc746..f9982d0 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 @@
&& (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 @@
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 @@
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 5cee5bd..2a2a0b1 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 @@
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 ef4108b..bd22893 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 @@
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 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 77ae059..5e883be 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.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 @@
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 @@
@Nullable DockManager dockManager,
KeyguardStateController keyguardStateController,
@Main Resources resources,
- HeadsUpManagerPhone headsUpManagerPhone) {
+ HeadsUpManagerPhone headsUpManagerPhone,
+ AuthController authController) {
mLockscreenGestureLogger = lockscreenGestureLogger;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockPatternUtils = lockPatternUtils;
@@ -337,6 +342,7 @@
mKeyguardStateController = keyguardStateController;
mResources = resources;
mHeadsUpManagerPhone = headsUpManagerPhone;
+ mAuthController = authController;
mKeyguardIndicationController.setLockIconController(this);
}
@@ -502,6 +508,11 @@
* @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 b185f48..e9a7132 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.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 @@
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 @@
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 @@
mLockscreenUserManager = notificationLockscreenUserManager;
mEntryManager = notificationEntryManager;
mConversationNotificationManager = conversationNotificationManager;
+ mAuthController = authController;
mView.setBackgroundColor(Color.TRANSPARENT);
OnAttachStateChangeListener onAttachStateChangeListener = new OnAttachStateChangeListener();
@@ -868,7 +872,8 @@
- 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 @@
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 e6479dd..caab2ab 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.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 @@
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 @@
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 @@
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 c923515..a0ae35f 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 @@
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 f1606c5..a39bc70 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.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 @@
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 @@
assertEquals(Surface.ROTATION_90, mWindowMagnificationController.mRotation);
}
-
@Test
public void onDensityChanged_enabled_updateDimensionsAndResetWindowMagnification() {
mInstrumentation.runOnMainSync(() -> {
@@ -310,4 +309,41 @@
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 0186d73..42bb005 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 @@
@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 a95396c..82ffd46 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 @@
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 @@
// 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 @@
// 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 6d87cc3..4bbba56 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 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 2042fab..83ef87a 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 @@
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 06d0331..72a0258 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 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 @@
private Resources mResources;
@Mock
private HeadsUpManagerPhone mHeadsUpManagerPhone;
+ @Mock
+ private AuthController mAuthController;
private LockscreenLockIconController mLockIconController;
private OnAttachStateChangeListener mOnAttachStateChangeListener;
@@ -89,13 +92,14 @@
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 cb56f1f..3b123f6 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.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 @@
private KeyguardStatusViewController mKeyguardStatusViewController;
@Mock
private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
+ @Mock
+ private AuthController mAuthController;
private NotificationPanelViewController mNotificationPanelViewController;
private View.AccessibilityDelegate mAccessibiltyDelegate;
@@ -201,6 +204,7 @@
@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 @@
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 0000000..3e9c962
--- /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 7c7e742..3c5268c 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 f7998ee..15f8c53 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.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 @@
* 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 @@
@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 @@
@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 @@
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 @@
return mDaemon;
}
- @LockoutTracker.LockoutMode int getLockoutModeForUser(int userId) {
+ @Override
+ public boolean containsSensor(int sensorId) {
+ return mSensorId == sensorId;
+ }
+
+ @Override
+ @NonNull
+ public List<FaceSensorPropertiesInternal> getSensorProperties() {
+ final List<FaceSensorPropertiesInternal> properties = new ArrayList<>();
+ properties.add(mSensorProperties);
+ return properties;
+ }
+
+ @Override
+ @NonNull
+ public List<Face> getEnrolledFaces(int sensorId, int userId) {
+ return FaceUtils.getInstance().getBiometricsForUser(mContext, userId);
+ }
+
+ @Override
+ @LockoutTracker.LockoutMode
+ public int getLockoutModeForUser(int sensorId, int userId) {
return mLockoutTracker.getLockoutModeForUser(userId);
}
- 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
+ public long getAuthenticatorId(int sensorId, int userId) {
+ return mAuthenticatorIds.get(userId);
}
- /**
- * 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;
- }
- }
- });
- }
-
- 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);
- });
- }
-
- 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);
- });
- }
-
- 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 @@
* 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 @@
});
}
- 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 @@
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 @@
});
}
- 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 @@
});
}
- 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 @@
});
}
- 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 @@
});
}
+
+ @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 @@
});
}
- 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 @@
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 83f10c8..a298e19 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.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 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 @@
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 @@
@Override // Binder call
public List<FaceSensorPropertiesInternal> getSensorPropertiesInternal(
String opPackageName) {
- Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+ Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
- final List<FaceSensorPropertiesInternal> properties = new ArrayList<>();
-
- 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 @@
}
@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 @@
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 @@
@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 @@
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 @@
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 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 @@
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 @@
@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 @@
@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 @@
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 @@
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 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 @@
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 0000000..e3fb750
--- /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 c88247f..265ba05 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 @@
}
@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 a806e3f..8c766d6 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 @@
@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 88867fc..a4ae9c8 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.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.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 @@
// 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 @@
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 @@
return;
}
notifySwitchWithRetries(RETRY_TIMES);
+ notifyDeviceStateWithRetries(RETRY_TIMES);
}
@Override
@@ -218,12 +241,55 @@
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 @@
}
}
+ @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 @@
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 @@
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 bc3bff1..ff31931 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 @@
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 @@
* 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 e4f52f1..77d5411 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 @@
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 6a3e7b7..b10cd12 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 @@
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 @@
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 @@
recordStableDisplayStatsIfNeededLocked(display);
recordTopInsetLocked(display);
}
+ addDisplayPowerControllerLocked(displayId);
DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
@@ -990,6 +1020,7 @@
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 @@
mPersistentDataStore.saveIfNeeded();
}
if (userId == mCurrentUserId) {
- mDisplayPowerController.setBrightnessConfiguration(c);
+ mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY).setBrightnessConfiguration(c);
}
}
}
@@ -1143,7 +1174,8 @@
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 @@
}
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 @@
+ ", 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 @@
}
}
+ 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 @@
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 @@
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 @@
BrightnessConfiguration config =
mPersistentDataStore.getBrightnessConfiguration(userSerial);
if (config == null) {
- config = mDisplayPowerController.getDefaultBrightnessConfiguration();
+ config = mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY)
+ .getDefaultBrightnessConfiguration();
}
return config;
}
@@ -2269,7 +2329,8 @@
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 @@
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 @@
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 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 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 @@
@Override
public void persistBrightnessTrackerState() {
synchronized (mSyncRoot) {
- mDisplayPowerController.persistBrightnessTrackerState();
+ mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY)
+ .persistBrightnessTrackerState();
}
}
@@ -2584,7 +2635,8 @@
@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 0211876..309271c 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 @@
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 16a4b72..b532fa1 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 @@
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 @@
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 @@
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 @@
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 @@
}
@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 @@
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 @@
}
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 @@
@ShellCommandResult
private int refreshDebugProperties() {
DebugFlags.FLAG_OPTIMIZE_START_INPUT.refresh();
- DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.refresh();
return ShellCommandResult.SUCCESS;
}
@@ -5822,12 +5779,6 @@
@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 76cd9ce..9145eca 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.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 @@
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 @@
/**
* Creates a primitive integer array given a Collection<Integer>.
+ *
* @param collection the collection to iterate
* @return the primitive integer array
*/
@@ -200,10 +208,25 @@
*/
/* 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 f25c651..f8d1195 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 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.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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
permissionLevel);
synchronized (mLock) {
- Preconditions.checkState(mStarted);
+ Preconditions.checkState(mState != STATE_STOPPED);
final long identity = Binder.clearCallingIdentity();
try {
putRegistration(pendingIntent, registration);
@@ -1551,7 +1574,7 @@
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 @@
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 @@
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 @@
private void onLocationEnabledChanged(int userId) {
synchronized (mLock) {
+ if (mState == STATE_STOPPED) {
+ return;
+ }
+
onEnabledChanged(userId);
}
}
@@ -2105,7 +2136,7 @@
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 e25e605..0c1e91d 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 @@
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 b679c0f..dd33865 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 @@
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 cdd347b..b3f49ad 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 @@
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 @@
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 void writePermissionSettings(int[] userIds, boolean async) {
synchronized (mLock) {
for (int userId : userIds) {
- mSettings.writeRuntimePermissionsForUserLPr(userId, !async);
+ writeRuntimePermissionsForUserLPrTEMP(userId, !async);
}
}
}
@@ -26401,6 +26401,17 @@
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 c121e6b..4e8ddac 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 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 @@
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 6d987ae..84f9823 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 @@
}
/** 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 @@
private PermissionControllerManager mPermissionControllerManager;
/** Map of OneTimePermissionUserManagers keyed by userId */
+ @GuardedBy("mLock")
+ @NonNull
private final SparseArray<OneTimePermissionUserManager> mOneTimePermissionUserManagers =
new SparseArray<>();
@@ -252,12 +254,14 @@
/** 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 @@
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 @@
@GuardedBy("mLock")
private CheckPermissionDelegate mCheckPermissionDelegate;
- @GuardedBy("mLock")
+ @NonNull
private final OnPermissionChangeListeners mOnPermissionChangeListeners;
@GuardedBy("mLock")
@@ -309,7 +306,7 @@
// 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 @@
}
};
- 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 @@
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 @@
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 @@
* 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 @@
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 @@
}
}
- @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 @@
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 @@
}
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 @@
}
synchronized (mLock) {
return PackageInfoUtils.generatePermissionGroupInfo(
- mRegistry.getPermissionGroupLocked(groupName), flags);
+ mRegistry.getPermissionGroup(groupName), flags);
}
}
@@ -554,7 +539,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
synchronized (mLock) {
- if (mRegistry.getPermissionLocked(permName) == null) {
+ if (mRegistry.getPermission(permName) == null) {
return 0;
}
@@ -807,14 +791,16 @@
}
}
- 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 @@
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 @@
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 @@
}
if (isInstantApp) {
- return mRegistry.isPermissionInstant(permissionName);
+ final Permission permission = mRegistry.getPermission(permissionName);
+ return permission != null && permission.isInstant();
}
return true;
@@ -1031,6 +1019,7 @@
return PackageManager.PERMISSION_DENIED;
}
+ @GuardedBy("mLock")
private boolean checkSingleUidPermissionInternalLocked(int uid,
@NonNull String permissionName) {
ArraySet<String> permissions = mSystemPermissions.get(uid);
@@ -1096,9 +1085,7 @@
Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS,
"addOnPermissionsChangeListener");
- synchronized (mLock) {
- mOnPermissionChangeListeners.addListenerLocked(listener);
- }
+ mOnPermissionChangeListeners.addListener(listener);
}
@Override
@@ -1106,9 +1093,7 @@
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 @@
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 @@
throw new IllegalArgumentException("Unknown package: " + packageName);
}
- final Permission bp;
+ final boolean isSoftRestrictedPermission;
synchronized (mLock) {
- bp = mRegistry.getPermissionLocked(permName);
+ final Permission permission = mRegistry.getPermission(permName);
+ isSoftRestrictedPermission = permission != null && permission.isSoftRestricted();
}
- if (bp == null) {
- throw new IllegalArgumentException("Unknown permission: " + permName);
- }
+ final boolean mayGrantSoftRestrictedPermission = isSoftRestrictedPermission
+ && SoftRestrictedPermissionPolicy.forPermission(mContext,
+ pkg.toAppInfoWithoutState(), pkg, UserHandle.of(userId), permName)
+ .mayGrantPermission();
- if (!(bp.isRuntime() || bp.isDevelopment())) {
- throw new SecurityException("Permission " + permName + " requested by "
- + pkg.getPackageName() + " is not a changeable permission type");
- }
-
- // 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;
- }
-
- 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;
- }
-
+ 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);
+ }
+
+ 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");
+ }
+
final UidPermissionState uidState = getUidStateLocked(pkg, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName() + " and user "
@@ -1515,6 +1499,14 @@
+ " 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 @@
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 @@
}
}
- 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 @@
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 @@
}
}
- 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 @@
for (int i = 0; i < permissionCount; i++) {
final String permName = pkg.getRequestedPermissions().get(i);
- final Permission bp;
- synchronized (mLock) {
- bp = mRegistry.getPermissionLocked(permName);
- }
- if (bp == null) {
- continue;
- }
- if (bp.isRemoved()) {
- continue;
+ final boolean isRuntimePermission;
+ synchronized (mLock) {
+ final Permission permission = mRegistry.getPermission(permName);
+ if (permission == null) {
+ 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 @@
// 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 @@
false, delayingPermCallback);
// Below is only runtime permission handling.
- if (!bp.isRuntime()) {
+ if (!isRuntimePermission) {
continue;
}
@@ -2092,13 +2097,15 @@
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 @@
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 @@
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 @@
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 @@
}
}
}
- bp.setDefinitionChanged(false);
}
}
@@ -2400,13 +2406,15 @@
// 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 @@
}
}
- 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 @@
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 @@
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 @@
}
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 @@
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 @@
@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 @@
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 @@
// 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 @@
// 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 @@
*
* @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 @@
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 @@
* @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 @@
+ " for " + pkgName);
}
- ps.grantPermission(mRegistry.getPermissionLocked(newPerm));
+ ps.grantPermission(mRegistry.getPermission(newPerm));
}
// Add permission flags
@@ -3163,6 +3180,7 @@
*
* @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 @@
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 @@
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 @@
+ 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 @@
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);
+ 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 (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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
/**
- * 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 @@
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 @@
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 @@
}
});
}
- mRegistry.removePermissionLocked(bp.getName());
+ synchronized (mLock) {
+ mRegistry.removePermission(bp.getName());
+ }
continue;
}
final AndroidPackage sourcePkg =
@@ -4239,7 +4230,7 @@
}
Slog.w(TAG, "Removing dangling permission: " + bp.getName()
+ " from package " + bp.getPackageName());
- mRegistry.removePermissionLocked(bp.getName());
+ mRegistry.removePermission(bp.getName());
}
}
}
@@ -4307,7 +4298,7 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
});
}
+ @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 @@
permission.setGids(configPermission.getRawGids(),
configPermission.areGidsPerUser());
}
- mRegistry.addPermissionLocked(permission);
+ mRegistry.addPermission(permission);
} else {
- mRegistry.addPermissionTreeLocked(permission);
+ mRegistry.addPermissionTree(permission);
}
}
}
@@ -4787,7 +4774,7 @@
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 @@
private void transferPermissions(@NonNull String oldPackageName,
@NonNull String newPackageName) {
synchronized (mLock) {
- mRegistry.transferPermissionsLocked(oldPackageName, newPackageName);
+ mRegistry.transferPermissions(oldPackageName, newPackageName);
}
}
@@ -4822,7 +4809,7 @@
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 @@
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 @@
@Override
public Permission getPermissionTEMP(String permName) {
- synchronized (PermissionManagerService.this.mLock) {
- return mRegistry.getPermissionLocked(permName);
+ synchronized (mLock) {
+ return mRegistry.getPermission(permName);
}
}
@@ -5056,7 +5043,7 @@
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 @@
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 @@
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 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 36719203..0e3fda7 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.util.ArrayMap;
import android.util.ArraySet;
-import com.android.internal.annotations.GuardedBy;
-
import java.util.Collection;
/**
@@ -34,87 +32,62 @@
* 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 @@
}
}
- @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 @@
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 @@
*/
@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 f8e26fc..b007a75 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.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 @@
* 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 @@
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 @@
}
}
+ 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 @@
}
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 @@
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 06edd19..1a4a222 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 @@
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.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 @@
/** 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 @@
/** 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 @@
*/
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 @@
@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 @@
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 @@
}
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 @@
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 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 @@
/** 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 @@
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 @@
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 7433a3a..d3b1ac6 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 @@
// 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 @@
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 c51e63f..9273bf7 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.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 @@
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 @@
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 @@
// 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 084b766..c806c94 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 @@
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 @@
}
}, 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 51857dc..7d54ea9 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 @@
@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 @@
if (t == null) {
t = new WindowContainerTransaction();
}
- applyTransaction(t, null /*callback*/, transition);
+ applyTransaction(t, -1 /*syncId*/, transition);
return transition;
}
} finally {
@@ -148,10 +190,16 @@
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 @@
}
/**
- * @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;
-
- /**
- * 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);
+ 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;
}
- 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);
- }
+ // 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;
+ 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);
- }
+ // 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 ((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();
- }
- }
-
- if ((effects & TRANSACT_EFFECTS_CLIENT_CONFIG) == 0) {
- mService.addWindowLayoutReasons(LAYOUT_REASON_CONFIG_CHANGED);
- }
- } finally {
- mService.continueWindowLayout();
- if (syncId >= 0) {
- setSyncReady(syncId);
+ 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 ((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();
+ }
+ }
+
+ 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 4d553e2..3bfcb6d 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 @@
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 @@
@Override
public boolean hasDeviceOwner() {
- enforceDeviceOwnerOrManageUsers();
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || canManageUsers(caller));
return mOwners.hasDeviceOwner();
}
@@ -8355,32 +8356,6 @@
|| 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 @@
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 @@
@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 @@
@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 03edc58..267c9b7 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1266,6 +1266,12 @@
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 @@
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
similarity index 99%
rename from services/tests/servicestests/src/com/android/server/appsearch/external/localbackend/AppSearchImplTest.java
rename to services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
index 081bfb5..0d0ac6d 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
similarity index 86%
rename from services/tests/servicestests/src/com/android/server/appsearch/external/localbackend/converter/GenericDocumentToProtoConverterTest.java
rename to services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverterTest.java
index a95290d..85d4f01 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 @@
.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 @@
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
similarity index 96%
rename from services/tests/servicestests/src/com/android/server/appsearch/external/localbackend/converter/SchemaToProtoConverterTest.java
rename to services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverterTest.java
index 8b2fd1c..7336c3c 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 @@
.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 @@
).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 @@
.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 @@
).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
similarity index 98%
rename from services/tests/servicestests/src/com/android/server/appsearch/external/localbackend/converter/SnippetTest.java
rename to services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java
index e9357aa..d5762a1 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 @@
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 7a0d894..b73a783 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 @@
private Face10 mFace10;
private IBinder mBinder;
+ private static void waitForIdle() {
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
@@ -59,11 +63,8 @@
@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 be05245..9660d6b 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 @@
+ "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 @@
+ "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 b24bca8..350b390 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 @@
.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 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 @@
.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 3167820..fa3f45c 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 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.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 @@
private DpmMockContext mContext;
- @Override
- protected void setUp() throws Exception {
- super.setUp();
+ @Before
+ public void setUp() throws Exception {
mContext = getContext();
@@ -77,6 +84,7 @@
.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 @@
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 @@
dpms.getProfileOwnerAdminLocked(11).ensureUserRestrictions());
}
+ @Test
public void testMigration2_profileOwnerOnUser0() throws Exception {
setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_SYSTEM_USER_UID);
@@ -271,13 +280,13 @@
} 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 @@
}
// 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 @@
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 @@
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 @@
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 @@
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));
+ 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();
- 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());
+ assertWithMessage("Accounts with management disabled weren't migrated to PO parent")
+ .that(dpm.getParentProfileInstance(admin1)
+ .getAccountTypesWithManagementDisabled()).asList()
+ .containsExactly("com.google-primary");
- 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));
+ assertWithMessage("Accounts with management disabled for profile were lost")
+ .that(dpm.getAccountTypesWithManagementDisabled()).asList()
+ .containsExactly("com.google-profile");
- 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("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 @@
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 @@
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 c4f7b95..8d7bc16 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.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.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 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 @@
/**
* 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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
/**
* Caller doesn't have proper permissions.
*/
+ @Test
public void testSetActiveAdmin_SecurityException() {
// 1. Failure cases.
@@ -422,6 +424,7 @@
* {@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 @@
// 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 @@
// (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 @@
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 @@
// 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 @@
// 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 @@
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 @@
* {@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 @@
* {@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 @@
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 @@
* Test for:
* {@link DevicePolicyManager#removeActiveAdmin}
*/
+ @Test
public void testRemoveActiveAdmin_SecurityException() {
mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
@@ -604,9 +611,9 @@
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 @@
* {@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 @@
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 @@
/* 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 @@
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 @@
* 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 @@
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 @@
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 @@
* 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 @@
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 @@
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 @@
// 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 @@
// 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 @@
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 @@
* 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 @@
/* 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 @@
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 @@
*
* 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 @@
// 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 @@
* {@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 @@
* 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 @@
/**
* Test for: {@link DevicePolicyManager#setDeviceOwner} DO on system user installs successfully.
*/
+ @Test
public void testSetDeviceOwner() throws Exception {
setDeviceOwner();
@@ -944,7 +960,7 @@
// 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 @@
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 @@
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 @@
// 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 @@
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 @@
/**
* 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 @@
() -> 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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
eq(UserHandle.USER_SYSTEM), eq(true));
}
+ @Test
public void testProfileOwnerBackupActivateDeactivate() throws Exception {
setAsProfileOwner(admin1);
@@ -1250,6 +1271,7 @@
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 @@
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 @@
() -> dpm.clearDeviceOwnerApp(admin1.getPackageName()));
// DO shouldn't be removed.
- assertTrue(dpm.isDeviceManaged());
+ assertThat(dpm.isDeviceManaged()).isTrue();
}
/**
@@ -1294,6 +1316,7 @@
*
* 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 @@
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 @@
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 @@
});
}
+ @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 @@
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 @@
// 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 @@
* 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 @@
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 @@
// 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 @@
{
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 @@
return uid;
}
+ @Test
public void testCertificateDisclosure() throws Exception {
final int userId = CALLER_USER_HANDLE;
final UserHandle user = UserHandle.of(userId);
@@ -1571,7 +1602,8 @@
.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 @@
* 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 @@
// 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 @@
}
}
+ @Test
public void testApplicationRestrictionsManagingApp() throws Exception {
setAsProfileOwner(admin1);
@@ -1673,7 +1708,7 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
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 @@
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 @@
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 @@
);
}
+ @Test
public void testNoDefaultEnabledUserRestrictions() throws Exception {
mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
mContext.callerPermissions.add(permission.MANAGE_USERS);
@@ -2112,8 +2154,8 @@
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 @@
);
}
+ @Test
public void testSetFactoryResetProtectionPolicyWithDO() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -2156,6 +2199,7 @@
eq(android.Manifest.permission.MANAGE_FACTORY_RESET_PROTECTION));
}
+ @Test
public void testSetFactoryResetProtectionPolicyFailWithPO() throws Exception {
setupProfileOwner();
@@ -2167,6 +2211,7 @@
() -> dpm.setFactoryResetProtectionPolicy(admin1, policy));
}
+ @Test
public void testSetFactoryResetProtectionPolicyWithPOOfOrganizationOwnedDevice()
throws Exception {
setupProfileOwner();
@@ -2204,6 +2249,7 @@
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 @@
assertThat(actualAccounts).containsExactlyElementsIn(expectedAccounts);
}
+ @Test
public void testSetKeyguardDisabledFeaturesWithDO() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -2255,6 +2302,7 @@
DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA);
}
+ @Test
public void testSetKeyguardDisabledFeaturesWithPO() throws Exception {
setupProfileOwner();
@@ -2264,6 +2312,7 @@
DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT);
}
+ @Test
public void testSetKeyguardDisabledFeaturesWithPOOfOrganizationOwnedDevice()
throws Exception {
final int MANAGED_PROFILE_USER_ID = CALLER_USER_HANDLE;
@@ -2281,6 +2330,7 @@
DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA);
}
+ @Test
public void testSetApplicationHiddenWithDO() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -2304,6 +2354,7 @@
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 @@
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 @@
// 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 @@
() -> 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 @@
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 @@
// 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 @@
() -> 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 @@
// 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 @@
{
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 @@
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 @@
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 @@
() -> 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 @@
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 @@
clearDeviceOwner();
}
+ @Test
public void testCreateAdminSupportIntent() throws Exception {
// Setup device owner.
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
@@ -2604,11 +2666,11 @@
// 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 @@
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 @@
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 @@
* {@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 @@
// 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 @@
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 @@
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 @@
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 @@
DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
}
+ @Test
public void testSetUserProvisioningState_unprivileged() throws Exception {
setupProfileOwner();
assertExpectException(SecurityException.class, /* messageRegex =*/ null,
@@ -2771,6 +2840,7 @@
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 @@
/* 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 @@
DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
}
+ @Test
public void testSetUserProvisioningState_deviceOwnerFromSetupWizardAlternative()
throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
@@ -2800,6 +2873,7 @@
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 @@
DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
}
+ @Test
public void testSetUserProvisioningState_managedProfileFromSetupWizard_primaryUser()
throws Exception {
setupProfileOwner();
@@ -2817,6 +2892,7 @@
DevicePolicyManager.STATE_USER_PROFILE_FINALIZED);
}
+ @Test
public void testSetUserProvisioningState_managedProfileFromSetupWizard_managedProfile()
throws Exception {
setupProfileOwner();
@@ -2826,6 +2902,7 @@
DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
}
+ @Test
public void testSetUserProvisioningState_managedProfileWithoutSetupWizard() throws Exception {
setupProfileOwner();
@@ -2833,6 +2910,7 @@
DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
}
+ @Test
public void testSetUserProvisioningState_illegalTransitionOutOfFinalized1() throws Exception {
setupProfileOwner();
@@ -2843,6 +2921,7 @@
DevicePolicyManager.STATE_USER_UNMANAGED));
}
+ @Test
public void testSetUserProvisioningState_illegalTransitionToAnotherInProgressState()
throws Exception {
setupProfileOwner();
@@ -2858,10 +2937,11 @@
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 @@
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 @@
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 @@
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 @@
verifyStayOnWhilePluggedCleared(false);
}
+ @Test
public void testIsActiveSupervisionApp() throws Exception {
when(mServiceContext.resources
.getString(R.string.config_defaultSupervisionProfileOwnerComponent))
@@ -2968,11 +3050,12 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
}
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 @@
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 @@
false /* because of non-split user */);
}
+ @Test
public void testCheckProvisioningPreCondition_nonSplitUser_firstBoot_primaryUser()
throws Exception {
setup_nonSplitUser_firstBoot_primaryUser();
@@ -3275,8 +3367,8 @@
}
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 @@
true)).thenReturn(true);
}
+ @Test
public void testIsProvisioningAllowed_nonSplitUser_afterDeviceSetup_primaryUser()
throws Exception {
setup_nonSplitUser_afterDeviceSetup_primaryUser();
@@ -3318,6 +3411,7 @@
false/* because of non-split user */);
}
+ @Test
public void testCheckProvisioningPreCondition_nonSplitUser_afterDeviceSetup_primaryUser()
throws Exception {
setup_nonSplitUser_afterDeviceSetup_primaryUser();
@@ -3335,6 +3429,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
false/* because calling uid is system user */);
}
+ @Test
public void testCheckProvisioningPreCondition_splitUser_firstBoot_systemUser()
throws Exception {
setup_splitUser_firstBoot_systemUser();
@@ -3491,8 +3592,8 @@
}
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 @@
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 @@
false/* because calling uid is system user */);
}
+ @Test
public void testCheckProvisioningPreCondition_splitUser_afterDeviceSetup_systemUser()
throws Exception {
setup_splitUser_afterDeviceSetup_systemUser();
@@ -3535,8 +3638,8 @@
}
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 @@
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 @@
assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_USER, true);
}
+ @Test
public void testCheckProvisioningPreCondition_splitUser_firstBoot_primaryUser()
throws Exception {
setup_splitUser_firstBoot_primaryUser();
@@ -3575,8 +3680,8 @@
}
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 @@
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
}
+ @Test
public void testIsProvisioningAllowed_splitUser_afterDeviceSetup_primaryUser()
throws Exception {
setup_splitUser_afterDeviceSetup_primaryUser();
@@ -3601,6 +3707,7 @@
false/* because user setup completed */);
}
+ @Test
public void testCheckProvisioningPreCondition_splitUser_afterDeviceSetup_primaryUser()
throws Exception {
setup_splitUser_afterDeviceSetup_primaryUser();
@@ -3621,8 +3728,8 @@
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 @@
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
}
+ @Test
public void testIsProvisioningAllowed_provisionManagedProfileWithDeviceOwner_systemUser()
throws Exception {
setup_provisionManagedProfileWithDeviceOwner_systemUser();
@@ -3640,6 +3748,7 @@
false /* can't provision managed profile on system user */);
}
+ @Test
public void testCheckProvisioningPreCondition_provisionManagedProfileWithDeviceOwner_systemUser()
throws Exception {
setup_provisionManagedProfileWithDeviceOwner_systemUser();
@@ -3651,8 +3760,8 @@
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 @@
mContext.binder.callingUid = DpmMockContext.ANOTHER_UID;
}
+ @Test
public void testIsProvisioningAllowed_provisionManagedProfileWithDeviceOwner_primaryUser()
throws Exception {
setup_provisionManagedProfileWithDeviceOwner_primaryUser();
@@ -3671,6 +3781,7 @@
assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
}
+ @Test
public void testCheckProvisioningPreCondition_provisionManagedProfileWithDeviceOwner_primaryUser()
throws Exception {
setup_provisionManagedProfileWithDeviceOwner_primaryUser();
@@ -3684,8 +3795,8 @@
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 @@
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
}
+ @Test
public void testIsProvisioningAllowed_provisionManagedProfileCantRemoveUser_primaryUser()
throws Exception {
setup_provisionManagedProfileCantRemoveUser_primaryUser();
@@ -3708,6 +3820,7 @@
assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
}
+ @Test
public void testCheckProvisioningPreCondition_provisionManagedProfileCantRemoveUser_primaryUser()
throws Exception {
setup_provisionManagedProfileCantRemoveUser_primaryUser();
@@ -3716,6 +3829,7 @@
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 @@
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 @@
() -> 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 @@
// 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 @@
// 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 @@
});
}
+ @Test
public void testGetLastSecurityLogRetrievalTime() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -3806,7 +3925,7 @@
.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 @@
.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 @@
Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0);
}
+ @Test
public void testSetConfiguredNetworksLockdownStateWithPO() throws Exception {
setupProfileOwner();
assertExpectException(SecurityException.class, null,
@@ -3883,6 +4004,7 @@
Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0);
}
+ @Test
public void testSetConfiguredNetworksLockdownStateWithPOOfOrganizationOwnedDevice()
throws Exception {
setupProfileOwner();
@@ -3896,6 +4018,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 0);
}
+ @Test
public void testSetAutoTimeEnabledFailWithPONotOnUser0() throws Exception {
setupProfileOwner();
assertExpectException(SecurityException.class, null,
@@ -3945,6 +4073,7 @@
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 @@
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 @@
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 @@
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 @@
0);
}
+ @Test
public void testSetAutoTimeZoneEnabledWithPOOfOrganizationOwnedDevice() throws Exception {
setupProfileOwner();
configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
@@ -3995,12 +4128,13 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
.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 @@
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 @@
() -> 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 @@
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 @@
() -> 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 @@
.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 @@
() -> 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 @@
.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 @@
.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 @@
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 @@
.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 @@
// 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 @@
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 @@
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 @@
() -> dpm.wipeData(0));
}
+ @Test
public void testWipeDataDeviceOwner() throws Exception {
setDeviceOwner();
when(getServices().userManager.getUserRestrictionSource(
@@ -4527,6 +4687,7 @@
/*wipeEuicc=*/ eq(false));
}
+ @Test
public void testWipeEuiccDataEnabled() throws Exception {
setDeviceOwner();
when(getServices().userManager.getUserRestrictionSource(
@@ -4542,6 +4703,7 @@
/*wipeEuicc=*/ eq(true));
}
+ @Test
public void testWipeDataDeviceOwnerDisallowed() throws Exception {
setDeviceOwner();
when(getServices().userManager.getUserRestrictionSource(
@@ -4556,6 +4718,7 @@
() -> 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 @@
verifyZeroInteractions(getServices().recoverySystem);
}
+ @Test
public void testMaximumFailedPasswordAttemptsReachedManagedProfileDisallowed()
throws Exception {
final int MANAGED_PROFILE_USER_ID = 15;
@@ -4621,6 +4785,7 @@
verifyZeroInteractions(getServices().recoverySystem);
}
+ @Test
public void testMaximumFailedPasswordAttemptsReachedDeviceOwner() throws Exception {
setDeviceOwner();
when(getServices().userManager.getUserRestrictionSource(
@@ -4643,6 +4808,7 @@
/*wipeEuicc=*/ eq(false));
}
+ @Test
public void testMaximumFailedPasswordAttemptsReachedDeviceOwnerDisallowed() throws Exception {
setDeviceOwner();
when(getServices().userManager.getUserRestrictionSource(
@@ -4664,6 +4830,7 @@
.removeUserEvenWhenDisallowed(anyInt());
}
+ @Test
public void testMaximumFailedDevicePasswordAttemptsReachedOrgOwnedManagedProfile()
throws Exception {
final int MANAGED_PROFILE_USER_ID = 15;
@@ -4679,16 +4846,16 @@
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 @@
/*wipeEuicc=*/ eq(false));
}
+ @Test
public void testMaximumFailedProfilePasswordAttemptsReachedOrgOwnedManagedProfile()
throws Exception {
final int MANAGED_PROFILE_USER_ID = 15;
@@ -4724,14 +4892,15 @@
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 @@
/*wipeEuicc=*/ eq(false));
}
+ @Test
public void testGetPermissionGrantState() throws Exception {
final String permission = "some.permission";
final String app1 = "com.example.app1";
@@ -4766,10 +4936,10 @@
// 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 @@
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 @@
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 @@
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 @@
// 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 @@
.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 @@
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 @@
// 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 @@
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 @@
// 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 @@
// 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 @@
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 @@
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 @@
assertSetPermittedCrossProfileNotificationListenersUnavailable(mContext.binder.callingUid);
}
+ @Test
public void testSetPermittedCrossProfileNotificationListeners_unavailableForPoOnUser()
throws Exception {
// Set up a profile owner.
@@ -5141,23 +5317,24 @@
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 @@
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 @@
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 @@
++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 @@
++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 @@
verifyCanGetOwnerInstalledCaCerts(admin1, mAdmin1Context);
}
+ @Test
public void testGetOwnerInstalledCaCertsForProfileOwner() throws Exception {
mServiceContext.packageName = mRealTestContext.getPackageName();
mServiceContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
@@ -5340,6 +5521,7 @@
verifyCantGetOwnerInstalledCaCertsProfileOwnerRemoval(admin1, mAdmin1Context);
}
+ @Test
public void testGetOwnerInstalledCaCertsForDelegate() throws Exception {
mServiceContext.packageName = mRealTestContext.getPackageName();
mServiceContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
@@ -5359,6 +5541,7 @@
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 @@
verifyDataSharingChangedBroadcast();
}
+ @Test
public void testDisallowSharingIntoProfileClearRestriction() {
when(mServiceContext.resources.getString(R.string.config_managed_provisioning_package))
.thenReturn("com.android.managedprovisioning");
@@ -5383,6 +5567,7 @@
verifyDataSharingChangedBroadcast();
}
+ @Test
public void testDisallowSharingIntoProfileUnchanged() {
RestrictionsListener listener = new RestrictionsListener(mContext);
listener.onUserRestrictionsChanged(CALLER_USER_HANDLE, new Bundle(), new Bundle());
@@ -5399,6 +5584,7 @@
MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
}
+ @Test
public void testOverrideApnAPIsFailWithPO() throws Exception {
setupProfileOwner();
ApnSetting apn = (new ApnSetting.Builder())
@@ -5446,13 +5632,14 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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));
+ assertThat(getMockTransferMetadataManager().metadataFileExists()).isFalse();
+ assertThat(dpms.isDeviceOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();
+ assertThat(dpms.isAdminActive(admin1, UserHandle.USER_SYSTEM)).isTrue();
}
- // @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)
+ @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)
- // 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();
- // }
+ @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();
+ }
- public void testRevertDeviceOwnership_adminAndDeviceNotMigrated()
- throws Exception {
+ @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 @@
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));
+ assertThat(getMockTransferMetadataManager().metadataFileExists()).isFalse();
+ assertThat(dpms.isProfileOwner(admin1, CALLER_USER_HANDLE)).isTrue();
+ assertThat(dpms.isAdminActive(admin1, CALLER_USER_HANDLE)).isTrue();
}
- // @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)
+ @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)
- // 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();
- // }
+ @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 @@
assertProfileOwnershipRevertedWithFakeTransferMetadata();
}
+ @Test
public void testGrantDeviceIdsAccess_notToProfileOwner() throws Exception {
setupProfileOwner();
configureContextForAccess(mContext, false);
@@ -5674,6 +5872,7 @@
() -> dpm.markProfileOwnerOnOrganizationOwnedDevice(admin2));
}
+ @Test
public void testGrantDeviceIdsAccess_notByAuthorizedCaller() throws Exception {
setupProfileOwner();
configureContextForAccess(mContext, false);
@@ -5682,6 +5881,7 @@
() -> dpm.markProfileOwnerOnOrganizationOwnedDevice(admin1));
}
+ @Test
public void testGrantDeviceIdsAccess_byAuthorizedSystemCaller() throws Exception {
setupProfileOwner();
@@ -5700,6 +5900,7 @@
.thenReturn(UserHandle.SYSTEM);
}
+ @Test
public void testGrantDeviceIdsAccess_byAuthorizedManagedProvisioning() throws Exception {
setupProfileOwner();
@@ -5719,6 +5920,7 @@
}
}
+ @Test
public void testEnforceCallerCanRequestDeviceIdAttestation_deviceOwnerCaller()
throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
@@ -5741,6 +5943,7 @@
dpms.getCallerIdentity(admin2)));
}
+ @Test
public void testEnforceCallerCanRequestDeviceIdAttestation_profileOwnerCaller()
throws Exception {
configureContextForAccess(mContext, false);
@@ -5781,6 +5984,7 @@
}
}
+ @Test
public void testEnforceCallerCanRequestDeviceIdAttestation_delegateCaller() throws Exception {
setupProfileOwner();
markDelegatedCertInstallerAsInstalled();
@@ -5800,6 +6004,7 @@
dpms.getCallerIdentity(null, DpmMockContext.DELEGATE_PACKAGE_NAME)));
}
+ @Test
public void testEnforceCallerCanRequestDeviceIdAttestation_delegateCallerWithoutPermissions()
throws Exception {
setupProfileOwner();
@@ -5821,6 +6026,7 @@
});
}
+ @Test
public void testGetPasswordComplexity_securityExceptionNotThrownForParentInstance() {
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
when(getServices().packageManager.getPackagesForUid(DpmMockContext.CALLER_UID)).thenReturn(
@@ -5830,9 +6036,10 @@
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 @@
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 @@
}
+ @Test
public void testGetPasswordComplexity_currentUserNoPassword() {
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
when(getServices().packageManager.getPackagesForUid(DpmMockContext.CALLER_UID)).thenReturn(
@@ -5859,9 +6068,10 @@
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 @@
.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 @@
.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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
.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 @@
.thenReturn(packages);
}
+ @Test
public void testSetAccountTypesWithManagementDisabledOnManagedProfile() throws Exception {
setupProfileOwner();
@@ -6249,6 +6480,7 @@
assertThat(dpm.getAccountTypesWithManagementDisabled()).isEmpty();
}
+ @Test
public void testSetAccountTypesWithManagementDisabledOnOrgOwnedManagedProfile()
throws Exception {
final int managedProfileUserId = 15;
@@ -6284,6 +6516,7 @@
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
}
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 @@
// 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 @@
// 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 @@
}
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 @@
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 @@
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 41d54e9..81570a1 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.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 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 @@
mockSystemPropertiesToReturnDefault();
}
- @Override
- public DpmMockContext getContext() {
+ protected DpmMockContext getContext() {
return mMockContext;
}
@@ -136,20 +143,15 @@
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 @@
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 e8818a3..3aa5a80 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 @@
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 @@
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 @@
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 c698312..7506dd4 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 @@
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.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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
/**
* 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 @@
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 @@
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 a3cc915..24e226a 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_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.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.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 @@
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 @@
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 5899bb0..bfe183c 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 @@
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());
+ assertThat(owners.getDeviceOwnerFile().exists()).isFalse();
- 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();
- 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();
}
// Then re-read and check.
@@ -75,19 +82,20 @@
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 @@
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 @@
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 @@
owners.load();
// The legacy file should be removed.
- assertFalse(owners.getLegacyConfigFile().exists());
+ assertThat(owners.getLegacyConfigFile().exists()).isFalse();
- assertFalse(owners.getDeviceOwnerFile().exists());
+ assertThat(owners.getDeviceOwnerFile().exists()).isFalse();
- assertTrue(owners.getProfileOwnerFile(10).exists());
- assertTrue(owners.getProfileOwnerFile(11).exists());
- assertFalse(owners.getProfileOwnerFile(20).exists());
- assertFalse(owners.getProfileOwnerFile(21).exists());
+ assertThat(owners.getProfileOwnerFile(10).exists()).isTrue();
+ assertThat(owners.getProfileOwnerFile(11).exists()).isTrue();
+ assertThat(owners.getProfileOwnerFile(20).exists()).isFalse();
+ assertThat(owners.getProfileOwnerFile(21).exists()).isFalse();
- assertFalse(owners.hasDeviceOwner());
- assertEquals(UserHandle.USER_NULL, owners.getDeviceOwnerUserId());
- assertNull(owners.getSystemUpdatePolicy());
+ assertThat(owners.hasDeviceOwner()).isFalse();
+ assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
+ assertThat(owners.getSystemUpdatePolicy()).isNull();
- 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");
- 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();
}
// Then re-read and check.
@@ -196,27 +205,27 @@
final OwnersTestable owners = new OwnersTestable(getServices());
owners.load();
- assertFalse(owners.hasDeviceOwner());
- assertEquals(UserHandle.USER_NULL, owners.getDeviceOwnerUserId());
- assertNull(owners.getSystemUpdatePolicy());
+ assertThat(owners.hasDeviceOwner()).isFalse();
+ assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
+ assertThat(owners.getSystemUpdatePolicy()).isNull();
- 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");
- 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();
}
}
@@ -224,6 +233,7 @@
* 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 @@
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();
- assertTrue(owners.getProfileOwnerFile(10).exists());
- assertTrue(owners.getProfileOwnerFile(11).exists());
- assertFalse(owners.getProfileOwnerFile(20).exists());
- assertFalse(owners.getProfileOwnerFile(21).exists());
+ assertThat(owners.getProfileOwnerFile(10).exists()).isTrue();
+ assertThat(owners.getProfileOwnerFile(11).exists()).isTrue();
+ 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);
- 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();
}
// Then re-read and check.
@@ -278,31 +288,31 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 8dcf21f..6cefaeb 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_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.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 @@
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 @@
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 e51859b..0a9aad7 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.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 @@
/**
* 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 @@
@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)));
+ 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);
- 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)));
+ 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);
- assertEquals(365 * 40, FreezePeriod.distanceWithoutLeapYear(
- LocalDate.of(2040, 1, 1), LocalDate.of(2000, 1, 1)));
+ assertThat(FreezePeriod.distanceWithoutLeapYear(
+ LocalDate.of(2040, 1, 1), LocalDate.of(2000, 1, 1))).isEqualTo(365 * 40);
- 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(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 @@
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 @@
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 @@
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 @@
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 @@
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 2005dd9..07ea855 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.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 @@
/**
* 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 @@
@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 @@
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 @@
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 56966776..6cea928 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 @@
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 af161ee..ca0270d 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 @@
private Runnable mOnUserAttention;
private TestableAttentionDetector mAttentionDetector;
private AttentionDetector mRealAttentionDetector;
- private long mPreDimCheckDuration;
private long mNextDimming;
private int mIsSettingEnabled;
@@ -342,23 +341,14 @@
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 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 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 @@
}
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 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 b4480ae..f1d49d5 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 @@
});
}
+ @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/wifi/aidl-export/android/net/wifi/aware/AwareResources.aidl b/wifi/aidl-export/android/net/wifi/aware/AwareResources.aidl
new file mode 100644
index 0000000..d0bd2dd
--- /dev/null
+++ b/wifi/aidl-export/android/net/wifi/aware/AwareResources.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.aware;
+
+parcelable AwareResources;
\ No newline at end of file
diff --git a/wifi/api/current.txt b/wifi/api/current.txt
index 0bc1ff2..d5ef703 100644
--- a/wifi/api/current.txt
+++ b/wifi/api/current.txt
@@ -561,6 +561,15 @@
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 @@
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 fa99da7..edbd463 100644
--- a/wifi/api/system-current.txt
+++ b/wifi/api/system-current.txt
@@ -428,8 +428,11 @@
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 @@
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 b0ff4bb..ff06a18 100644
--- a/wifi/jarjar-rules.txt
+++ b/wifi/jarjar-rules.txt
@@ -36,7 +36,7 @@
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 9ca64d2..8103ff7 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -1011,6 +1011,17 @@
*/
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 @@
osu = false;
trusted = true; // Networks are considered trusted by default.
oemPaid = false;
+ oemPrivate = false;
fromWifiNetworkSuggestion = false;
fromWifiNetworkSpecifier = false;
meteredHint = false;
@@ -2372,13 +2384,14 @@
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 @@
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 @@
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 @@
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 fe5002e..774c043 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -164,6 +164,11 @@
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 @@
setFrequency(-1);
setMeteredHint(false);
setEphemeral(false);
+ setTrusted(false);
+ setOemPaid(false);
+ setOemPrivate(false);
setOsuAp(false);
setRequestingPackageName(null);
setFQDN(null);
@@ -363,7 +371,8 @@
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 @@
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 @@
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 @@
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 @@
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 acae218..dc6ec90 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -25,6 +25,7 @@
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 @@
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 @@
mWapiEnterpriseConfig = null;
mIsNetworkUntrusted = false;
mIsNetworkOemPaid = false;
+ mIsNetworkOemPrivate = false;
mPriorityGroup = 0;
mIsEnhancedMacRandomizationEnabled = false;
mSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -667,6 +675,9 @@
* 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 @@
* <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 @@
* <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 @@
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 @@
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 @@
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 @@
}
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 @@
.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 @@
}
/**
+ * @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 0000000..cee1f40
--- /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 cd2ca69..c90c4d8 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.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 @@
// 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 67c6032..e19b095 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -263,7 +263,7 @@
*
* @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 @@
}
/**
+ * 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 b82c67b..f09c37d 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -69,6 +69,7 @@
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 @@
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 @@
}
@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 06ae13a..c6faf66 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 @@
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 @@
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 @@
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 56e7998..870ff0a 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -223,6 +223,34 @@
/**
* 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 @@
}
/**
+ * 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 @@
/**
* 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 d0d0c57..1ecd325 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 @@
*/
@Test
public void testIsAttached() throws Exception {
+ assumeTrue(SdkLevel.isAtLeastS());
mDut.isDeviceAttached();
verify(mockAwareService).isDeviceAttached();
}
@@ -172,6 +173,16 @@
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
*/