Merge "Fix ripple radius calculation" into sc-dev
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
index 0b24c0d..b5e3662 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
@@ -90,6 +90,7 @@
@NonNull Consumer<AppSearchResult<AppSearchSession>> callback) {
try {
mService.initialize(
+ mPackageName,
mUserHandle,
/*binderCallStartTimeMillis=*/ SystemClock.elapsedRealtime(),
new IAppSearchResultCallback.Stub() {
@@ -685,7 +686,9 @@
if (mIsMutated && !mIsClosed) {
try {
mService.persistToDisk(
- mUserHandle, /*binderCallStartTimeMillis=*/ SystemClock.elapsedRealtime());
+ mPackageName,
+ mUserHandle,
+ /*binderCallStartTimeMillis=*/ SystemClock.elapsedRealtime());
mIsClosed = true;
} catch (RemoteException e) {
Log.e(TAG, "Unable to close the AppSearchSession", e);
diff --git a/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java
index 247eb08..130e442 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java
@@ -73,6 +73,7 @@
@NonNull Consumer<AppSearchResult<GlobalSearchSession>> callback) {
try {
mService.initialize(
+ mPackageName,
mUserHandle,
/*binderCallStartTimeMillis=*/ SystemClock.elapsedRealtime(),
new IAppSearchResultCallback.Stub() {
@@ -187,7 +188,9 @@
if (mIsMutated && !mIsClosed) {
try {
mService.persistToDisk(
- mUserHandle, /*binderCallStartTimeMillis=*/ SystemClock.elapsedRealtime());
+ mPackageName,
+ mUserHandle,
+ /*binderCallStartTimeMillis=*/ SystemClock.elapsedRealtime());
mIsClosed = true;
} catch (RemoteException e) {
Log.e(TAG, "Unable to close the GlobalSearchSession", e);
diff --git a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java b/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
index eb5d22e..6dfa01f 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
@@ -124,7 +124,8 @@
wrapCallback(executor, callback));
}
} else {
- mService.getNextPage(mNextPageToken, mUserHandle, wrapCallback(executor, callback));
+ mService.getNextPage(mPackageName, mNextPageToken, mUserHandle,
+ wrapCallback(executor, callback));
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -135,7 +136,7 @@
public void close() {
if (!mIsClosed) {
try {
- mService.invalidateNextPageToken(mNextPageToken, mUserHandle);
+ mService.invalidateNextPageToken(mPackageName, mNextPageToken, mUserHandle);
mIsClosed = true;
} catch (RemoteException e) {
Log.e(TAG, "Unable to close the SearchResults", e);
diff --git a/apex/appsearch/framework/java/android/app/appsearch/aidl/IAppSearchManager.aidl b/apex/appsearch/framework/java/android/app/appsearch/aidl/IAppSearchManager.aidl
index c639ef6..a2f545f 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/aidl/IAppSearchManager.aidl
+++ b/apex/appsearch/framework/java/android/app/appsearch/aidl/IAppSearchManager.aidl
@@ -181,21 +181,30 @@
* Fetches the next page of results of a previously executed query. Results can be empty if
* next-page token is invalid or all pages have been returned.
*
+ * @param packageName The name of the package to persist to disk for.
* @param nextPageToken The token of pre-loaded results of previously executed query.
* @param userHandle Handle of the calling user
* @param callback {@link AppSearchResult}<{@link Bundle}> of performing this
* operation.
*/
- void getNextPage(in long nextPageToken, in UserHandle userHandle, in IAppSearchResultCallback callback);
+ void getNextPage(
+ in String packageName,
+ in long nextPageToken,
+ in UserHandle userHandle,
+ in IAppSearchResultCallback callback);
/**
* Invalidates the next-page token so that no more results of the related query can be returned.
*
+ * @param packageName The name of the package to persist to disk for.
* @param nextPageToken The token of pre-loaded results of previously executed query to be
* Invalidated.
* @param userHandle Handle of the calling user
*/
- void invalidateNextPageToken(in long nextPageToken, in UserHandle userHandle);
+ void invalidateNextPageToken(
+ in String packageName,
+ in long nextPageToken,
+ in UserHandle userHandle);
/**
* Searches a document based on a given specifications.
@@ -336,20 +345,26 @@
/**
* Persists all update/delete requests to the disk.
*
+ * @param packageName The name of the package to persist to disk for.
* @param userHandle Handle of the calling user
* @param binderCallStartTimeMillis start timestamp of binder call in Millis
*/
- void persistToDisk(in UserHandle userHandle, in long binderCallStartTimeMillis);
+ void persistToDisk(
+ in String packageName,
+ in UserHandle userHandle,
+ in long binderCallStartTimeMillis);
/**
* Creates and initializes AppSearchImpl for the calling app.
*
+ * @param packageName The name of the package to initialize for.
* @param userHandle Handle of the calling user
* @param binderCallStartTimeMillis start timestamp of binder call in Millis
* @param callback {@link IAppSearchResultCallback#onResult} will be called with an
* {@link AppSearchResult}<{@link Void}>.
*/
void initialize(
+ in String packageName,
in UserHandle userHandle,
in long binderCallStartTimeMillis,
in IAppSearchResultCallback callback);
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchBatchResult.java b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchBatchResult.java
index 272e12d..d493a1c 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchBatchResult.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchBatchResult.java
@@ -96,17 +96,6 @@
return Collections.unmodifiableMap(mAll);
}
- /**
- * Asserts that this {@link AppSearchBatchResult} has no failures.
- *
- * @hide
- */
- public void checkSuccess() {
- if (!isSuccess()) {
- throw new IllegalStateException("AppSearchBatchResult has failures: " + this);
- }
- }
-
@Override
@NonNull
public String toString() {
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchResult.java b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchResult.java
index c57cf2e..b1cb132 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchResult.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchResult.java
@@ -239,6 +239,8 @@
resultCode = AppSearchResult.RESULT_INVALID_ARGUMENT;
} else if (t instanceof IOException) {
resultCode = AppSearchResult.RESULT_IO_ERROR;
+ } else if (t instanceof SecurityException) {
+ resultCode = AppSearchResult.RESULT_SECURITY_ERROR;
} else {
resultCode = AppSearchResult.RESULT_UNKNOWN_ERROR;
}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java
index 237e624..0ee5e65 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java
@@ -21,6 +21,7 @@
import android.annotation.Nullable;
import android.app.appsearch.exceptions.IllegalSchemaException;
import android.app.appsearch.util.BundleUtil;
+import android.app.appsearch.util.IndentingStringBuilder;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Bundle;
import android.util.ArraySet;
@@ -30,6 +31,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -67,8 +69,45 @@
}
@Override
+ @NonNull
public String toString() {
- return mBundle.toString();
+ IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
+ appendAppSearchSchemaString(stringBuilder);
+ return stringBuilder.toString();
+ }
+
+ /**
+ * Appends a debugging string for the {@link AppSearchSchema} instance to the given string
+ * builder.
+ *
+ * @param builder the builder to append to.
+ */
+ private void appendAppSearchSchemaString(@NonNull IndentingStringBuilder builder) {
+ Objects.requireNonNull(builder);
+
+ builder.append("{\n");
+ builder.increaseIndentLevel();
+ builder.append("schemaType: \"").append(getSchemaType()).append("\",\n");
+ builder.append("properties: [\n");
+
+ AppSearchSchema.PropertyConfig[] sortedProperties =
+ getProperties().toArray(new AppSearchSchema.PropertyConfig[0]);
+ Arrays.sort(sortedProperties, (o1, o2) -> o1.getName().compareTo(o2.getName()));
+
+ for (int i = 0; i < sortedProperties.length; i++) {
+ AppSearchSchema.PropertyConfig propertyConfig = sortedProperties[i];
+ builder.increaseIndentLevel();
+ propertyConfig.appendPropertyConfigString(builder);
+ if (i != sortedProperties.length - 1) {
+ builder.append(",\n");
+ }
+ builder.decreaseIndentLevel();
+ }
+
+ builder.append("\n");
+ builder.append("]\n");
+ builder.decreaseIndentLevel();
+ builder.append("}");
}
/** Returns the name of this schema type, e.g. Email. */
@@ -255,7 +294,68 @@
@Override
@NonNull
public String toString() {
- return mBundle.toString();
+ IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
+ appendPropertyConfigString(stringBuilder);
+ return stringBuilder.toString();
+ }
+
+ /**
+ * Appends a debug string for the {@link AppSearchSchema.PropertyConfig} instance to the
+ * given string builder.
+ *
+ * @param builder the builder to append to.
+ */
+ void appendPropertyConfigString(@NonNull IndentingStringBuilder builder) {
+ Objects.requireNonNull(builder);
+
+ builder.append("{\n");
+ builder.increaseIndentLevel();
+ builder.append("name: \"").append(getName()).append("\",\n");
+
+ if (this instanceof AppSearchSchema.StringPropertyConfig) {
+ ((StringPropertyConfig) this).appendStringPropertyConfigFields(builder);
+ } else if (this instanceof AppSearchSchema.DocumentPropertyConfig) {
+ ((DocumentPropertyConfig) this).appendDocumentPropertyConfigFields(builder);
+ }
+
+ switch (getCardinality()) {
+ case AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED:
+ builder.append("cardinality: CARDINALITY_REPEATED,\n");
+ break;
+ case AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL:
+ builder.append("cardinality: CARDINALITY_OPTIONAL,\n");
+ break;
+ case AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED:
+ builder.append("cardinality: CARDINALITY_REQUIRED,\n");
+ break;
+ default:
+ builder.append("cardinality: CARDINALITY_UNKNOWN,\n");
+ }
+
+ switch (getDataType()) {
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_STRING:
+ builder.append("dataType: DATA_TYPE_STRING,\n");
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_LONG:
+ builder.append("dataType: DATA_TYPE_LONG,\n");
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE:
+ builder.append("dataType: DATA_TYPE_DOUBLE,\n");
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN:
+ builder.append("dataType: DATA_TYPE_BOOLEAN,\n");
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES:
+ builder.append("dataType: DATA_TYPE_BYTES,\n");
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_DOCUMENT:
+ builder.append("dataType: DATA_TYPE_DOCUMENT,\n");
+ break;
+ default:
+ builder.append("dataType: DATA_TYPE_UNKNOWN,\n");
+ }
+ builder.decreaseIndentLevel();
+ builder.append("}");
}
/** Returns the name of this property. */
@@ -506,6 +606,41 @@
return new StringPropertyConfig(bundle);
}
}
+
+ /**
+ * Appends a debug string for the {@link StringPropertyConfig} instance to the given string
+ * builder.
+ *
+ * <p>This appends fields specific to a {@link StringPropertyConfig} instance.
+ *
+ * @param builder the builder to append to.
+ */
+ void appendStringPropertyConfigFields(@NonNull IndentingStringBuilder builder) {
+ switch (getIndexingType()) {
+ case AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE:
+ builder.append("indexingType: INDEXING_TYPE_NONE,\n");
+ break;
+ case AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS:
+ builder.append("indexingType: INDEXING_TYPE_EXACT_TERMS,\n");
+ break;
+ case AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES:
+ builder.append("indexingType: INDEXING_TYPE_PREFIXES,\n");
+ break;
+ default:
+ builder.append("indexingType: INDEXING_TYPE_UNKNOWN,\n");
+ }
+
+ switch (getTokenizerType()) {
+ case AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE:
+ builder.append("tokenizerType: TOKENIZER_TYPE_NONE,\n");
+ break;
+ case AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN:
+ builder.append("tokenizerType: TOKENIZER_TYPE_PLAIN,\n");
+ break;
+ default:
+ builder.append("tokenizerType: TOKENIZER_TYPE_UNKNOWN,\n");
+ }
+ }
}
/**
@@ -858,5 +993,21 @@
return new DocumentPropertyConfig(bundle);
}
}
+
+ /**
+ * Appends a debug string for the {@link DocumentPropertyConfig} instance to the given
+ * string builder.
+ *
+ * <p>This appends fields specific to a {@link DocumentPropertyConfig} instance.
+ *
+ * @param builder the builder to append to.
+ */
+ void appendDocumentPropertyConfigFields(@NonNull IndentingStringBuilder builder) {
+ builder.append("shouldIndexNestedProperties: ")
+ .append(shouldIndexNestedProperties())
+ .append(",\n");
+
+ builder.append("schemaType: \"").append(getSchemaType()).append("\",\n");
+ }
}
}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java b/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
index bcd341e..c905f95 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
@@ -22,6 +22,7 @@
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.appsearch.util.BundleUtil;
+import android.app.appsearch.util.IndentingStringBuilder;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Bundle;
import android.os.Parcelable;
@@ -50,9 +51,6 @@
public class GenericDocument {
private static final String TAG = "AppSearchGenericDocumen";
- /** The maximum number of elements in a repeatable field. */
- private static final int MAX_REPEATED_PROPERTY_LENGTH = 100;
-
/** The maximum {@link String#length} of a {@link String} field. */
private static final int MAX_STRING_LENGTH = 20_000;
@@ -861,6 +859,7 @@
*
* @hide
*/
+ // TODO(b/171882200): Expose this API in Android T
@NonNull
public GenericDocument.Builder<GenericDocument.Builder<?>> toBuilder() {
Bundle clonedBundle = BundleUtil.deepCopy(mBundle);
@@ -890,121 +889,101 @@
@Override
@NonNull
public String toString() {
- StringBuilder stringBuilder = new StringBuilder();
- appendGenericDocumentString(this, /*indentLevel=*/ 0, stringBuilder);
+ IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
+ appendGenericDocumentString(stringBuilder);
return stringBuilder.toString();
}
- private static void appendGenericDocumentString(
- @NonNull GenericDocument document, int indentLevel, @NonNull StringBuilder builder) {
- Objects.requireNonNull(document);
+ /**
+ * Appends a debug string for the {@link GenericDocument} instance to the given string builder.
+ *
+ * @param builder the builder to append to.
+ */
+ void appendGenericDocumentString(@NonNull IndentingStringBuilder builder) {
Objects.requireNonNull(builder);
- builder.append(getIndent(indentLevel)).append("{\n");
+ builder.append("{\n");
+ builder.increaseIndentLevel();
- String indent1 = getIndent(indentLevel + 1);
-
- builder.append(indent1)
- .append("namespace: \"")
- .append(document.getNamespace())
- .append("\",\n");
-
- builder.append(indent1).append("id: \"").append(document.getId()).append("\",\n");
-
- builder.append(indent1).append("score: ").append(document.getScore()).append(",\n");
-
- builder.append(indent1)
- .append("schemaType: \"")
- .append(document.getSchemaType())
- .append("\",\n");
-
- builder.append(indent1)
- .append("creationTimestampMillis: ")
- .append(document.getCreationTimestampMillis())
+ builder.append("namespace: \"").append(getNamespace()).append("\",\n");
+ builder.append("id: \"").append(getId()).append("\",\n");
+ builder.append("score: ").append(getScore()).append(",\n");
+ builder.append("schemaType: \"").append(getSchemaType()).append("\",\n");
+ builder.append("creationTimestampMillis: ")
+ .append(getCreationTimestampMillis())
.append(",\n");
+ builder.append("timeToLiveMillis: ").append(getTtlMillis()).append(",\n");
- builder.append(indent1)
- .append("timeToLiveMillis: ")
- .append(document.getTtlMillis())
- .append(",\n");
+ builder.append("properties: {\n");
- builder.append(indent1).append("properties: {\n");
-
- String[] sortedProperties = document.getPropertyNames().toArray(new String[0]);
+ String[] sortedProperties = getPropertyNames().toArray(new String[0]);
Arrays.sort(sortedProperties);
for (int i = 0; i < sortedProperties.length; i++) {
- Object property = document.getProperty(sortedProperties[i]);
- builder.append(getIndent(indentLevel + 2))
- .append("\"")
- .append(sortedProperties[i])
- .append("\"")
- .append(": ");
- appendPropertyString(property, indentLevel + 2, builder);
+ Object property = getProperty(sortedProperties[i]);
+ builder.increaseIndentLevel();
+ appendPropertyString(sortedProperties[i], property, builder);
if (i != sortedProperties.length - 1) {
builder.append(",\n");
}
+ builder.decreaseIndentLevel();
}
builder.append("\n");
- builder.append(indent1).append("}");
+ builder.append("}");
+ builder.decreaseIndentLevel();
builder.append("\n");
- builder.append(getIndent(indentLevel)).append("}");
+ builder.append("}");
}
/**
- * Appends a string for the given property to the given builder.
+ * Appends a debug string for the given document property to the given string builder.
*
+ * @param propertyName name of property to create string for.
* @param property property object to create string for.
- * @param indentLevel base indent level for property.
* @param builder the builder to append to.
*/
- private static void appendPropertyString(
- @NonNull Object property, int indentLevel, @NonNull StringBuilder builder) {
+ private void appendPropertyString(
+ @NonNull String propertyName,
+ @NonNull Object property,
+ @NonNull IndentingStringBuilder builder) {
+ Objects.requireNonNull(propertyName);
Objects.requireNonNull(property);
Objects.requireNonNull(builder);
- builder.append("[");
+ builder.append("\"").append(propertyName).append("\": [");
if (property instanceof GenericDocument[]) {
GenericDocument[] documentValues = (GenericDocument[]) property;
for (int i = 0; i < documentValues.length; ++i) {
builder.append("\n");
- appendGenericDocumentString(documentValues[i], indentLevel + 1, builder);
+ builder.increaseIndentLevel();
+ documentValues[i].appendGenericDocumentString(builder);
if (i != documentValues.length - 1) {
- builder.append(", ");
+ builder.append(",");
}
builder.append("\n");
+ builder.decreaseIndentLevel();
}
- builder.append(getIndent(indentLevel));
+ builder.append("]");
} else {
int propertyArrLength = Array.getLength(property);
for (int i = 0; i < propertyArrLength; i++) {
Object propertyElement = Array.get(property, i);
if (propertyElement instanceof String) {
- builder.append("\"").append(propertyElement).append("\"");
+ builder.append("\"").append((String) propertyElement).append("\"");
} else if (propertyElement instanceof byte[]) {
builder.append(Arrays.toString((byte[]) propertyElement));
} else {
- builder.append(propertyElement);
+ builder.append(propertyElement.toString());
}
if (i != propertyArrLength - 1) {
builder.append(", ");
+ } else {
+ builder.append("]");
}
}
}
-
- builder.append("]");
- }
-
- /** Appends a string for given indent level to the given builder. */
- @NonNull
- private static String getIndent(int indentLevel) {
- StringBuilder builder = new StringBuilder();
- for (int i = 0; i < indentLevel; ++i) {
- builder.append(" ");
- }
- return builder.toString();
}
/**
@@ -1187,8 +1166,8 @@
* @param name the name associated with the {@code values}. Must match the name for this
* property as given in {@link AppSearchSchema.PropertyConfig#getName}.
* @param values the {@code String} values of the property.
- * @throws IllegalArgumentException if no values are provided, if provided values exceed
- * maximum repeated property length, or if a passed in {@code String} is {@code null}.
+ * @throws IllegalArgumentException if no values are provided, or if a passed in {@code
+ * String} is {@code null}.
*/
@NonNull
public BuilderType setPropertyString(@NonNull String name, @NonNull String... values) {
@@ -1206,7 +1185,6 @@
* @param name the name associated with the {@code values}. Must match the name for this
* property as given in {@link AppSearchSchema.PropertyConfig#getName}.
* @param values the {@code boolean} values of the property.
- * @throws IllegalArgumentException if values exceed maximum repeated property length.
*/
@NonNull
public BuilderType setPropertyBoolean(@NonNull String name, @NonNull boolean... values) {
@@ -1223,7 +1201,6 @@
* @param name the name associated with the {@code values}. Must match the name for this
* property as given in {@link AppSearchSchema.PropertyConfig#getName}.
* @param values the {@code long} values of the property.
- * @throws IllegalArgumentException if values exceed maximum repeated property length.
*/
@NonNull
public BuilderType setPropertyLong(@NonNull String name, @NonNull long... values) {
@@ -1240,7 +1217,6 @@
* @param name the name associated with the {@code values}. Must match the name for this
* property as given in {@link AppSearchSchema.PropertyConfig#getName}.
* @param values the {@code double} values of the property.
- * @throws IllegalArgumentException if values exceed maximum repeated property length.
*/
@NonNull
public BuilderType setPropertyDouble(@NonNull String name, @NonNull double... values) {
@@ -1257,8 +1233,8 @@
* @param name the name associated with the {@code values}. Must match the name for this
* property as given in {@link AppSearchSchema.PropertyConfig#getName}.
* @param values the {@code byte[]} of the property.
- * @throws IllegalArgumentException if no values are provided, if provided values exceed
- * maximum repeated property length, or if a passed in {@code byte[]} is {@code null}.
+ * @throws IllegalArgumentException if no values are provided, or if a passed in {@code
+ * byte[]} is {@code null}.
*/
@NonNull
public BuilderType setPropertyBytes(@NonNull String name, @NonNull byte[]... values) {
@@ -1276,8 +1252,7 @@
* @param name the name associated with the {@code values}. Must match the name for this
* property as given in {@link AppSearchSchema.PropertyConfig#getName}.
* @param values the {@link GenericDocument} values of the property.
- * @throws IllegalArgumentException if no values are provided, if provided values exceed if
- * provided values exceed maximum repeated property length, or if a passed in {@link
+ * @throws IllegalArgumentException if no values are provided, or if a passed in {@link
* GenericDocument} is {@code null}.
*/
@NonNull
@@ -1308,7 +1283,6 @@
private void putInPropertyBundle(@NonNull String name, @NonNull String[] values)
throws IllegalArgumentException {
- validateRepeatedPropertyLength(name, values.length);
for (int i = 0; i < values.length; i++) {
if (values[i] == null) {
throw new IllegalArgumentException("The String at " + i + " is null.");
@@ -1327,17 +1301,14 @@
}
private void putInPropertyBundle(@NonNull String name, @NonNull boolean[] values) {
- validateRepeatedPropertyLength(name, values.length);
mProperties.putBooleanArray(name, values);
}
private void putInPropertyBundle(@NonNull String name, @NonNull double[] values) {
- validateRepeatedPropertyLength(name, values.length);
mProperties.putDoubleArray(name, values);
}
private void putInPropertyBundle(@NonNull String name, @NonNull long[] values) {
- validateRepeatedPropertyLength(name, values.length);
mProperties.putLongArray(name, values);
}
@@ -1348,7 +1319,6 @@
* into ArrayList<Bundle>, and each elements will contain a one dimension byte[].
*/
private void putInPropertyBundle(@NonNull String name, @NonNull byte[][] values) {
- validateRepeatedPropertyLength(name, values.length);
ArrayList<Bundle> bundles = new ArrayList<>(values.length);
for (int i = 0; i < values.length; i++) {
if (values[i] == null) {
@@ -1362,7 +1332,6 @@
}
private void putInPropertyBundle(@NonNull String name, @NonNull GenericDocument[] values) {
- validateRepeatedPropertyLength(name, values.length);
Parcelable[] documentBundles = new Parcelable[values.length];
for (int i = 0; i < values.length; i++) {
if (values[i] == null) {
@@ -1373,18 +1342,6 @@
mProperties.putParcelableArray(name, documentBundles);
}
- private static void validateRepeatedPropertyLength(@NonNull String name, int length) {
- if (length > MAX_REPEATED_PROPERTY_LENGTH) {
- throw new IllegalArgumentException(
- "Repeated property \""
- + name
- + "\" has length "
- + length
- + ", which exceeds the limit of "
- + MAX_REPEATED_PROPERTY_LENGTH);
- }
- }
-
/** Builds the {@link GenericDocument} object. */
@NonNull
public GenericDocument build() {
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
index 0af3e7a..b72ca9a 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
@@ -169,13 +169,14 @@
/** Builder for {@link SetSchemaRequest} objects. */
public static final class Builder {
+ private static final int DEFAULT_VERSION = 1;
private ArraySet<AppSearchSchema> mSchemas = new ArraySet<>();
private ArraySet<String> mSchemasNotDisplayedBySystem = new ArraySet<>();
private ArrayMap<String, Set<PackageIdentifier>> mSchemasVisibleToPackages =
new ArrayMap<>();
private ArrayMap<String, Migrator> mMigrators = new ArrayMap<>();
private boolean mForceOverride = false;
- private int mVersion = 1;
+ private int mVersion = DEFAULT_VERSION;
private boolean mBuilt = false;
/**
@@ -384,6 +385,9 @@
* <p>The version number can stay the same, increase, or decrease relative to the current
* version number that is already stored in the {@link AppSearchSession} database.
*
+ * <p>The version of an empty database will always be 0. You cannot set version to the
+ * {@link SetSchemaRequest}, if it doesn't contains any {@link AppSearchSchema}.
+ *
* @param version A positive integer representing the version of the entire set of schemas
* represents the version of the whole schema in the {@link AppSearchSession} database,
* default version is 1.
@@ -423,7 +427,10 @@
throw new IllegalArgumentException(
"Schema types " + referencedSchemas + " referenced, but were not added.");
}
-
+ if (mSchemas.isEmpty() && mVersion != DEFAULT_VERSION) {
+ throw new IllegalArgumentException(
+ "Cannot set version to the request if schema is empty.");
+ }
mBuilt = true;
return new SetSchemaRequest(
mSchemas,
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/util/IndentingStringBuilder.java b/apex/appsearch/framework/java/external/android/app/appsearch/util/IndentingStringBuilder.java
new file mode 100644
index 0000000..b494c3c
--- /dev/null
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/util/IndentingStringBuilder.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appsearch.util;
+
+import android.annotation.NonNull;
+
+/**
+ * Utility for building indented strings.
+ *
+ * <p>This is a wrapper for {@link StringBuilder} for appending strings with indentation. The
+ * indentation level can be increased by calling {@link #increaseIndentLevel()} and decreased by
+ * calling {@link #decreaseIndentLevel()}.
+ *
+ * <p>Indentation is applied after each newline character for the given indent level.
+ *
+ * @hide
+ */
+public class IndentingStringBuilder {
+ private final StringBuilder mStringBuilder = new StringBuilder();
+
+ // Indicates whether next non-newline character should have an indent applied before it.
+ private boolean mIndentNext = false;
+ private int mIndentLevel = 0;
+
+ /** Increases the indent level by one for appended strings. */
+ @NonNull
+ public IndentingStringBuilder increaseIndentLevel() {
+ mIndentLevel++;
+ return this;
+ }
+
+ /** Decreases the indent level by one for appended strings. */
+ @NonNull
+ public IndentingStringBuilder decreaseIndentLevel() throws IllegalStateException {
+ if (mIndentLevel == 0) {
+ throw new IllegalStateException("Cannot set indent level below 0.");
+ }
+ mIndentLevel--;
+ return this;
+ }
+
+ /**
+ * Appends provided {@code String} at the current indentation level.
+ *
+ * <p>Indentation is applied after each newline character.
+ */
+ @NonNull
+ public IndentingStringBuilder append(@NonNull String str) {
+ applyIndentToString(str);
+ return this;
+ }
+
+ /**
+ * Appends provided {@code Object}, represented as a {@code String}, at the current indentation
+ * level.
+ *
+ * <p>Indentation is applied after each newline character.
+ */
+ @NonNull
+ public IndentingStringBuilder append(@NonNull Object obj) {
+ applyIndentToString(obj.toString());
+ return this;
+ }
+
+ @Override
+ @NonNull
+ public String toString() {
+ return mStringBuilder.toString();
+ }
+
+ /** Adds indent string to the {@link StringBuilder} instance for current indent level. */
+ private void applyIndent() {
+ for (int i = 0; i < mIndentLevel; i++) {
+ mStringBuilder.append(" ");
+ }
+ }
+
+ /**
+ * Applies indent, for current indent level, after each newline character.
+ *
+ * <p>Consecutive newline characters are not indented.
+ */
+ private void applyIndentToString(@NonNull String str) {
+ int index = str.indexOf("\n");
+ if (index == 0) {
+ // String begins with new line character: append newline and slide past newline.
+ mStringBuilder.append("\n");
+ mIndentNext = true;
+ if (str.length() > 1) {
+ applyIndentToString(str.substring(index + 1));
+ }
+ } else if (index >= 1) {
+ // String contains new line character: divide string between newline, append new line,
+ // and recurse on each string.
+ String beforeIndentString = str.substring(0, index);
+ applyIndentToString(beforeIndentString);
+ mStringBuilder.append("\n");
+ mIndentNext = true;
+ if (str.length() > index + 1) {
+ String afterIndentString = str.substring(index + 1);
+ applyIndentToString(afterIndentString);
+ }
+ } else {
+ // String does not contain newline character: append string.
+ if (mIndentNext) {
+ applyIndent();
+ mIndentNext = false;
+ }
+ mStringBuilder.append(str);
+ }
+ }
+}
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 ac584fe..481d51e 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -60,8 +60,8 @@
import com.android.server.LocalManagerRegistry;
import com.android.server.SystemService;
import com.android.server.appsearch.external.localstorage.stats.CallStats;
+import com.android.server.appsearch.external.localstorage.visibilitystore.VisibilityStore;
import com.android.server.appsearch.util.PackageUtil;
-import com.android.server.appsearch.visibilitystore.VisibilityStore;
import com.android.server.usage.StorageStatsManagerLocal;
import com.android.server.usage.StorageStatsManagerLocal.StorageStatsAugmenter;
@@ -220,9 +220,10 @@
}
// Only clear the package's data if AppSearch exists for this user.
if (AppSearchUserInstanceManager.getAppSearchDir(userHandle).exists()) {
+ Context userContext = mContext.createContextAsUser(userHandle, /*flags=*/ 0);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getOrCreateUserInstance(
- mContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
+ userContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
//TODO(b/145759910) clear visibility setting for package.
instance.getAppSearchImpl().clearPackageData(packageName);
instance.getLogger().removeCachedUidForPackage(packageName);
@@ -243,11 +244,11 @@
try {
// Only clear the package's data if AppSearch exists for this user.
if (AppSearchUserInstanceManager.getAppSearchDir(userHandle).exists()) {
+ Context userContext = mContext.createContextAsUser(userHandle, /*flags=*/ 0);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getOrCreateUserInstance(
- mContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
- List<PackageInfo> installedPackageInfos = mContext
- .createContextAsUser(userHandle, /*flags=*/0)
+ userContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
+ List<PackageInfo> installedPackageInfos = userContext
.getPackageManager()
.getInstalledPackages(/*flags=*/0);
Set<String> packagesToKeep = new ArraySet<>(installedPackageInfos.size());
@@ -327,8 +328,10 @@
int operationSuccessCount = 0;
int operationFailureCount = 0;
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
- verifyCallingPackage(callingUser, callingUid, packageName);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
List<AppSearchSchema> schemas = new ArrayList<>(schemaBundles.size());
for (int i = 0; i < schemaBundles.size(); i++) {
schemas.add(new AppSearchSchema(schemaBundles.get(i)));
@@ -401,8 +404,10 @@
UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
EXECUTOR.execute(() -> {
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
- verifyCallingPackage(callingUser, callingUid, packageName);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getUserInstance(callingUser);
GetSchemaResponse response =
@@ -431,8 +436,10 @@
UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
EXECUTOR.execute(() -> {
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
- verifyCallingPackage(callingUser, callingUid, packageName);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getUserInstance(callingUser);
List<String> namespaces =
@@ -468,8 +475,10 @@
int operationSuccessCount = 0;
int operationFailureCount = 0;
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
- verifyCallingPackage(callingUser, callingUid, packageName);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
AppSearchBatchResult.Builder<String, Void> resultBuilder =
new AppSearchBatchResult.Builder<>();
instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
@@ -548,8 +557,10 @@
int operationSuccessCount = 0;
int operationFailureCount = 0;
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
- verifyCallingPackage(callingUser, callingUid, packageName);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
AppSearchBatchResult.Builder<String, Bundle> resultBuilder =
new AppSearchBatchResult.Builder<>();
instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
@@ -627,8 +638,10 @@
int operationSuccessCount = 0;
int operationFailureCount = 0;
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
- verifyCallingPackage(callingUser, callingUid, packageName);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
SearchResultPage searchResultPage = instance.getAppSearchImpl().query(
packageName,
@@ -691,8 +704,10 @@
int operationSuccessCount = 0;
int operationFailureCount = 0;
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
- verifyCallingPackage(callingUser, callingUid, packageName);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
boolean callerHasSystemAccess =
@@ -738,9 +753,11 @@
@Override
public void getNextPage(
+ @NonNull String packageName,
long nextPageToken,
@NonNull UserHandle userHandle,
@NonNull IAppSearchResultCallback callback) {
+ Objects.requireNonNull(packageName);
Objects.requireNonNull(userHandle);
Objects.requireNonNull(callback);
@@ -750,7 +767,10 @@
// opened it
EXECUTOR.execute(() -> {
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getUserInstance(callingUser);
SearchResultPage searchResultPage =
@@ -765,14 +785,19 @@
}
@Override
- public void invalidateNextPageToken(long nextPageToken, @NonNull UserHandle userHandle) {
+ public void invalidateNextPageToken(@NonNull String packageName, long nextPageToken,
+ @NonNull UserHandle userHandle) {
+ Objects.requireNonNull(packageName);
Objects.requireNonNull(userHandle);
int callingUid = Binder.getCallingUid();
UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
EXECUTOR.execute(() -> {
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getUserInstance(callingUser);
instance.getAppSearchImpl().invalidateNextPageToken(nextPageToken);
@@ -803,7 +828,10 @@
UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
EXECUTOR.execute(() -> {
try {
- verifyCallingPackage(callingUser, callingUid, packageName);
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
+ verifyUserUnlocked(callingUser);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getUserInstance(callingUser);
// we don't need to append the file. The file is always brand new.
@@ -849,7 +877,10 @@
UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
EXECUTOR.execute(() -> {
try {
- verifyCallingPackage(callingUser, callingUid, packageName);
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
+ verifyUserUnlocked(callingUser);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getUserInstance(callingUser);
@@ -908,8 +939,10 @@
UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
EXECUTOR.execute(() -> {
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
- verifyCallingPackage(callingUser, callingUid, packageName);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getUserInstance(callingUser);
@@ -957,8 +990,10 @@
int operationSuccessCount = 0;
int operationFailureCount = 0;
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
- verifyCallingPackage(callingUser, callingUid, packageName);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
AppSearchBatchResult.Builder<String, Void> resultBuilder =
new AppSearchBatchResult.Builder<>();
instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
@@ -1039,8 +1074,10 @@
int operationSuccessCount = 0;
int operationFailureCount = 0;
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
- verifyCallingPackage(callingUser, callingUid, packageName);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
instance.getAppSearchImpl().removeByQuery(
packageName,
@@ -1095,8 +1132,10 @@
UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
EXECUTOR.execute(() -> {
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
- verifyCallingPackage(callingUser, callingUid, packageName);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getUserInstance(callingUser);
StorageInfo storageInfo = instance.getAppSearchImpl()
@@ -1112,8 +1151,10 @@
@Override
public void persistToDisk(
+ @NonNull String packageName,
@NonNull UserHandle userHandle,
@ElapsedRealtimeLong long binderCallStartTimeMillis) {
+ Objects.requireNonNull(packageName);
Objects.requireNonNull(userHandle);
long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
@@ -1125,7 +1166,10 @@
int operationSuccessCount = 0;
int operationFailureCount = 0;
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
instance.getAppSearchImpl().persistToDisk(PersistType.Code.FULL);
++operationSuccessCount;
@@ -1157,24 +1201,30 @@
@Override
public void initialize(
+ @NonNull String packageName,
@NonNull UserHandle userHandle,
@ElapsedRealtimeLong long binderCallStartTimeMillis,
@NonNull IAppSearchResultCallback callback) {
+ Objects.requireNonNull(packageName);
Objects.requireNonNull(userHandle);
Objects.requireNonNull(callback);
long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
int callingUid = Binder.getCallingUid();
UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
+
EXECUTOR.execute(() -> {
@AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
AppSearchUserInstance instance = null;
int operationSuccessCount = 0;
int operationFailureCount = 0;
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
instance = mAppSearchUserInstanceManager.getOrCreateUserInstance(
- mContext, callingUser, AppSearchConfig.getInstance(EXECUTOR));
+ userContext, callingUser, AppSearchConfig.getInstance(EXECUTOR));
++operationSuccessCount;
invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
} catch (Throwable t) {
@@ -1204,14 +1254,15 @@
}
private void verifyCallingPackage(
+ @NonNull Context userContext,
@NonNull UserHandle actualCallingUser,
int actualCallingUid,
@NonNull String claimedCallingPackage) {
Objects.requireNonNull(actualCallingUser);
Objects.requireNonNull(claimedCallingPackage);
- int claimedCallingUid = PackageUtil.getPackageUidAsUser(
- mContext, claimedCallingPackage, actualCallingUser);
+ int claimedCallingUid = PackageUtil.getPackageUid(
+ userContext, claimedCallingPackage);
if (claimedCallingUid == INVALID_UID) {
throw new SecurityException(
"Specified calling package [" + claimedCallingPackage + "] not found");
@@ -1317,6 +1368,21 @@
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL);
}
+ /**
+ * Helper for ensuring instant apps can't make calls to AppSearch.
+ *
+ * @param userContext Context of the user making the call.
+ * @param packageName Package name of the caller.
+ * @throws SecurityException if the caller is an instant app.
+ */
+ private void verifyNotInstantApp(@NonNull Context userContext, @NonNull String packageName) {
+ PackageManager callingPackageManager = userContext.getPackageManager();
+ if (callingPackageManager.isInstantApp(packageName)) {
+ throw new SecurityException("Caller not allowed to create AppSearch session"
+ + "; userHandle=" + userContext.getUser() + ", callingPackage=" + packageName);
+ }
+ }
+
// TODO(b/179160886): Cache the previous storage stats.
private class AppSearchStorageStatsAugmenter implements StorageStatsAugmenter {
@Override
@@ -1331,9 +1397,10 @@
try {
verifyUserUnlocked(userHandle);
+ Context userContext = mContext.createContextAsUser(userHandle, /*flags=*/ 0);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getOrCreateUserInstance(
- mContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
+ userContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
stats.dataSize += instance.getAppSearchImpl()
.getStorageInfoForPackage(packageName).getSizeBytes();
} catch (Throwable t) {
@@ -1359,9 +1426,10 @@
if (packagesForUid == null) {
return;
}
+ Context userContext = mContext.createContextAsUser(userHandle, /*flags=*/ 0);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getOrCreateUserInstance(
- mContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
+ userContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
for (int i = 0; i < packagesForUid.length; i++) {
stats.dataSize += instance.getAppSearchImpl()
.getStorageInfoForPackage(packagesForUid[i]).getSizeBytes();
@@ -1387,9 +1455,10 @@
if (packagesForUser == null) {
return;
}
+ Context userContext = mContext.createContextAsUser(userHandle, /*flags=*/ 0);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getOrCreateUserInstance(
- mContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
+ userContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
for (int i = 0; i < packagesForUser.size(); i++) {
String packageName = packagesForUser.get(i).packageName;
stats.dataSize += instance.getAppSearchImpl()
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstance.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstance.java
index 7e743ed..56e2af5 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstance.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstance.java
@@ -19,7 +19,7 @@
import com.android.server.appsearch.external.localstorage.AppSearchImpl;
import com.android.server.appsearch.stats.PlatformLogger;
-import com.android.server.appsearch.visibilitystore.VisibilityStore;
+import com.android.server.appsearch.visibilitystore.VisibilityStoreImpl;
import java.util.Objects;
@@ -30,12 +30,12 @@
public final class AppSearchUserInstance {
private final PlatformLogger mLogger;
private final AppSearchImpl mAppSearchImpl;
- private final VisibilityStore mVisibilityStore;
+ private final VisibilityStoreImpl mVisibilityStore;
AppSearchUserInstance(
@NonNull PlatformLogger logger,
@NonNull AppSearchImpl appSearchImpl,
- @NonNull VisibilityStore visibilityStore) {
+ @NonNull VisibilityStoreImpl visibilityStore) {
mLogger = Objects.requireNonNull(logger);
mAppSearchImpl = Objects.requireNonNull(appSearchImpl);
mVisibilityStore = Objects.requireNonNull(visibilityStore);
@@ -52,7 +52,7 @@
}
@NonNull
- public VisibilityStore getVisibilityStore() {
+ public VisibilityStoreImpl getVisibilityStore() {
return mVisibilityStore;
}
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstanceManager.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstanceManager.java
index cedc364..e067d4b 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstanceManager.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstanceManager.java
@@ -30,7 +30,7 @@
import com.android.server.appsearch.external.localstorage.FrameworkOptimizeStrategy;
import com.android.server.appsearch.external.localstorage.stats.InitializeStats;
import com.android.server.appsearch.stats.PlatformLogger;
-import com.android.server.appsearch.visibilitystore.VisibilityStore;
+import com.android.server.appsearch.visibilitystore.VisibilityStoreImpl;
import java.io.File;
import java.util.Map;
@@ -89,25 +89,24 @@
* <p>If no AppSearchUserInstance exists for the unlocked user, Icing will be initialized and
* one will be created.
*
- * @param context The context
+ * @param userContext Context of the user calling AppSearch
* @param userHandle The multi-user handle of the device user calling AppSearch
* @param config Flag manager for AppSearch
* @return An initialized {@link AppSearchUserInstance} for this user
*/
@NonNull
public AppSearchUserInstance getOrCreateUserInstance(
- @NonNull Context context,
+ @NonNull Context userContext,
@NonNull UserHandle userHandle,
@NonNull AppSearchConfig config)
throws AppSearchException {
- Objects.requireNonNull(context);
+ Objects.requireNonNull(userContext);
Objects.requireNonNull(userHandle);
Objects.requireNonNull(config);
synchronized (mInstancesLocked) {
AppSearchUserInstance instance = mInstancesLocked.get(userHandle);
if (instance == null) {
- Context userContext = context.createContextAsUser(userHandle, /*flags=*/ 0);
instance = createUserInstance(userContext, userHandle, config);
mInstancesLocked.put(userHandle, instance);
}
@@ -169,7 +168,7 @@
InitializeStats.Builder initStatsBuilder = new InitializeStats.Builder();
// Initialize the classes that make up AppSearchUserInstance
- PlatformLogger logger = new PlatformLogger(userContext, userHandle, config);
+ PlatformLogger logger = new PlatformLogger(userContext, config);
File appSearchDir = getAppSearchDir(userHandle);
File icingDir = new File(appSearchDir, "icing");
@@ -178,7 +177,8 @@
AppSearchImpl.create(icingDir, initStatsBuilder, new FrameworkOptimizeStrategy());
long prepareVisibilityStoreLatencyStartMillis = SystemClock.elapsedRealtime();
- VisibilityStore visibilityStore = VisibilityStore.create(appSearchImpl, userContext);
+ VisibilityStoreImpl visibilityStore =
+ VisibilityStoreImpl.create(appSearchImpl, userContext);
long prepareVisibilityStoreLatencyEndMillis = SystemClock.elapsedRealtime();
initStatsBuilder
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
index 4ad1c8c..9dee179 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
@@ -58,7 +58,7 @@
import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
import com.android.server.appsearch.external.localstorage.stats.RemoveStats;
import com.android.server.appsearch.external.localstorage.stats.SearchStats;
-import com.android.server.appsearch.visibilitystore.VisibilityStore;
+import com.android.server.appsearch.external.localstorage.visibilitystore.VisibilityStore;
import com.google.android.icing.IcingSearchEngine;
import com.google.android.icing.proto.DeleteByQueryResultProto;
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/visibilitystore/VisibilityStore.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/visibilitystore/VisibilityStore.java
new file mode 100644
index 0000000..fb89250
--- /dev/null
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/visibilitystore/VisibilityStore.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.appsearch.external.localstorage.visibilitystore;
+
+import android.annotation.NonNull;
+import android.app.appsearch.PackageIdentifier;
+import android.app.appsearch.exceptions.AppSearchException;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * An interface for classes that store and validate document visibility data.
+ *
+ * @hide
+ */
+public interface VisibilityStore {
+ /**
+ * These cannot have any of the special characters used by AppSearchImpl (e.g. {@code
+ * AppSearchImpl#PACKAGE_DELIMITER} or {@code AppSearchImpl#DATABASE_DELIMITER}.
+ */
+ String PACKAGE_NAME = "VS#Pkg";
+
+ @VisibleForTesting String DATABASE_NAME = "VS#Db";
+
+ /**
+ * Sets visibility settings for the given database. Any previous visibility settings will be
+ * overwritten.
+ *
+ * @param packageName Package of app that owns the schemas.
+ * @param databaseName Database that owns the schemas.
+ * @param schemasNotDisplayedBySystem Set of prefixed schemas that should be hidden from
+ * platform surfaces.
+ * @param schemasVisibleToPackages Map of prefixed schemas to a list of package identifiers that
+ * have access to the schema.
+ * @throws AppSearchException on AppSearchImpl error.
+ */
+ void setVisibility(
+ @NonNull String packageName,
+ @NonNull String databaseName,
+ @NonNull Set<String> schemasNotDisplayedBySystem,
+ @NonNull Map<String, List<PackageIdentifier>> schemasVisibleToPackages)
+ throws AppSearchException;
+
+ /**
+ * Checks whether the given package has access to system-surfaceable schemas.
+ *
+ * @param callerUid UID of the app that wants to see the data.
+ */
+ boolean isSchemaSearchableByCaller(
+ @NonNull String packageName,
+ @NonNull String databaseName,
+ @NonNull String prefixedSchema,
+ int callerUid,
+ boolean callerHasSystemAccess);
+}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java b/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java
index 31fead5e..322bd11 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java
@@ -22,7 +22,6 @@
import android.content.Context;
import android.os.Process;
import android.os.SystemClock;
-import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseIntArray;
@@ -55,11 +54,8 @@
public final class PlatformLogger implements AppSearchLogger {
private static final String TAG = "AppSearchPlatformLogger";
- // Context of the system service.
- private final Context mContext;
-
- // User we're logging for.
- private final UserHandle mUserHandle;
+ // Context of the user we're logging for.
+ private final Context mUserContext;
// Manager holding the configuration flags
private final AppSearchConfig mConfig;
@@ -120,10 +116,9 @@
* Westworld constructor
*/
public PlatformLogger(
- @NonNull Context context, @NonNull UserHandle userHandle,
+ @NonNull Context userContext,
@NonNull AppSearchConfig config) {
- mContext = Objects.requireNonNull(context);
- mUserHandle = Objects.requireNonNull(userHandle);
+ mUserContext = Objects.requireNonNull(userContext);
mConfig = Objects.requireNonNull(config);
}
@@ -451,7 +446,7 @@
private int getPackageUidAsUserLocked(@NonNull String packageName) {
Integer packageUid = mPackageUidCacheLocked.get(packageName);
if (packageUid == null) {
- packageUid = PackageUtil.getPackageUidAsUser(mContext, packageName, mUserHandle);
+ packageUid = PackageUtil.getPackageUid(mUserContext, packageName);
if (packageUid != Process.INVALID_UID) {
mPackageUidCacheLocked.put(packageName, packageUid);
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/util/PackageUtil.java b/apex/appsearch/service/java/com/android/server/appsearch/util/PackageUtil.java
index 53a1bed..714ffb6 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/util/PackageUtil.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/util/PackageUtil.java
@@ -20,7 +20,6 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Process;
-import android.os.UserHandle;
/**
* Utilities for interacting with {@link android.content.pm.PackageManager},
@@ -32,16 +31,6 @@
private PackageUtil() {}
/**
- * Finds the UID of the {@code packageName}. Returns {@link Process#INVALID_UID} if unable to
- * find the UID.
- */
- public static int getPackageUidAsUser(
- @NonNull Context context, @NonNull String packageName, @NonNull UserHandle user) {
- Context userContext = context.createContextAsUser(user, /*flags=*/ 0);
- return getPackageUid(userContext, packageName);
- }
-
- /**
* Finds the UID of the {@code packageName} in the given {@code context}. Returns
* {@link Process#INVALID_UID} if unable to find the UID.
*/
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStore.java b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStoreImpl.java
similarity index 88%
rename from apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStore.java
rename to apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStoreImpl.java
index a096aef..ce142d6 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStore.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStoreImpl.java
@@ -30,9 +30,9 @@
import android.util.ArrayMap;
import android.util.ArraySet;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.server.appsearch.external.localstorage.AppSearchImpl;
import com.android.server.appsearch.external.localstorage.util.PrefixUtil;
+import com.android.server.appsearch.external.localstorage.visibilitystore.VisibilityStore;
import com.android.server.appsearch.util.PackageUtil;
import com.google.android.icing.proto.PersistType;
@@ -60,23 +60,12 @@
* <p>This class doesn't handle any locking itself. Its callers should handle the locking at a
* higher level.
*
- * <p>NOTE: This class holds an instance of AppSearchImpl and AppSearchImpl holds an instance of
- * this class. Take care to not cause any circular dependencies.
- *
* @hide
*/
-public class VisibilityStore {
+public class VisibilityStoreImpl implements VisibilityStore {
/** Version for the visibility schema */
private static final int SCHEMA_VERSION = 0;
- /**
- * These cannot have any of the special characters used by AppSearchImpl (e.g. {@code
- * AppSearchImpl#PACKAGE_DELIMITER} or {@code AppSearchImpl#DATABASE_DELIMITER}.
- */
- public static final String PACKAGE_NAME = "VS#Pkg";
-
- @VisibleForTesting public static final String DATABASE_NAME = "VS#Db";
-
/** Namespace of documents that contain visibility settings */
private static final String NAMESPACE = "";
@@ -101,13 +90,13 @@
* @param userContext Context of the user that the call is being made as
*/
@NonNull
- public static VisibilityStore create(
+ public static VisibilityStoreImpl create(
@NonNull AppSearchImpl appSearchImpl, @NonNull Context userContext)
throws AppSearchException {
- return new VisibilityStore(appSearchImpl, userContext);
+ return new VisibilityStoreImpl(appSearchImpl, userContext);
}
- private VisibilityStore(@NonNull AppSearchImpl appSearchImpl, @NonNull Context userContext)
+ private VisibilityStoreImpl(@NonNull AppSearchImpl appSearchImpl, @NonNull Context userContext)
throws AppSearchException {
mAppSearchImpl = Objects.requireNonNull(appSearchImpl);
mUserContext = Objects.requireNonNull(userContext);
@@ -207,18 +196,7 @@
}
}
- /**
- * Sets visibility settings for the given database. Any previous visibility settings will be
- * overwritten.
- *
- * @param packageName Package of app that owns the schemas.
- * @param databaseName Database that owns the schemas.
- * @param schemasNotDisplayedBySystem Set of prefixed schemas that should be hidden from the
- * platform.
- * @param schemasVisibleToPackages Map of prefixed schemas to a list of package identifiers that
- * have access to the schema.
- * @throws AppSearchException on AppSearchImpl error.
- */
+ @Override
public void setVisibility(
@NonNull String packageName,
@NonNull String databaseName,
@@ -282,17 +260,7 @@
== PackageManager.PERMISSION_GRANTED;
}
- /**
- * Checks whether {@code prefixedSchema} can be searched over by the {@code callerUid}.
- *
- * @param packageName Package that owns the schema.
- * @param databaseName Database within the package that owns the schema.
- * @param prefixedSchema Prefixed schema type the caller is trying to access.
- * @param callerUid UID of the client making the globalQuery call.
- * @param callerHasSystemAccess Whether the caller has been identified as having
- * access to schemas marked system surfaceable by {@link
- * #doesCallerHaveSystemAccess}.
- */
+ @Override
public boolean isSchemaSearchableByCaller(
@NonNull String packageName,
@NonNull String databaseName,
diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt
index 9859f20..6555107 100644
--- a/apex/appsearch/synced_jetpack_changeid.txt
+++ b/apex/appsearch/synced_jetpack_changeid.txt
@@ -1 +1 @@
-04351b43fbbf9d59ffeae41903322023931c84f2
+c7387d9b58726a23a0608a9365fb3a1b57b7b8a1
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index 0e9efbc..ac20187 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -442,6 +442,7 @@
private long mNextIdlePendingDelay;
private long mNextIdleDelay;
private long mNextLightIdleDelay;
+ private long mNextLightIdleDelayFlex;
private long mNextLightAlarmTime;
private long mNextSensingTimeoutAlarmTime;
@@ -886,16 +887,20 @@
*/
public final class Constants implements DeviceConfig.OnPropertiesChangedListener {
// Key names stored in the settings value.
- private static final String KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT
- = "light_after_inactive_to";
+ private static final String KEY_FLEX_TIME_SHORT = "flex_time_short";
+ private static final String KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT =
+ "light_after_inactive_to";
private static final String KEY_LIGHT_PRE_IDLE_TIMEOUT = "light_pre_idle_to";
private static final String KEY_LIGHT_IDLE_TIMEOUT = "light_idle_to";
+ private static final String KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX =
+ "light_idle_to_initial_flex";
+ private static final String KEY_LIGHT_MAX_IDLE_TIMEOUT_FLEX = "light_max_idle_to_flex";
private static final String KEY_LIGHT_IDLE_FACTOR = "light_idle_factor";
private static final String KEY_LIGHT_MAX_IDLE_TIMEOUT = "light_max_idle_to";
- private static final String KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET
- = "light_idle_maintenance_min_budget";
- private static final String KEY_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET
- = "light_idle_maintenance_max_budget";
+ private static final String KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET =
+ "light_idle_maintenance_min_budget";
+ private static final String KEY_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET =
+ "light_idle_maintenance_max_budget";
private static final String KEY_MIN_LIGHT_MAINTENANCE_TIME = "min_light_maintenance_time";
private static final String KEY_MIN_DEEP_MAINTENANCE_TIME = "min_deep_maintenance_time";
private static final String KEY_INACTIVE_TIMEOUT = "inactive_to";
@@ -903,6 +908,7 @@
private static final String KEY_LOCATING_TIMEOUT = "locating_to";
private static final String KEY_LOCATION_ACCURACY = "location_accuracy";
private static final String KEY_MOTION_INACTIVE_TIMEOUT = "motion_inactive_to";
+ private static final String KEY_MOTION_INACTIVE_TIMEOUT_FLEX = "motion_inactive_to_flex";
private static final String KEY_IDLE_AFTER_INACTIVE_TIMEOUT = "idle_after_inactive_to";
private static final String KEY_IDLE_PENDING_TIMEOUT = "idle_pending_to";
private static final String KEY_MAX_IDLE_PENDING_TIMEOUT = "max_idle_pending_to";
@@ -929,13 +935,20 @@
"pre_idle_factor_long";
private static final String KEY_PRE_IDLE_FACTOR_SHORT =
"pre_idle_factor_short";
+ private static final String KEY_USE_WINDOW_ALARMS = "use_window_alarms";
+ private static final long DEFAULT_FLEX_TIME_SHORT =
+ !COMPRESS_TIME ? 60 * 1000L : 5 * 1000L;
private static final long DEFAULT_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT =
- !COMPRESS_TIME ? 3 * 60 * 1000L : 15 * 1000L;
+ !COMPRESS_TIME ? 60 * 1000L : 15 * 1000L;
private static final long DEFAULT_LIGHT_PRE_IDLE_TIMEOUT =
!COMPRESS_TIME ? 3 * 60 * 1000L : 30 * 1000L;
private static final long DEFAULT_LIGHT_IDLE_TIMEOUT =
!COMPRESS_TIME ? 5 * 60 * 1000L : 15 * 1000L;
+ private static final long DEFAULT_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX =
+ !COMPRESS_TIME ? 60 * 1000L : 5 * 1000L;
+ private static final long DEFAULT_LIGHT_MAX_IDLE_TIMEOUT_FLEX =
+ !COMPRESS_TIME ? 15 * 60 * 1000L : 60 * 1000L;
private static final float DEFAULT_LIGHT_IDLE_FACTOR = 2f;
private static final long DEFAULT_LIGHT_MAX_IDLE_TIMEOUT =
!COMPRESS_TIME ? 15 * 60 * 1000L : 60 * 1000L;
@@ -958,6 +971,8 @@
private static final float DEFAULT_LOCATION_ACCURACY = 20f;
private static final long DEFAULT_MOTION_INACTIVE_TIMEOUT =
!COMPRESS_TIME ? 10 * 60 * 1000L : 60 * 1000L;
+ private static final long DEFAULT_MOTION_INACTIVE_TIMEOUT_FLEX =
+ !COMPRESS_TIME ? 60 * 1000L : 5 * 1000L;
private static final long DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT =
(30 * 60 * 1000L) / (!COMPRESS_TIME ? 1 : 10);
private static final long DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT_SMALL_BATTERY =
@@ -983,6 +998,14 @@
private static final boolean DEFAULT_WAIT_FOR_UNLOCK = true;
private static final float DEFAULT_PRE_IDLE_FACTOR_LONG = 1.67f;
private static final float DEFAULT_PRE_IDLE_FACTOR_SHORT = .33f;
+ private static final boolean DEFAULT_USE_WINDOW_ALARMS = true;
+
+ /**
+ * A somewhat short alarm window size that we will tolerate for various alarm timings.
+ *
+ * @see #KEY_FLEX_TIME_SHORT
+ */
+ public long FLEX_TIME_SHORT = DEFAULT_FLEX_TIME_SHORT;
/**
* This is the time, after becoming inactive, that we go in to the first
@@ -1002,13 +1025,28 @@
public long LIGHT_PRE_IDLE_TIMEOUT = DEFAULT_LIGHT_PRE_IDLE_TIMEOUT;
/**
- * This is the initial time that we will run in idle maintenance mode.
+ * This is the initial time that we will run in light idle maintenance mode.
*
* @see #KEY_LIGHT_IDLE_TIMEOUT
*/
public long LIGHT_IDLE_TIMEOUT = DEFAULT_LIGHT_IDLE_TIMEOUT;
/**
+ * This is the initial alarm window size that we will tolerate for light idle maintenance
+ * timing.
+ *
+ * @see #KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX
+ */
+ public long LIGHT_IDLE_TIMEOUT_INITIAL_FLEX = DEFAULT_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX;
+
+ /**
+ * This is the maximum value that {@link #LIGHT_IDLE_TIMEOUT_INITIAL_FLEX} should take.
+ *
+ * @see #KEY_LIGHT_MAX_IDLE_TIMEOUT_FLEX
+ */
+ public long LIGHT_MAX_IDLE_TIMEOUT_FLEX = DEFAULT_LIGHT_MAX_IDLE_TIMEOUT_FLEX;
+
+ /**
* Scaling factor to apply to the light idle mode time each time we complete a cycle.
*
* @see #KEY_LIGHT_IDLE_FACTOR
@@ -1016,7 +1054,7 @@
public float LIGHT_IDLE_FACTOR = DEFAULT_LIGHT_IDLE_FACTOR;
/**
- * This is the maximum time we will run in idle maintenance mode.
+ * This is the maximum time we will stay in light idle mode.
*
* @see #KEY_LIGHT_MAX_IDLE_TIMEOUT
*/
@@ -1099,13 +1137,22 @@
/**
* This is the time, after seeing motion, that we wait after becoming inactive from
* that until we start looking for motion again.
+ *
* @see #KEY_MOTION_INACTIVE_TIMEOUT
*/
public long MOTION_INACTIVE_TIMEOUT = DEFAULT_MOTION_INACTIVE_TIMEOUT;
/**
+ * This is the alarm window size we will tolerate for motion detection timings.
+ *
+ * @see #KEY_MOTION_INACTIVE_TIMEOUT_FLEX
+ */
+ public long MOTION_INACTIVE_TIMEOUT_FLEX = DEFAULT_MOTION_INACTIVE_TIMEOUT_FLEX;
+
+ /**
* This is the time, after the inactive timeout elapses, that we will wait looking
* for motion until we truly consider the device to be idle.
+ *
* @see #KEY_IDLE_AFTER_INACTIVE_TIMEOUT
*/
public long IDLE_AFTER_INACTIVE_TIMEOUT = DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT;
@@ -1204,6 +1251,12 @@
public boolean WAIT_FOR_UNLOCK = DEFAULT_WAIT_FOR_UNLOCK;
+ /**
+ * Whether to use window alarms. True to use window alarms (call AlarmManager.setWindow()).
+ * False to use the legacy inexact alarms (call AlarmManager.set()).
+ */
+ public boolean USE_WINDOW_ALARMS = DEFAULT_USE_WINDOW_ALARMS;
+
private final boolean mSmallBatteryDevice;
public Constants() {
@@ -1227,6 +1280,10 @@
continue;
}
switch (name) {
+ case KEY_FLEX_TIME_SHORT:
+ FLEX_TIME_SHORT = properties.getLong(
+ KEY_FLEX_TIME_SHORT, DEFAULT_FLEX_TIME_SHORT);
+ break;
case KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT:
LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT = properties.getLong(
KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT,
@@ -1240,9 +1297,19 @@
LIGHT_IDLE_TIMEOUT = properties.getLong(
KEY_LIGHT_IDLE_TIMEOUT, DEFAULT_LIGHT_IDLE_TIMEOUT);
break;
+ case KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX:
+ LIGHT_IDLE_TIMEOUT_INITIAL_FLEX = properties.getLong(
+ KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX,
+ DEFAULT_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX);
+ break;
+ case KEY_LIGHT_MAX_IDLE_TIMEOUT_FLEX:
+ LIGHT_MAX_IDLE_TIMEOUT_FLEX = properties.getLong(
+ KEY_LIGHT_MAX_IDLE_TIMEOUT_FLEX,
+ DEFAULT_LIGHT_MAX_IDLE_TIMEOUT_FLEX);
+ break;
case KEY_LIGHT_IDLE_FACTOR:
- LIGHT_IDLE_FACTOR = properties.getFloat(
- KEY_LIGHT_IDLE_FACTOR, DEFAULT_LIGHT_IDLE_FACTOR);
+ LIGHT_IDLE_FACTOR = Math.max(1, properties.getFloat(
+ KEY_LIGHT_IDLE_FACTOR, DEFAULT_LIGHT_IDLE_FACTOR));
break;
case KEY_LIGHT_MAX_IDLE_TIMEOUT:
LIGHT_MAX_IDLE_TIMEOUT = properties.getLong(
@@ -1291,6 +1358,11 @@
MOTION_INACTIVE_TIMEOUT = properties.getLong(
KEY_MOTION_INACTIVE_TIMEOUT, DEFAULT_MOTION_INACTIVE_TIMEOUT);
break;
+ case KEY_MOTION_INACTIVE_TIMEOUT_FLEX:
+ MOTION_INACTIVE_TIMEOUT_FLEX = properties.getLong(
+ KEY_MOTION_INACTIVE_TIMEOUT_FLEX,
+ DEFAULT_MOTION_INACTIVE_TIMEOUT_FLEX);
+ break;
case KEY_IDLE_AFTER_INACTIVE_TIMEOUT:
final long defaultIdleAfterInactiveTimeout = mSmallBatteryDevice
? DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT_SMALL_BATTERY
@@ -1362,6 +1434,10 @@
PRE_IDLE_FACTOR_SHORT = properties.getFloat(
KEY_PRE_IDLE_FACTOR_SHORT, DEFAULT_PRE_IDLE_FACTOR_SHORT);
break;
+ case KEY_USE_WINDOW_ALARMS:
+ USE_WINDOW_ALARMS = properties.getBoolean(
+ KEY_USE_WINDOW_ALARMS, DEFAULT_USE_WINDOW_ALARMS);
+ break;
default:
Slog.e(TAG, "Unknown configuration key: " + name);
break;
@@ -1373,6 +1449,10 @@
void dump(PrintWriter pw) {
pw.println(" Settings:");
+ pw.print(" "); pw.print(KEY_FLEX_TIME_SHORT); pw.print("=");
+ TimeUtils.formatDuration(FLEX_TIME_SHORT, pw);
+ pw.println();
+
pw.print(" ");
pw.print(KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT);
pw.print("=");
@@ -1387,6 +1467,14 @@
TimeUtils.formatDuration(LIGHT_IDLE_TIMEOUT, pw);
pw.println();
+ pw.print(" "); pw.print(KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX); pw.print("=");
+ TimeUtils.formatDuration(LIGHT_IDLE_TIMEOUT_INITIAL_FLEX, pw);
+ pw.println();
+
+ pw.print(" "); pw.print(KEY_LIGHT_MAX_IDLE_TIMEOUT_FLEX); pw.print("=");
+ TimeUtils.formatDuration(LIGHT_MAX_IDLE_TIMEOUT_FLEX, pw);
+ pw.println();
+
pw.print(" "); pw.print(KEY_LIGHT_IDLE_FACTOR); pw.print("=");
pw.print(LIGHT_IDLE_FACTOR);
pw.println();
@@ -1431,6 +1519,10 @@
TimeUtils.formatDuration(MOTION_INACTIVE_TIMEOUT, pw);
pw.println();
+ pw.print(" "); pw.print(KEY_MOTION_INACTIVE_TIMEOUT_FLEX); pw.print("=");
+ TimeUtils.formatDuration(MOTION_INACTIVE_TIMEOUT_FLEX, pw);
+ pw.println();
+
pw.print(" "); pw.print(KEY_IDLE_AFTER_INACTIVE_TIMEOUT); pw.print("=");
TimeUtils.formatDuration(IDLE_AFTER_INACTIVE_TIMEOUT, pw);
pw.println();
@@ -1489,6 +1581,9 @@
pw.print(" "); pw.print(KEY_PRE_IDLE_FACTOR_SHORT); pw.print("=");
pw.println(PRE_IDLE_FACTOR_SHORT);
+
+ pw.print(" "); pw.print(KEY_USE_WINDOW_ALARMS); pw.print("=");
+ pw.println(USE_WINDOW_ALARMS);
}
}
@@ -3199,7 +3294,8 @@
mLightState = LIGHT_STATE_INACTIVE;
if (DEBUG) Slog.d(TAG, "Moved from LIGHT_STATE_ACTIVE to LIGHT_STATE_INACTIVE");
resetLightIdleManagementLocked();
- scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT);
+ scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT,
+ mConstants.FLEX_TIME_SHORT);
EventLogTags.writeDeviceIdleLight(mLightState, "no activity");
}
}
@@ -3219,6 +3315,7 @@
private void resetLightIdleManagementLocked() {
mNextLightIdleDelay = 0;
+ mNextLightIdleDelayFlex = 0;
mCurLightIdleBudget = 0;
cancelLightAlarmLocked();
}
@@ -3265,13 +3362,15 @@
mCurLightIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
// Reset the upcoming idle delays.
mNextLightIdleDelay = mConstants.LIGHT_IDLE_TIMEOUT;
+ mNextLightIdleDelayFlex = mConstants.LIGHT_IDLE_TIMEOUT_INITIAL_FLEX;
mMaintenanceStartTime = 0;
if (!isOpsInactiveLocked()) {
// We have some active ops going on... give them a chance to finish
// before going in to our first idle.
mLightState = LIGHT_STATE_PRE_IDLE;
EventLogTags.writeDeviceIdleLight(mLightState, reason);
- scheduleLightAlarmLocked(mConstants.LIGHT_PRE_IDLE_TIMEOUT);
+ scheduleLightAlarmLocked(mConstants.LIGHT_PRE_IDLE_TIMEOUT,
+ mConstants.FLEX_TIME_SHORT);
break;
}
// Nothing active, fall through to immediately idle.
@@ -3290,12 +3389,11 @@
}
}
mMaintenanceStartTime = 0;
- scheduleLightAlarmLocked(mNextLightIdleDelay);
+ scheduleLightAlarmLocked(mNextLightIdleDelay, mNextLightIdleDelayFlex);
mNextLightIdleDelay = Math.min(mConstants.LIGHT_MAX_IDLE_TIMEOUT,
- (long)(mNextLightIdleDelay * mConstants.LIGHT_IDLE_FACTOR));
- if (mNextLightIdleDelay < mConstants.LIGHT_IDLE_TIMEOUT) {
- mNextLightIdleDelay = mConstants.LIGHT_IDLE_TIMEOUT;
- }
+ (long) (mNextLightIdleDelay * mConstants.LIGHT_IDLE_FACTOR));
+ mNextLightIdleDelayFlex = Math.min(mConstants.LIGHT_MAX_IDLE_TIMEOUT_FLEX,
+ (long) (mNextLightIdleDelayFlex * mConstants.LIGHT_IDLE_FACTOR));
if (DEBUG) Slog.d(TAG, "Moved to LIGHT_STATE_IDLE.");
mLightState = LIGHT_STATE_IDLE;
EventLogTags.writeDeviceIdleLight(mLightState, reason);
@@ -3315,7 +3413,7 @@
} else if (mCurLightIdleBudget > mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET) {
mCurLightIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET;
}
- scheduleLightAlarmLocked(mCurLightIdleBudget);
+ scheduleLightAlarmLocked(mCurLightIdleBudget, mConstants.FLEX_TIME_SHORT);
if (DEBUG) Slog.d(TAG,
"Moved from LIGHT_STATE_IDLE to LIGHT_STATE_IDLE_MAINTENANCE.");
mLightState = LIGHT_STATE_IDLE_MAINTENANCE;
@@ -3326,7 +3424,7 @@
// We'd like to do maintenance, but currently don't have network
// connectivity... let's try to wait until the network comes back.
// We'll only wait for another full idle period, however, and then give up.
- scheduleLightAlarmLocked(mNextLightIdleDelay);
+ scheduleLightAlarmLocked(mNextLightIdleDelay, mNextLightIdleDelayFlex / 2);
if (DEBUG) Slog.d(TAG, "Moved to LIGHT_WAITING_FOR_NETWORK.");
mLightState = LIGHT_STATE_WAITING_FOR_NETWORK;
EventLogTags.writeDeviceIdleLight(mLightState, reason);
@@ -3844,40 +3942,75 @@
mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP,
mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);
} else {
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);
+ if (mConstants.USE_WINDOW_ALARMS) {
+ mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ mConstants.FLEX_TIME_SHORT,
+ mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);
+ } else {
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);
+ }
}
}
- void scheduleLightAlarmLocked(long delay) {
- if (DEBUG) Slog.d(TAG, "scheduleLightAlarmLocked(" + delay + ")");
+ void scheduleLightAlarmLocked(long delay, long flex) {
+ if (DEBUG) {
+ Slog.d(TAG, "scheduleLightAlarmLocked(" + delay
+ + (mConstants.USE_WINDOW_ALARMS ? "/" + flex : "") + ")");
+ }
mNextLightAlarmTime = SystemClock.elapsedRealtime() + delay;
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- mNextLightAlarmTime, "DeviceIdleController.light", mLightAlarmListener, mHandler);
+ if (mConstants.USE_WINDOW_ALARMS) {
+ mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP, mNextLightAlarmTime, flex,
+ "DeviceIdleController.light", mLightAlarmListener, mHandler);
+ } else {
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, mNextLightAlarmTime,
+ "DeviceIdleController.light", mLightAlarmListener, mHandler);
+ }
}
private void scheduleMotionRegistrationAlarmLocked() {
if (DEBUG) Slog.d(TAG, "scheduleMotionRegistrationAlarmLocked");
long nextMotionRegistrationAlarmTime =
mInjector.getElapsedRealtime() + mConstants.MOTION_INACTIVE_TIMEOUT / 2;
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextMotionRegistrationAlarmTime,
- "DeviceIdleController.motion_registration", mMotionRegistrationAlarmListener,
- mHandler);
+ if (mConstants.USE_WINDOW_ALARMS) {
+ mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ nextMotionRegistrationAlarmTime, mConstants.MOTION_INACTIVE_TIMEOUT_FLEX,
+ "DeviceIdleController.motion_registration", mMotionRegistrationAlarmListener,
+ mHandler);
+ } else {
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextMotionRegistrationAlarmTime,
+ "DeviceIdleController.motion_registration", mMotionRegistrationAlarmListener,
+ mHandler);
+ }
}
private void scheduleMotionTimeoutAlarmLocked() {
if (DEBUG) Slog.d(TAG, "scheduleMotionAlarmLocked");
long nextMotionTimeoutAlarmTime =
mInjector.getElapsedRealtime() + mConstants.MOTION_INACTIVE_TIMEOUT;
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextMotionTimeoutAlarmTime,
- "DeviceIdleController.motion", mMotionTimeoutAlarmListener, mHandler);
+ if (mConstants.USE_WINDOW_ALARMS) {
+ mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ nextMotionTimeoutAlarmTime,
+ mConstants.MOTION_INACTIVE_TIMEOUT_FLEX,
+ "DeviceIdleController.motion", mMotionTimeoutAlarmListener, mHandler);
+ } else {
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextMotionTimeoutAlarmTime,
+ "DeviceIdleController.motion", mMotionTimeoutAlarmListener, mHandler);
+ }
}
void scheduleSensingTimeoutAlarmLocked(long delay) {
if (DEBUG) Slog.d(TAG, "scheduleSensingAlarmLocked(" + delay + ")");
mNextSensingTimeoutAlarmTime = SystemClock.elapsedRealtime() + delay;
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, mNextSensingTimeoutAlarmTime,
- "DeviceIdleController.sensing", mSensingTimeoutAlarmListener, mHandler);
+ if (mConstants.USE_WINDOW_ALARMS) {
+ mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ mNextSensingTimeoutAlarmTime,
+ mConstants.FLEX_TIME_SHORT,
+ "DeviceIdleController.sensing", mSensingTimeoutAlarmListener, mHandler);
+ } else {
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, mNextSensingTimeoutAlarmTime,
+ "DeviceIdleController.sensing", mSensingTimeoutAlarmListener, mHandler);
+ }
}
private static int[] buildAppIdArray(ArrayMap<String, Integer> systemApps,
@@ -4852,7 +4985,13 @@
if (mNextLightIdleDelay != 0) {
pw.print(" mNextIdleDelay=");
TimeUtils.formatDuration(mNextLightIdleDelay, pw);
- pw.println();
+ if (mConstants.USE_WINDOW_ALARMS) {
+ pw.print(" (flex=");
+ TimeUtils.formatDuration(mNextLightIdleDelayFlex, pw);
+ pw.println(")");
+ } else {
+ pw.println();
+ }
}
if (mNextLightAlarmTime != 0) {
pw.print(" mNextLightAlarmTime=");
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 96d59b8..9bd6c750f 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -4804,6 +4804,16 @@
public static final int HISTORY_FLAG_DISCRETE = 1 << 1;
/**
+ * Flag for querying app op history: assemble attribution chains, and attach the last visible
+ * node in the chain to the start as a proxy info. This only applies to discrete accesses.
+ *
+ * TODO 191512294: Add to @SystemApi
+ *
+ * @hide
+ */
+ public static final int HISTORY_FLAG_GET_ATTRIBUTION_CHAINS = 1 << 2;
+
+ /**
* Flag for querying app op history: get all types of historical access information.
*
* @see #getHistoricalOps(HistoricalOpsRequest, Executor, Consumer)
@@ -4819,7 +4829,8 @@
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, prefix = { "HISTORY_FLAG_" }, value = {
HISTORY_FLAG_AGGREGATE,
- HISTORY_FLAG_DISCRETE
+ HISTORY_FLAG_DISCRETE,
+ HISTORY_FLAG_GET_ATTRIBUTION_CHAINS
})
public @interface OpHistoryFlags {}
@@ -5037,7 +5048,8 @@
* @return This builder.
*/
public @NonNull Builder setHistoryFlags(@OpHistoryFlags int flags) {
- Preconditions.checkFlagsArgument(flags, HISTORY_FLAGS_ALL);
+ Preconditions.checkFlagsArgument(flags,
+ HISTORY_FLAGS_ALL | HISTORY_FLAG_GET_ATTRIBUTION_CHAINS);
mHistoryFlags = flags;
return this;
}
@@ -5290,8 +5302,17 @@
@Nullable String attributionTag, @UidState int uidState, @OpFlags int opFlag,
long discreteAccessTime, long discreteAccessDuration) {
getOrCreateHistoricalUidOps(uid).addDiscreteAccess(opCode, packageName, attributionTag,
- uidState, opFlag, discreteAccessTime, discreteAccessDuration);
- };
+ uidState, opFlag, discreteAccessTime, discreteAccessDuration, null);
+ }
+
+ /** @hide */
+ public void addDiscreteAccess(int opCode, int uid, @NonNull String packageName,
+ @Nullable String attributionTag, @UidState int uidState, @OpFlags int opFlag,
+ long discreteAccessTime, long discreteAccessDuration,
+ @Nullable OpEventProxyInfo proxy) {
+ getOrCreateHistoricalUidOps(uid).addDiscreteAccess(opCode, packageName, attributionTag,
+ uidState, opFlag, discreteAccessTime, discreteAccessDuration, proxy);
+ }
/** @hide */
@@ -5623,9 +5644,10 @@
private void addDiscreteAccess(int opCode, @NonNull String packageName,
@Nullable String attributionTag, @UidState int uidState,
- @OpFlags int flag, long discreteAccessTime, long discreteAccessDuration) {
+ @OpFlags int flag, long discreteAccessTime, long discreteAccessDuration,
+ @Nullable OpEventProxyInfo proxy) {
getOrCreateHistoricalPackageOps(packageName).addDiscreteAccess(opCode, attributionTag,
- uidState, flag, discreteAccessTime, discreteAccessDuration);
+ uidState, flag, discreteAccessTime, discreteAccessDuration, proxy);
};
/**
@@ -5889,9 +5911,9 @@
private void addDiscreteAccess(int opCode, @Nullable String attributionTag,
@UidState int uidState, @OpFlags int flag, long discreteAccessTime,
- long discreteAccessDuration) {
+ long discreteAccessDuration, @Nullable OpEventProxyInfo proxy) {
getOrCreateAttributedHistoricalOps(attributionTag).addDiscreteAccess(opCode, uidState,
- flag, discreteAccessTime, discreteAccessDuration);
+ flag, discreteAccessTime, discreteAccessDuration, proxy);
}
/**
@@ -6212,9 +6234,10 @@
}
private void addDiscreteAccess(int opCode, @UidState int uidState, @OpFlags int flag,
- long discreteAccessTime, long discreteAccessDuration) {
+ long discreteAccessTime, long discreteAccessDuration,
+ @Nullable OpEventProxyInfo proxy) {
getOrCreateHistoricalOp(opCode).addDiscreteAccess(uidState,flag, discreteAccessTime,
- discreteAccessDuration);
+ discreteAccessDuration, proxy);
}
/**
@@ -6583,11 +6606,12 @@
}
private void addDiscreteAccess(@UidState int uidState, @OpFlags int flag,
- long discreteAccessTime, long discreteAccessDuration) {
+ long discreteAccessTime, long discreteAccessDuration,
+ @Nullable OpEventProxyInfo proxy) {
List<AttributedOpEntry> discreteAccesses = getOrCreateDiscreteAccesses();
LongSparseArray<NoteOpEvent> accessEvents = new LongSparseArray<>();
long key = makeKey(uidState, flag);
- NoteOpEvent note = new NoteOpEvent(discreteAccessTime, discreteAccessDuration, null);
+ NoteOpEvent note = new NoteOpEvent(discreteAccessTime, discreteAccessDuration, proxy);
accessEvents.append(key, note);
AttributedOpEntry access = new AttributedOpEntry(mOp, false, accessEvents, null);
int insertionPoint = discreteAccesses.size() - 1;
@@ -10022,6 +10046,8 @@
NoteOpEvent existingAccess = accessEvents.get(key);
if (existingAccess == null || existingAccess.getDuration() == -1) {
accessEvents.append(key, access);
+ } else if (existingAccess.mProxy == null && access.mProxy != null ) {
+ existingAccess.mProxy = access.mProxy;
}
}
if (reject != null) {
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 9ed76c1..a2c9795 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -546,6 +546,10 @@
if (aInfo.sharedLibraryFiles != null) {
int index = 0;
for (String lib : aInfo.sharedLibraryFiles) {
+ // sharedLibraryFiles might contain native shared libraries that are not APK paths.
+ if (!lib.endsWith(".apk")) {
+ continue;
+ }
if (!outSeenPaths.contains(lib) && !outZipPaths.contains(lib)) {
outZipPaths.add(index, lib);
index++;
diff --git a/core/java/android/app/WallpaperColors.java b/core/java/android/app/WallpaperColors.java
index 2777a7a..7ef0a19 100644
--- a/core/java/android/app/WallpaperColors.java
+++ b/core/java/android/app/WallpaperColors.java
@@ -420,7 +420,7 @@
for (Map.Entry<Integer, Integer> colorEntry : mAllColors.entrySet()) {
if (colorEntry.getKey() != null) {
dest.writeInt(colorEntry.getKey());
- Integer population = mAllColors.get(colorEntry.getValue());
+ Integer population = colorEntry.getValue();
int populationInt = (population != null) ? population : 0;
dest.writeInt(populationInt);
}
diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl
index eb4c624..585eb61 100644
--- a/core/java/android/app/usage/IUsageStatsManager.aidl
+++ b/core/java/android/app/usage/IUsageStatsManager.aidl
@@ -68,5 +68,5 @@
void reportUserInteraction(String packageName, int userId);
int getUsageSource();
void forceUsageSourceSettingRead();
- long getLastTimeAnyComponentUsed(String packageName);
+ long getLastTimeAnyComponentUsed(String packageName, String callingPackage);
}
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index e8175c7..ac7a318 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -1287,7 +1287,7 @@
android.Manifest.permission.PACKAGE_USAGE_STATS})
public long getLastTimeAnyComponentUsed(@NonNull String packageName) {
try {
- return mService.getLastTimeAnyComponentUsed(packageName);
+ return mService.getLastTimeAnyComponentUsed(packageName, mContext.getOpPackageName());
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index ded5e6e..5b72b76 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -3054,6 +3054,9 @@
return true;
}
return false;
+ } else if (profile == BluetoothProfile.LE_AUDIO) {
+ BluetoothLeAudio leAudio = new BluetoothLeAudio(context, listener, this);
+ return true;
} else {
return false;
}
@@ -3142,6 +3145,10 @@
case BluetoothProfile.HEARING_AID:
BluetoothHearingAid hearingAid = (BluetoothHearingAid) proxy;
hearingAid.close();
+ break;
+ case BluetoothProfile.LE_AUDIO:
+ BluetoothLeAudio leAudio = (BluetoothLeAudio) proxy;
+ leAudio.close();
}
}
diff --git a/core/java/android/companion/OWNERS b/core/java/android/companion/OWNERS
index da723b3..54b35fc 100644
--- a/core/java/android/companion/OWNERS
+++ b/core/java/android/companion/OWNERS
@@ -1 +1,4 @@
-eugenesusla@google.com
\ No newline at end of file
+ewol@google.com
+evanxinchen@google.com
+guojing@google.com
+svetoslavganov@google.com
\ No newline at end of file
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 37469e9..08f5a8a 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -848,8 +848,10 @@
/**
* Get the highest supported direct report mode rate level of the sensor.
*
- * @return Highest direct report rate level of this sensor. If the sensor does not support
- * direct report mode, this returns {@link SensorDirectChannel#RATE_STOP}.
+ * @return Highest direct report rate level of this sensor. Note that if the app does not have
+ * the {@link android.Manifest.permission#HIGH_SAMPLING_RATE_SENSORS} permission, the highest
+ * direct report rate level is {@link SensorDirectChannel#RATE_NORMAL}. If the sensor
+ * does not support direct report mode, this returns {@link SensorDirectChannel#RATE_STOP}.
* @see SensorDirectChannel#RATE_STOP
* @see SensorDirectChannel#RATE_NORMAL
* @see SensorDirectChannel#RATE_FAST
@@ -1002,9 +1004,11 @@
}
/**
- * @return the minimum delay allowed between two events in microsecond
+ * @return the minimum delay allowed between two events in microseconds
* or zero if this sensor only returns a value when the data it's measuring
- * changes.
+ * changes. Note that if the app does not have the
+ * {@link android.Manifest.permission#HIGH_SAMPLING_RATE_SENSORS} permission, the
+ * minimum delay is capped at 5000 microseconds (200 Hz).
*/
public int getMinDelay() {
return mMinDelay;
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 713b66a..572a8a8 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -46,6 +46,13 @@
* at {@link TriggerEventListener}. {@link Sensor#TYPE_SIGNIFICANT_MOTION}
* is an example of a trigger sensor.
* </p>
+ * <p>
+ * In order to access sensor data at high sampling rates (i.e. greater than 200 Hz
+ * for {@link SensorEventListener} and greater than {@link SensorDirectChannel#RATE_NORMAL}
+ * for {@link SensorDirectChannel}), apps must declare
+ * the {@link android.Manifest.permission#HIGH_SAMPLING_RATE_SENSORS} permission
+ * in their AndroidManifest.xml file.
+ * </p>
* <pre class="prettyprint">
* public class SensorActivity extends Activity implements SensorEventListener {
* private final SensorManager mSensorManager;
diff --git a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
index 2d46a407..e665d0f 100644
--- a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
@@ -208,7 +208,8 @@
FINGERPRINT_ACQUIRED_TOO_FAST,
FINGERPRINT_ACQUIRED_VENDOR,
FINGERPRINT_ACQUIRED_START,
- FINGERPRINT_ACQUIRED_UNKNOWN})
+ FINGERPRINT_ACQUIRED_UNKNOWN,
+ FINGERPRINT_ACQUIRED_IMMOBILE})
@Retention(RetentionPolicy.SOURCE)
@interface FingerprintAcquired {}
@@ -278,6 +279,14 @@
int FINGERPRINT_ACQUIRED_UNKNOWN = 8;
/**
+ * This message may be sent during enrollment if the same area of the finger has already
+ * been captured during this enrollment session. In general, enrolling multiple areas of the
+ * same finger can help against false rejections.
+ * @hide
+ */
+ int FINGERPRINT_ACQUIRED_IMMOBILE = 9;
+
+ /**
* @hide
*/
int FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000;
diff --git a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
index e24332a..5b259f7 100644
--- a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
@@ -212,9 +212,9 @@
*/
private static final class CameraExtensionManagerGlobal {
private static final String TAG = "CameraExtensionManagerGlobal";
- private static final String PROXY_PACKAGE_NAME = "com.android.camera";
+ private static final String PROXY_PACKAGE_NAME = "com.android.cameraextensions";
private static final String PROXY_SERVICE_NAME =
- "com.android.camera.CameraExtensionsProxyService";
+ "com.android.cameraextensions.CameraExtensionsProxyService";
// Singleton instance
private static final CameraExtensionManagerGlobal GLOBAL_CAMERA_MANAGER =
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 688f9f1..0819835 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -1417,6 +1417,9 @@
case FINGERPRINT_ACQUIRED_TOO_FAST:
return context.getString(
com.android.internal.R.string.fingerprint_acquired_too_fast);
+ case FINGERPRINT_ACQUIRED_IMMOBILE:
+ return context.getString(
+ com.android.internal.R.string.fingerprint_acquired_immobile);
case FINGERPRINT_ACQUIRED_VENDOR: {
String[] msgArray = context.getResources().getStringArray(
com.android.internal.R.array.fingerprint_acquired_vendor);
diff --git a/core/java/android/net/VpnManager.java b/core/java/android/net/VpnManager.java
index 662ebb3..5c28553 100644
--- a/core/java/android/net/VpnManager.java
+++ b/core/java/android/net/VpnManager.java
@@ -389,6 +389,10 @@
/**
* Starts a legacy VPN.
+ *
+ * Legacy VPN is deprecated starting from Android S. So this API shouldn't be called if the
+ * initial SDK version of device is Android S+. Otherwise, UnsupportedOperationException will be
+ * thrown.
* @hide
*/
public void startLegacyVpn(VpnProfile profile) {
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index 86cd23d..752ef3e 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -352,6 +352,7 @@
public int hashCode() {
return Objects.hash(
mGatewayConnectionName,
+ mTunnelConnectionParams,
mExposedCapabilities,
Arrays.hashCode(mRetryIntervalsMs),
mMaxMtu);
@@ -365,6 +366,7 @@
final VcnGatewayConnectionConfig rhs = (VcnGatewayConnectionConfig) other;
return mGatewayConnectionName.equals(rhs.mGatewayConnectionName)
+ && mTunnelConnectionParams.equals(rhs.mTunnelConnectionParams)
&& mExposedCapabilities.equals(rhs.mExposedCapabilities)
&& Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs)
&& mMaxMtu == rhs.mMaxMtu;
diff --git a/core/java/android/os/SystemVibrator.java b/core/java/android/os/SystemVibrator.java
index fd8948c..0c3debb1 100644
--- a/core/java/android/os/SystemVibrator.java
+++ b/core/java/android/os/SystemVibrator.java
@@ -26,6 +26,7 @@
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.Objects;
@@ -254,11 +255,14 @@
* <p>This uses the first vibrator on the list as the default one for all hardware spec, but
* uses an intersection of all vibrators to decide the capabilities and effect/primitive
* support.
+ *
+ * @hide
*/
- private static class AllVibratorsInfo extends VibratorInfo {
+ @VisibleForTesting
+ public static class AllVibratorsInfo extends VibratorInfo {
private final VibratorInfo[] mVibratorInfos;
- AllVibratorsInfo(VibratorInfo[] vibrators) {
+ public AllVibratorsInfo(VibratorInfo[] vibrators) {
super(/* id= */ -1, capabilitiesIntersection(vibrators),
vibrators.length > 0 ? vibrators[0] : VibratorInfo.EMPTY_VIBRATOR_INFO);
mVibratorInfos = vibrators;
@@ -266,6 +270,9 @@
@Override
public int isEffectSupported(int effectId) {
+ if (mVibratorInfos.length == 0) {
+ return Vibrator.VIBRATION_EFFECT_SUPPORT_NO;
+ }
int supported = Vibrator.VIBRATION_EFFECT_SUPPORT_YES;
for (VibratorInfo info : mVibratorInfos) {
int effectSupported = info.isEffectSupported(effectId);
@@ -280,6 +287,9 @@
@Override
public boolean isPrimitiveSupported(int primitiveId) {
+ if (mVibratorInfos.length == 0) {
+ return false;
+ }
for (VibratorInfo info : mVibratorInfos) {
if (!info.isPrimitiveSupported(primitiveId)) {
return false;
@@ -288,6 +298,19 @@
return true;
}
+ @Override
+ public int getPrimitiveDuration(int primitiveId) {
+ int maxDuration = 0;
+ for (VibratorInfo info : mVibratorInfos) {
+ int duration = info.getPrimitiveDuration(primitiveId);
+ if (duration == 0) {
+ return 0;
+ }
+ maxDuration = Math.max(maxDuration, duration);
+ }
+ return maxDuration;
+ }
+
private static int capabilitiesIntersection(VibratorInfo[] infos) {
if (infos.length == 0) {
return 0;
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index c5d0cd4..4ef0e6e 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -908,9 +908,32 @@
*/
public static boolean shouldShowPackageForIndicatorCached(@NonNull Context context,
@NonNull String packageName) {
- if (SYSTEM_PKG.equals(packageName)) {
- return false;
+ return !getIndicatorExemptedPackages(context).contains(packageName);
+ }
+
+ /**
+ * Get the list of packages that are not shown by the indicators. Only a select few roles, and
+ * the system app itself, are hidden. These values are updated at most every 15 seconds.
+ * @hide
+ */
+ public static Set<String> getIndicatorExemptedPackages(@NonNull Context context) {
+ updateIndicatorExemptedPackages(context);
+ ArraySet<String> pkgNames = new ArraySet<>();
+ pkgNames.add(SYSTEM_PKG);
+ for (int i = 0; i < INDICATOR_EXEMPTED_PACKAGES.length; i++) {
+ String exemptedPackage = INDICATOR_EXEMPTED_PACKAGES[i];
+ if (exemptedPackage != null) {
+ pkgNames.add(exemptedPackage);
+ }
}
+ return pkgNames;
+ }
+
+ /**
+ * Update the cached indicator exempted packages
+ * @hide
+ */
+ public static void updateIndicatorExemptedPackages(@NonNull Context context) {
long now = SystemClock.elapsedRealtime();
if (sLastIndicatorUpdateTime == -1
|| (now - sLastIndicatorUpdateTime) > EXEMPTED_INDICATOR_ROLE_UPDATE_FREQUENCY_MS) {
@@ -919,14 +942,6 @@
INDICATOR_EXEMPTED_PACKAGES[i] = context.getString(EXEMPTED_ROLES[i]);
}
}
- for (int i = 0; i < EXEMPTED_ROLES.length; i++) {
- String exemptedPackage = INDICATOR_EXEMPTED_PACKAGES[i];
- if (exemptedPackage != null && exemptedPackage.equals(packageName)) {
- return false;
- }
- }
-
- return true;
}
/**
* Gets the list of packages that have permissions that specified
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index d4e548e..791764b 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -410,7 +410,9 @@
int usageAttr = usage.getPackageIdHash();
// If this usage has a proxy, but is not a proxy, it is the end of a chain.
- if (!proxies.containsKey(usageAttr) && usage.proxy != null) {
+ // TODO remove once camera converted
+ if (!proxies.containsKey(usageAttr) && usage.proxy != null
+ && !usage.op.equals(OPSTR_RECORD_AUDIO)) {
proxyLabels.put(usage, new ArrayList<>());
proxyPackages.add(usage.getPackageIdHash());
}
diff --git a/core/java/android/service/contentcapture/ActivityEvent.java b/core/java/android/service/contentcapture/ActivityEvent.java
index 1188a3f..74a7355 100644
--- a/core/java/android/service/contentcapture/ActivityEvent.java
+++ b/core/java/android/service/contentcapture/ActivityEvent.java
@@ -55,12 +55,25 @@
*/
public static final int TYPE_ACTIVITY_DESTROYED = Event.ACTIVITY_DESTROYED;
+ /**
+ * TODO: change to public field.
+ * The activity was started.
+ *
+ * <p>There are some reason, ACTIVITY_START cannot be added into UsageStats. We don't depend on
+ * UsageEvents for Activity start.
+ * </p>
+ *
+ * @hide
+ */
+ public static final int TYPE_ACTIVITY_STARTED = 10000;
+
/** @hide */
@IntDef(prefix = { "TYPE_" }, value = {
TYPE_ACTIVITY_RESUMED,
TYPE_ACTIVITY_PAUSED,
TYPE_ACTIVITY_STOPPED,
- TYPE_ACTIVITY_DESTROYED
+ TYPE_ACTIVITY_DESTROYED,
+ TYPE_ACTIVITY_STARTED
})
@Retention(RetentionPolicy.SOURCE)
public @interface ActivityEventType{}
@@ -86,7 +99,8 @@
* Gets the event type.
*
* @return either {@link #TYPE_ACTIVITY_RESUMED}, {@value #TYPE_ACTIVITY_PAUSED},
- * {@value #TYPE_ACTIVITY_STOPPED}, or {@value #TYPE_ACTIVITY_DESTROYED}.
+ * {@value #TYPE_ACTIVITY_STOPPED}, {@value #TYPE_ACTIVITY_DESTROYED} or 10000 if the Activity
+ * was started.
*/
@ActivityEventType
public int getEventType() {
@@ -104,6 +118,8 @@
return "ACTIVITY_STOPPED";
case TYPE_ACTIVITY_DESTROYED:
return "ACTIVITY_DESTROYED";
+ case TYPE_ACTIVITY_STARTED:
+ return "ACTIVITY_STARTED";
default:
return "UKNOWN_TYPE: " + type;
}
diff --git a/core/java/android/service/voice/HotwordDetectedResult.java b/core/java/android/service/voice/HotwordDetectedResult.java
index 846f2f9..315392b 100644
--- a/core/java/android/service/voice/HotwordDetectedResult.java
+++ b/core/java/android/service/voice/HotwordDetectedResult.java
@@ -20,11 +20,18 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.content.res.Resources;
+import android.media.AudioRecord;
import android.media.MediaSyncEvent;
+import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
+import com.android.internal.R;
import com.android.internal.util.DataClass;
+import com.android.internal.util.Preconditions;
+
+import java.util.Objects;
/**
* Represents a result supporting the hotword detection.
@@ -187,16 +194,20 @@
return new PersistableBundle();
}
+ private static int sMaxBundleSize = -1;
+
/**
* Returns the maximum byte size of the information contained in the bundle.
*
- * <p>The total size will be calculated as a sum of byte sizes over all bundle keys.
- *
- * <p>For example, for a bundle containing a single key: {@code "example_key" -> 42.0f}, the
- * bundle size will be {@code 11 + Float.BYTES = 15} bytes.
+ * <p>The total size will be calculated by how much bundle data should be written into the
+ * Parcel.
*/
public static int getMaxBundleSize() {
- return 50;
+ if (sMaxBundleSize < 0) {
+ sMaxBundleSize = Resources.getSystem().getInteger(
+ R.integer.config_hotwordDetectedResultMaxBundleSize);
+ }
+ return sMaxBundleSize;
}
/**
@@ -212,6 +223,34 @@
return mMediaSyncEvent;
}
+ /**
+ * Returns how many bytes should be written into the Parcel
+ *
+ * @hide
+ */
+ public static int getParcelableSize(@NonNull Parcelable parcelable) {
+ final Parcel p = Parcel.obtain();
+ parcelable.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ final int size = p.dataSize();
+ p.recycle();
+ return size;
+ }
+
+ private void onConstructed() {
+ Preconditions.checkArgumentInRange(mScore, 0, getMaxScore(), "score");
+ Preconditions.checkArgumentInRange(mPersonalizedScore, 0, getMaxScore(),
+ "personalizedScore");
+ Preconditions.checkArgumentInRange(mHotwordPhraseId, 0, getMaxHotwordPhraseId(),
+ "hotwordPhraseId");
+ Preconditions.checkArgumentInRange((long) mHotwordDurationMillis, 0,
+ AudioRecord.getMaxSharedAudioHistoryMillis(), "hotwordDurationMillis");
+ if (!mExtras.isEmpty()) {
+ Preconditions.checkArgumentInRange(getParcelableSize(mExtras), 0, getMaxBundleSize(),
+ "extras");
+ }
+ }
+
// Code below generated by codegen v1.0.23.
@@ -290,7 +329,7 @@
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mExtras);
- // onConstructed(); // You can define this method to get a callback
+ onConstructed();
}
/**
@@ -422,7 +461,7 @@
//noinspection PointlessBooleanExpression
return true
&& mConfidenceLevel == that.mConfidenceLevel
- && java.util.Objects.equals(mMediaSyncEvent, that.mMediaSyncEvent)
+ && Objects.equals(mMediaSyncEvent, that.mMediaSyncEvent)
&& mHotwordOffsetMillis == that.mHotwordOffsetMillis
&& mHotwordDurationMillis == that.mHotwordDurationMillis
&& mAudioChannel == that.mAudioChannel
@@ -430,7 +469,7 @@
&& mScore == that.mScore
&& mPersonalizedScore == that.mPersonalizedScore
&& mHotwordPhraseId == that.mHotwordPhraseId
- && java.util.Objects.equals(mExtras, that.mExtras);
+ && Objects.equals(mExtras, that.mExtras);
}
@Override
@@ -441,7 +480,7 @@
int _hash = 1;
_hash = 31 * _hash + mConfidenceLevel;
- _hash = 31 * _hash + java.util.Objects.hashCode(mMediaSyncEvent);
+ _hash = 31 * _hash + Objects.hashCode(mMediaSyncEvent);
_hash = 31 * _hash + mHotwordOffsetMillis;
_hash = 31 * _hash + mHotwordDurationMillis;
_hash = 31 * _hash + mAudioChannel;
@@ -449,13 +488,13 @@
_hash = 31 * _hash + mScore;
_hash = 31 * _hash + mPersonalizedScore;
_hash = 31 * _hash + mHotwordPhraseId;
- _hash = 31 * _hash + java.util.Objects.hashCode(mExtras);
+ _hash = 31 * _hash + Objects.hashCode(mExtras);
return _hash;
}
@Override
@DataClass.Generated.Member
- public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
@@ -481,7 +520,7 @@
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
@DataClass.Generated.Member
- /* package-private */ HotwordDetectedResult(@NonNull android.os.Parcel in) {
+ /* package-private */ HotwordDetectedResult(@NonNull Parcel in) {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
@@ -512,7 +551,7 @@
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mExtras);
- // onConstructed(); // You can define this method to get a callback
+ onConstructed();
}
@DataClass.Generated.Member
@@ -524,7 +563,7 @@
}
@Override
- public HotwordDetectedResult createFromParcel(@NonNull android.os.Parcel in) {
+ public HotwordDetectedResult createFromParcel(@NonNull Parcel in) {
return new HotwordDetectedResult(in);
}
};
@@ -745,10 +784,10 @@
}
@DataClass.Generated(
- time = 1621943150502L,
+ time = 1624361647985L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/service/voice/HotwordDetectedResult.java",
- inputSignatures = "public static final int CONFIDENCE_LEVEL_NONE\npublic static final int CONFIDENCE_LEVEL_LOW\npublic static final int CONFIDENCE_LEVEL_LOW_MEDIUM\npublic static final int CONFIDENCE_LEVEL_MEDIUM\npublic static final int CONFIDENCE_LEVEL_MEDIUM_HIGH\npublic static final int CONFIDENCE_LEVEL_HIGH\npublic static final int CONFIDENCE_LEVEL_VERY_HIGH\npublic static final int HOTWORD_OFFSET_UNSET\npublic static final int AUDIO_CHANNEL_UNSET\nprivate final @android.service.voice.HotwordDetectedResult.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate @android.annotation.Nullable android.media.MediaSyncEvent mMediaSyncEvent\nprivate int mHotwordOffsetMillis\nprivate int mHotwordDurationMillis\nprivate int mAudioChannel\nprivate boolean mHotwordDetectionPersonalized\nprivate final int mScore\nprivate final int mPersonalizedScore\nprivate final int mHotwordPhraseId\nprivate final @android.annotation.NonNull android.os.PersistableBundle mExtras\nprivate static int defaultConfidenceLevel()\nprivate static int defaultScore()\nprivate static int defaultPersonalizedScore()\npublic static int getMaxScore()\nprivate static int defaultHotwordPhraseId()\npublic static int getMaxHotwordPhraseId()\nprivate static android.os.PersistableBundle defaultExtras()\npublic static int getMaxBundleSize()\npublic @android.annotation.Nullable android.media.MediaSyncEvent getMediaSyncEvent()\nclass HotwordDetectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
+ inputSignatures = "public static final int CONFIDENCE_LEVEL_NONE\npublic static final int CONFIDENCE_LEVEL_LOW\npublic static final int CONFIDENCE_LEVEL_LOW_MEDIUM\npublic static final int CONFIDENCE_LEVEL_MEDIUM\npublic static final int CONFIDENCE_LEVEL_MEDIUM_HIGH\npublic static final int CONFIDENCE_LEVEL_HIGH\npublic static final int CONFIDENCE_LEVEL_VERY_HIGH\npublic static final int HOTWORD_OFFSET_UNSET\npublic static final int AUDIO_CHANNEL_UNSET\nprivate final @android.service.voice.HotwordDetectedResult.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate @android.annotation.Nullable android.media.MediaSyncEvent mMediaSyncEvent\nprivate int mHotwordOffsetMillis\nprivate int mHotwordDurationMillis\nprivate int mAudioChannel\nprivate boolean mHotwordDetectionPersonalized\nprivate final int mScore\nprivate final int mPersonalizedScore\nprivate final int mHotwordPhraseId\nprivate final @android.annotation.NonNull android.os.PersistableBundle mExtras\nprivate static int sMaxBundleSize\nprivate static int defaultConfidenceLevel()\nprivate static int defaultScore()\nprivate static int defaultPersonalizedScore()\npublic static int getMaxScore()\nprivate static int defaultHotwordPhraseId()\npublic static int getMaxHotwordPhraseId()\nprivate static android.os.PersistableBundle defaultExtras()\npublic static int getMaxBundleSize()\npublic @android.annotation.Nullable android.media.MediaSyncEvent getMediaSyncEvent()\npublic static int getParcelableSize(android.os.Parcelable)\nprivate void onConstructed()\nclass HotwordDetectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/service/voice/HotwordDetectionService.java b/core/java/android/service/voice/HotwordDetectionService.java
index 93a7ec7..567ee2f 100644
--- a/core/java/android/service/voice/HotwordDetectionService.java
+++ b/core/java/android/service/voice/HotwordDetectionService.java
@@ -76,6 +76,7 @@
private static final boolean DBG = true;
private static final long UPDATE_TIMEOUT_MILLIS = 5000;
+
/** @hide */
public static final String KEY_INITIALIZATION_STATUS = "initialization_status";
@@ -388,6 +389,14 @@
*/
public void onDetected(@NonNull HotwordDetectedResult result) {
requireNonNull(result);
+ final PersistableBundle persistableBundle = result.getExtras();
+ if (!persistableBundle.isEmpty() && HotwordDetectedResult.getParcelableSize(
+ persistableBundle) > HotwordDetectedResult.getMaxBundleSize()) {
+ throw new IllegalArgumentException(
+ "The bundle size of result is larger than max bundle size ("
+ + HotwordDetectedResult.getMaxBundleSize()
+ + ") of HotwordDetectedResult");
+ }
try {
mRemoteCallback.onDetected(result);
} catch (RemoteException e) {
diff --git a/core/java/android/view/CrossWindowBlurListeners.java b/core/java/android/view/CrossWindowBlurListeners.java
index e307b96..761a2b8 100644
--- a/core/java/android/view/CrossWindowBlurListeners.java
+++ b/core/java/android/view/CrossWindowBlurListeners.java
@@ -73,14 +73,14 @@
return instance;
}
- boolean isCrossWindowBlurEnabled() {
+ public boolean isCrossWindowBlurEnabled() {
synchronized (sLock) {
attachInternalListenerIfNeededLocked();
return mCrossWindowBlurEnabled;
}
}
- void addListener(@NonNull @CallbackExecutor Executor executor,
+ public void addListener(@NonNull @CallbackExecutor Executor executor,
@NonNull Consumer<Boolean> listener) {
Preconditions.checkNotNull(listener, "listener cannot be null");
Preconditions.checkNotNull(executor, "executor cannot be null");
@@ -94,7 +94,7 @@
}
- void removeListener(Consumer<Boolean> listener) {
+ public void removeListener(Consumer<Boolean> listener) {
Preconditions.checkNotNull(listener, "listener cannot be null");
synchronized (sLock) {
diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java
index 85ff93b..1506ee4 100644
--- a/core/java/android/view/InsetsSourceControl.java
+++ b/core/java/android/view/InsetsSourceControl.java
@@ -48,6 +48,7 @@
private Insets mInsetsHint;
private boolean mSkipAnimationOnce;
+ private int mParcelableFlags;
public InsetsSourceControl(@InternalInsetsType int type, @Nullable SurfaceControl leash,
Point surfacePosition, Insets insetsHint) {
@@ -132,6 +133,10 @@
return result;
}
+ public void setParcelableFlags(int parcelableFlags) {
+ mParcelableFlags = parcelableFlags;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -140,9 +145,9 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mType);
- dest.writeTypedObject(mLeash, 0 /* parcelableFlags */);
- dest.writeTypedObject(mSurfacePosition, 0 /* parcelableFlags */);
- dest.writeTypedObject(mInsetsHint, 0 /* parcelableFlags */);
+ dest.writeTypedObject(mLeash, mParcelableFlags);
+ dest.writeTypedObject(mSurfacePosition, mParcelableFlags);
+ dest.writeTypedObject(mInsetsHint, mParcelableFlags);
dest.writeBoolean(mSkipAnimationOnce);
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 573ae99..210f10c 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -5290,7 +5290,16 @@
// b) When loosing control, controller can restore server state by taking last
// dispatched state as truth.
mInsetsController.onStateChanged((InsetsState) args.arg1);
- mInsetsController.onControlsChanged((InsetsSourceControl[]) args.arg2);
+ InsetsSourceControl[] controls = (InsetsSourceControl[]) args.arg2;
+ if (mAdded) {
+ mInsetsController.onControlsChanged(controls);
+ } else if (controls != null) {
+ for (InsetsSourceControl control : controls) {
+ if (control != null) {
+ control.release(SurfaceControl::release);
+ }
+ }
+ }
args.recycle();
break;
}
@@ -8136,6 +8145,10 @@
}
}
+ // If our window is removed, we might not get notified about losing control.
+ // Invoking this can release the leashes as soon as possible instead of relying on GC.
+ mInsetsController.onControlsChanged(null);
+
mAdded = false;
}
WindowManagerGlobal.getInstance().doRemoveView(this);
diff --git a/core/java/android/view/contentcapture/ContentCaptureEvent.java b/core/java/android/view/contentcapture/ContentCaptureEvent.java
index 10ae691..ce6d034 100644
--- a/core/java/android/view/contentcapture/ContentCaptureEvent.java
+++ b/core/java/android/view/contentcapture/ContentCaptureEvent.java
@@ -286,6 +286,15 @@
return this;
}
+ boolean hasSameComposingSpan(@NonNull ContentCaptureEvent other) {
+ return mComposingStart == other.mComposingStart && mComposingEnd == other.mComposingEnd;
+ }
+
+ boolean hasSameSelectionSpan(@NonNull ContentCaptureEvent other) {
+ return mSelectionStartIndex == other.mSelectionStartIndex
+ && mSelectionEndIndex == other.mSelectionEndIndex;
+ }
+
private int getComposingStart() {
return mComposingStart;
}
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index bcb9142..7ec9d34 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -368,7 +368,10 @@
final CharSequence lastText = lastEvent.getText();
final boolean bothNonEmpty = !TextUtils.isEmpty(lastText)
&& !TextUtils.isEmpty(text);
- boolean equalContent = TextUtils.equals(lastText, text);
+ boolean equalContent =
+ TextUtils.equals(lastText, text)
+ && lastEvent.hasSameComposingSpan(event)
+ && lastEvent.hasSameSelectionSpan(event);
if (equalContent) {
addEvent = false;
} else if (bothNonEmpty) {
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index bdd1206..c4540b0 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -163,6 +163,17 @@
}
/**
+ * Called after only the composing region is modified (so it isn't called if the text also
+ * changes).
+ * <p>
+ * Default implementation does nothing.
+ *
+ * @hide
+ */
+ public void endComposingRegionEditInternal() {
+ }
+
+ /**
* Default implementation calls {@link #finishComposingText()} and
* {@code setImeConsumesInput(false)}.
*/
@@ -468,6 +479,7 @@
// Note: sendCurrentText does nothing unless mFallbackMode is set
sendCurrentText();
endBatchEdit();
+ endComposingRegionEditInternal();
}
return true;
}
@@ -734,6 +746,7 @@
// Note: sendCurrentText does nothing unless mFallbackMode is set
sendCurrentText();
endBatchEdit();
+ endComposingRegionEditInternal();
}
return true;
}
diff --git a/core/java/android/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java
index 5ac878d..592993c 100644
--- a/core/java/android/view/translation/UiTranslationController.java
+++ b/core/java/android/view/translation/UiTranslationController.java
@@ -424,7 +424,7 @@
if (callback == null) {
if (view instanceof TextView) {
// developer doesn't provide their override, we set the default TextView
- // implememtation.
+ // implementation.
callback = new TextViewTranslationCallback();
view.setViewTranslationCallback(callback);
} else {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 3c4fd5e..37374ef 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -129,7 +129,6 @@
import android.text.method.TimeKeyListener;
import android.text.method.TransformationMethod;
import android.text.method.TransformationMethod2;
-import android.text.method.TranslationTransformationMethod;
import android.text.method.WordIterator;
import android.text.style.CharacterStyle;
import android.text.style.ClickableSpan;
@@ -199,7 +198,6 @@
import android.view.translation.UiTranslationController;
import android.view.translation.ViewTranslationCallback;
import android.view.translation.ViewTranslationRequest;
-import android.view.translation.ViewTranslationResponse;
import android.widget.RemoteViews.RemoteView;
import com.android.internal.annotations.VisibleForTesting;
@@ -10832,11 +10830,19 @@
}
}
+ notifyContentCaptureTextChanged();
+ }
+
+ /**
+ * Notifies the ContentCapture service that the text of the view has changed (only if
+ * ContentCapture has been notified of this view's existence already).
+ *
+ * @hide
+ */
+ public void notifyContentCaptureTextChanged() {
// TODO(b/121045053): should use a flag / boolean to keep status of SHOWN / HIDDEN instead
// of using isLaidout(), so it's not called in cases where it's laid out but a
// notifyAppeared was not sent.
-
- // ContentCapture
if (isLaidOut() && isImportantForContentCapture() && getNotifiedContentCaptureAppeared()) {
final ContentCaptureManager cm = mContext.getSystemService(ContentCaptureManager.class);
if (cm != null && cm.isContentCaptureEnabled()) {
@@ -13925,8 +13931,8 @@
Log.w(LOG_TAG, "Cannot create translation request. editable = "
+ isTextEditable() + ", isPassword = " + isPassword + ", selectable = "
+ isTextSelectable());
- return;
}
+ return;
}
// TODO(b/176488462): apply the view's important for translation
requestBuilder.setValue(ViewTranslationRequest.ID_TEXT,
@@ -13938,33 +13944,4 @@
}
requestsCollector.accept(requestBuilder.build());
}
-
- /**
- *
- * Called when the content from {@link #onCreateViewTranslationRequest} had been translated by
- * the TranslationService. The default implementation will replace the current
- * {@link TransformationMethod} to transform the original text to the translated text display.
- *
- * @param response a {@link ViewTranslationResponse} that contains the translated information
- * which can be shown in the view.
- */
- @Override
- public void onViewTranslationResponse(@NonNull ViewTranslationResponse response) {
- // set ViewTranslationResponse
- super.onViewTranslationResponse(response);
- // TODO(b/178353965): move to ViewTranslationCallback.onShow()
- ViewTranslationCallback callback = getViewTranslationCallback();
- if (callback instanceof TextViewTranslationCallback) {
- TextViewTranslationCallback textViewDefaultCallback =
- (TextViewTranslationCallback) callback;
- TranslationTransformationMethod oldTranslationMethod =
- textViewDefaultCallback.getTranslationTransformation();
- TransformationMethod originalTranslationMethod = oldTranslationMethod != null
- ? oldTranslationMethod.getOriginalTransformationMethod() : mTransformation;
- TranslationTransformationMethod newTranslationMethod =
- new TranslationTransformationMethod(response, originalTranslationMethod);
- // TODO(b/178353965): well-handle setTransformationMethod.
- textViewDefaultCallback.setTranslationTransformation(newTranslationMethod);
- }
- }
}
diff --git a/core/java/android/widget/TextViewTranslationCallback.java b/core/java/android/widget/TextViewTranslationCallback.java
index a7d5ee4..e1b04f8 100644
--- a/core/java/android/widget/TextViewTranslationCallback.java
+++ b/core/java/android/widget/TextViewTranslationCallback.java
@@ -56,26 +56,6 @@
private CharSequence mContentDescription;
- /**
- * Invoked by the platform when receiving the successful {@link ViewTranslationResponse} for the
- * view that provides the translatable information by {@link View#createTranslationRequest} and
- * sent by the platform.
- */
- void setTranslationTransformation(TranslationTransformationMethod method) {
- if (method == null) {
- if (DEBUG) {
- Log.w(TAG, "setTranslationTransformation: should not set null "
- + "TranslationTransformationMethod");
- }
- return;
- }
- mTranslationTransformation = method;
- }
-
- TranslationTransformationMethod getTranslationTransformation() {
- return mTranslationTransformation;
- }
-
private void clearTranslationTransformation() {
if (DEBUG) {
Log.v(TAG, "clearTranslationTransformation: " + mTranslationTransformation);
@@ -88,34 +68,33 @@
*/
@Override
public boolean onShowTranslation(@NonNull View view) {
- if (view.getViewTranslationResponse() == null) {
- Log.wtf(TAG, "onShowTranslation() shouldn't be called before "
+ ViewTranslationResponse response = view.getViewTranslationResponse();
+ if (response == null) {
+ Log.e(TAG, "onShowTranslation() shouldn't be called before "
+ "onViewTranslationResponse().");
return false;
}
- if (mTranslationTransformation != null) {
- final TransformationMethod transformation = mTranslationTransformation;
- runWithAnimation(
- (TextView) view,
- () -> {
- mIsShowingTranslation = true;
- ((TextView) view).setTransformationMethod(transformation);
- });
- ViewTranslationResponse response = view.getViewTranslationResponse();
- if (response.getKeys().contains(ViewTranslationRequest.ID_CONTENT_DESCRIPTION)) {
- CharSequence translatedContentDescription =
- response.getValue(ViewTranslationRequest.ID_CONTENT_DESCRIPTION).getText();
- if (!TextUtils.isEmpty(translatedContentDescription)) {
- mContentDescription = view.getContentDescription();
- view.setContentDescription(translatedContentDescription);
- }
+ if (mTranslationTransformation == null) {
+ TransformationMethod originalTranslationMethod =
+ ((TextView) view).getTransformationMethod();
+ mTranslationTransformation = new TranslationTransformationMethod(response,
+ originalTranslationMethod);
+ }
+ final TransformationMethod transformation = mTranslationTransformation;
+ runWithAnimation(
+ (TextView) view,
+ () -> {
+ mIsShowingTranslation = true;
+ // TODO(b/178353965): well-handle setTransformationMethod.
+ ((TextView) view).setTransformationMethod(transformation);
+ });
+ if (response.getKeys().contains(ViewTranslationRequest.ID_CONTENT_DESCRIPTION)) {
+ CharSequence translatedContentDescription =
+ response.getValue(ViewTranslationRequest.ID_CONTENT_DESCRIPTION).getText();
+ if (!TextUtils.isEmpty(translatedContentDescription)) {
+ mContentDescription = view.getContentDescription();
+ view.setContentDescription(translatedContentDescription);
}
- } else {
- if (DEBUG) {
- // TODO(b/182433547): remove before S release
- Log.w(TAG, "onShowTranslation(): no translated text.");
- }
- return false;
}
return true;
}
@@ -126,7 +105,7 @@
@Override
public boolean onHideTranslation(@NonNull View view) {
if (view.getViewTranslationResponse() == null) {
- Log.wtf(TAG, "onHideTranslation() shouldn't be called before "
+ Log.e(TAG, "onHideTranslation() shouldn't be called before "
+ "onViewTranslationResponse().");
return false;
}
diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java
index 4a3bf91..148986a 100644
--- a/core/java/android/window/SplashScreenView.java
+++ b/core/java/android/window/SplashScreenView.java
@@ -292,6 +292,7 @@
private SurfaceView createSurfaceView(@NonNull SplashScreenView view) {
final SurfaceView surfaceView = new SurfaceView(view.getContext());
+ surfaceView.setPadding(0, 0, 0, 0);
if (mSurfacePackage == null) {
if (DEBUG) {
Log.d(TAG,
diff --git a/core/java/com/android/internal/os/AppZygoteInit.java b/core/java/com/android/internal/os/AppZygoteInit.java
index 0e83e41..f925afc 100644
--- a/core/java/com/android/internal/os/AppZygoteInit.java
+++ b/core/java/com/android/internal/os/AppZygoteInit.java
@@ -91,7 +91,9 @@
} else {
Constructor<?> ctor = cl.getConstructor();
ZygotePreload preloadObject = (ZygotePreload) ctor.newInstance();
+ Zygote.markOpenedFilesBeforePreload();
preloadObject.doPreload(appInfo);
+ Zygote.allowFilesOpenedByPreload();
}
} catch (ReflectiveOperationException e) {
Log.e(TAG, "AppZygote application preload failed for "
diff --git a/core/java/com/android/internal/os/BatterySipper.java b/core/java/com/android/internal/os/BatterySipper.java
index 4f2f973b..dfd561a 100644
--- a/core/java/com/android/internal/os/BatterySipper.java
+++ b/core/java/com/android/internal/os/BatterySipper.java
@@ -23,7 +23,10 @@
/**
* Contains power usage of an application, system service, or hardware type.
+ *
+ * @deprecated Please use BatteryStatsManager.getBatteryUsageStats instead.
*/
+@Deprecated
public class BatterySipper implements Comparable<BatterySipper> {
@UnsupportedAppUsage
public int userId;
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index b20f50d..608782a 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -59,7 +59,10 @@
*
* The caller must initialize this class as soon as activity object is ready to use (for example, in
* onAttach() for Fragment), call create() in onCreate() and call destroy() in onDestroy().
+ *
+ * @deprecated Please use BatteryStatsManager.getBatteryUsageStats instead.
*/
+@Deprecated
public class BatteryStatsHelper {
static final boolean DEBUG = false;
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 945a6ab..dab3e9f 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -12141,6 +12141,15 @@
}
}
}
+
+ void reset() {
+ idleTimeMs = 0;
+ rxTimeMs = 0;
+ txTimeMs = 0;
+ energy = 0;
+ uidRxBytes.clear();
+ uidTxBytes.clear();
+ }
}
private final BluetoothActivityInfoCache mLastBluetoothActivityInfo
@@ -12167,6 +12176,15 @@
mHasBluetoothReporting = true;
+ if (info.getControllerRxTimeMillis() < mLastBluetoothActivityInfo.rxTimeMs
+ || info.getControllerTxTimeMillis() < mLastBluetoothActivityInfo.txTimeMs
+ || info.getControllerIdleTimeMillis() < mLastBluetoothActivityInfo.idleTimeMs
+ || info.getControllerEnergyUsed() < mLastBluetoothActivityInfo.energy) {
+ // A drop in accumulated Bluetooth stats is a sign of a Bluetooth crash.
+ // Reset the preserved previous snapshot in order to restart accumulating deltas.
+ mLastBluetoothActivityInfo.reset();
+ }
+
final long rxTimeMs =
info.getControllerRxTimeMillis() - mLastBluetoothActivityInfo.rxTimeMs;
final long txTimeMs =
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 0c9dded..e4e28a9 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -500,6 +500,36 @@
}
/**
+ * Scans file descriptors in /proc/self/fd/, stores their metadata from readlink(2)/stat(2) when
+ * available. Saves this information in a global on native side, to be used by subsequent call
+ * to allowFilesOpenedByPreload(). Fatally fails if the FDs are of unsupported type and are not
+ * explicitly allowed. Ignores repeated invocations.
+ *
+ * Inspecting the FDs is more permissive than in forkAndSpecialize() because preload is invoked
+ * earlier and hence needs to allow a few open sockets. The checks in forkAndSpecialize()
+ * enforce that these sockets are closed when forking.
+ */
+ static void markOpenedFilesBeforePreload() {
+ nativeMarkOpenedFilesBeforePreload();
+ }
+
+ private static native void nativeMarkOpenedFilesBeforePreload();
+
+ /**
+ * By scanning /proc/self/fd/ determines file descriptor numbers in this process opened since
+ * the first call to markOpenedFilesBeforePreload(). These FDs are treated as 'owned' by the
+ * custom preload of the App Zygote - the app is responsible for not sharing data with its other
+ * processes using these FDs, including by lseek(2). File descriptor types and file names are
+ * not checked. Changes in FDs recorded by markOpenedFilesBeforePreload() are not expected and
+ * kill the current process.
+ */
+ static void allowFilesOpenedByPreload() {
+ nativeAllowFilesOpenedByPreload();
+ }
+
+ private static native void nativeAllowFilesOpenedByPreload();
+
+ /**
* Installs a seccomp filter that limits setresuid()/setresgid() to the passed-in range
* @param uidGidMin The smallest allowed uid/gid
* @param uidGidMax The largest allowed uid/gid
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 1a23cc1..134b158 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -70,12 +70,12 @@
import android.transition.TransitionManager;
import android.transition.TransitionSet;
import android.util.AndroidRuntimeException;
-import android.view.AttachedSurfaceControl;
import android.util.EventLog;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
import android.util.TypedValue;
+import android.view.AttachedSurfaceControl;
import android.view.ContextThemeWrapper;
import android.view.CrossWindowBlurListeners;
import android.view.Gravity;
@@ -3148,7 +3148,6 @@
if (cb == null || isDestroyed()) {
result = false;
} else {
- sendCloseSystemWindows("search");
int deviceId = event.getDeviceId();
SearchEvent searchEvent = null;
if (deviceId != 0) {
diff --git a/core/java/com/android/internal/util/function/DodecConsumer.java b/core/java/com/android/internal/util/function/DodecConsumer.java
new file mode 100644
index 0000000..b4d2fb9
--- /dev/null
+++ b/core/java/com/android/internal/util/function/DodecConsumer.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util.function;
+
+import java.util.function.Consumer;
+
+
+/**
+ * A 12-argument {@link Consumer}
+ *
+ * @hide
+ */
+public interface DodecConsumer<A, B, C, D, E, F, G, H, I, J, K, L> {
+ void accept(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l);
+}
diff --git a/core/java/com/android/internal/util/function/DodecFunction.java b/core/java/com/android/internal/util/function/DodecFunction.java
new file mode 100644
index 0000000..178b2c1
--- /dev/null
+++ b/core/java/com/android/internal/util/function/DodecFunction.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util.function;
+
+import java.util.function.Function;
+
+/**
+ * A 12-argument {@link Function}
+ *
+ * @hide
+ */
+public interface DodecFunction<A, B, C, D, E, F, G, H, I, J, K, L, R> {
+ R apply(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l);
+}
diff --git a/core/java/com/android/internal/util/function/DodecPredicate.java b/core/java/com/android/internal/util/function/DodecPredicate.java
new file mode 100644
index 0000000..d3a2b85
--- /dev/null
+++ b/core/java/com/android/internal/util/function/DodecPredicate.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util.function;
+
+import java.util.function.Predicate;
+
+/**
+ * A 12-argument {@link Predicate}
+ *
+ * @hide
+ */
+public interface DodecPredicate<A, B, C, D, E, F, G, H, I, J, K, L> {
+ boolean test(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l);
+}
diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambda.java b/core/java/com/android/internal/util/function/pooled/PooledLambda.java
index a60cc0f..f073c1c0 100755
--- a/core/java/com/android/internal/util/function/pooled/PooledLambda.java
+++ b/core/java/com/android/internal/util/function/pooled/PooledLambda.java
@@ -23,6 +23,8 @@
import com.android.internal.util.function.DecConsumer;
import com.android.internal.util.function.DecFunction;
+import com.android.internal.util.function.DodecConsumer;
+import com.android.internal.util.function.DodecFunction;
import com.android.internal.util.function.HeptConsumer;
import com.android.internal.util.function.HeptFunction;
import com.android.internal.util.function.HexConsumer;
@@ -188,7 +190,7 @@
A arg1) {
return acquire(PooledLambdaImpl.sPool,
function, 1, 0, ReturnType.VOID, arg1, null, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -205,7 +207,7 @@
A arg1) {
return acquire(PooledLambdaImpl.sPool,
function, 1, 0, ReturnType.BOOLEAN, arg1, null, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -222,7 +224,7 @@
A arg1) {
return acquire(PooledLambdaImpl.sPool,
function, 1, 0, ReturnType.OBJECT, arg1, null, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -253,7 +255,7 @@
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 1, 0, ReturnType.VOID, arg1, null, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -273,7 +275,7 @@
A arg1, B arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 0, ReturnType.VOID, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -291,7 +293,7 @@
A arg1, B arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 0, ReturnType.BOOLEAN, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -309,7 +311,7 @@
A arg1, B arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 0, ReturnType.OBJECT, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -327,7 +329,7 @@
ArgumentPlaceholder<A> arg1, B arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 1, ReturnType.VOID, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -345,7 +347,7 @@
ArgumentPlaceholder<A> arg1, B arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 1, ReturnType.BOOLEAN, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -364,7 +366,7 @@
ArgumentPlaceholder<A> arg1, B arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 1, ReturnType.BOOLEAN, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -384,7 +386,7 @@
ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.BOOLEAN, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -405,7 +407,7 @@
ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4, E arg5) {
return acquire(PooledLambdaImpl.sPool,
function, 5, 1, ReturnType.BOOLEAN, arg1, arg2, arg3, arg4, arg5, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -423,7 +425,7 @@
ArgumentPlaceholder<A> arg1, B arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 1, ReturnType.OBJECT, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -441,7 +443,7 @@
A arg1, ArgumentPlaceholder<B> arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 1, ReturnType.VOID, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -459,7 +461,7 @@
A arg1, ArgumentPlaceholder<B> arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 1, ReturnType.BOOLEAN, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -477,7 +479,7 @@
A arg1, ArgumentPlaceholder<B> arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 1, ReturnType.OBJECT, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -509,7 +511,7 @@
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 2, 0, ReturnType.VOID, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -530,7 +532,7 @@
A arg1, B arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 0, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -549,7 +551,7 @@
A arg1, B arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 0, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -568,7 +570,7 @@
ArgumentPlaceholder<A> arg1, B arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -587,7 +589,7 @@
ArgumentPlaceholder<A> arg1, B arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -606,7 +608,7 @@
A arg1, ArgumentPlaceholder<B> arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -625,7 +627,7 @@
A arg1, ArgumentPlaceholder<B> arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -644,7 +646,7 @@
A arg1, B arg2, ArgumentPlaceholder<C> arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -663,7 +665,7 @@
A arg1, B arg2, ArgumentPlaceholder<C> arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -696,7 +698,7 @@
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 3, 0, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -718,7 +720,7 @@
A arg1, B arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -738,7 +740,7 @@
A arg1, B arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -758,7 +760,7 @@
ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -778,7 +780,7 @@
ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -798,7 +800,7 @@
A arg1, ArgumentPlaceholder<B> arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -818,7 +820,7 @@
A arg1, ArgumentPlaceholder<B> arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -838,7 +840,7 @@
A arg1, B arg2, ArgumentPlaceholder<C> arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -858,7 +860,7 @@
A arg1, B arg2, ArgumentPlaceholder<C> arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -878,7 +880,7 @@
A arg1, B arg2, C arg3, ArgumentPlaceholder<D> arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -898,7 +900,7 @@
A arg1, B arg2, C arg3, ArgumentPlaceholder<D> arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -932,7 +934,7 @@
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 4, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -955,7 +957,7 @@
A arg1, B arg2, C arg3, D arg4, E arg5) {
return acquire(PooledLambdaImpl.sPool,
function, 5, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -976,7 +978,7 @@
function, A arg1, B arg2, C arg3, D arg4, E arg5) {
return acquire(PooledLambdaImpl.sPool,
function, 5, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -1012,7 +1014,7 @@
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 5, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, null, null, null,
- null, null, null);
+ null, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -1036,7 +1038,7 @@
A arg1, B arg2, C arg3, D arg4, E arg5, F arg6) {
return acquire(PooledLambdaImpl.sPool,
function, 6, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -1058,7 +1060,7 @@
? extends R> function, A arg1, B arg2, C arg3, D arg4, E arg5, F arg6) {
return acquire(PooledLambdaImpl.sPool,
function, 6, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -1095,7 +1097,7 @@
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 6, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, null, null,
- null, null, null);
+ null, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -1120,7 +1122,7 @@
? super G> function, A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7) {
return acquire(PooledLambdaImpl.sPool,
function, 7, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -1144,7 +1146,7 @@
A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7) {
return acquire(PooledLambdaImpl.sPool,
function, 7, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -1182,7 +1184,7 @@
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 7, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, null,
- null, null, null);
+ null, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -1209,7 +1211,7 @@
H arg8) {
return acquire(PooledLambdaImpl.sPool,
function, 8, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -1234,7 +1236,7 @@
A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8) {
return acquire(PooledLambdaImpl.sPool,
function, 8, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -1274,7 +1276,7 @@
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 8, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- null, null, null);
+ null, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -1302,7 +1304,7 @@
E arg5, F arg6, G arg7, H arg8, I arg9) {
return acquire(PooledLambdaImpl.sPool,
function, 9, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- arg9, null, null);
+ arg9, null, null, null);
}
/**
@@ -1328,7 +1330,7 @@
A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9) {
return acquire(PooledLambdaImpl.sPool,
function, 9, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- arg9, null, null);
+ arg9, null, null, null);
}
/**
@@ -1369,7 +1371,7 @@
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 9, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- arg9, null, null);
+ arg9, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -1398,7 +1400,7 @@
D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10) {
return acquire(PooledLambdaImpl.sPool,
function, 10, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- arg9, arg10, null);
+ arg9, arg10, null, null);
}
/**
@@ -1425,7 +1427,7 @@
A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10) {
return acquire(PooledLambdaImpl.sPool,
function, 10, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- arg9, arg10, null);
+ arg9, arg10, null, null);
}
/**
@@ -1467,7 +1469,7 @@
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 10, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
- arg8, arg9, arg10, null);
+ arg8, arg9, arg10, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -1498,7 +1500,7 @@
C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10, K arg11) {
return acquire(PooledLambdaImpl.sPool,
function, 11, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- arg9, arg10, arg11);
+ arg9, arg10, arg11, null);
}
/**
@@ -1528,7 +1530,7 @@
K arg11) {
return acquire(PooledLambdaImpl.sPool,
function, 11, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- arg9, arg10, arg11);
+ arg9, arg10, arg11, null);
}
/**
@@ -1571,7 +1573,118 @@
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 11, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
- arg8, arg9, arg10, arg11);
+ arg8, arg9, arg10, arg11, null);
+ return Message.obtain().setCallback(callback.recycleOnUse());
+ }
+ }
+
+ /**
+ * {@link PooledRunnable} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 parameter supplied to {@code function} on call
+ * @param arg5 parameter supplied to {@code function} on call
+ * @param arg6 parameter supplied to {@code function} on call
+ * @param arg7 parameter supplied to {@code function} on call
+ * @param arg8 parameter supplied to {@code function} on call
+ * @param arg9 parameter supplied to {@code function} on call
+ * @param arg10 parameter supplied to {@code function} on call
+ * @param arg11 parameter supplied to {@code function} on call
+ * @param arg12 parameter supplied to {@code function} on call
+ * @return a {@link PooledRunnable}, equivalent to lambda:
+ * {@code () -> function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10,
+ * arg11, arg12) }
+ */
+ static <A, B, C, D, E, F, G, H, I, J, K, L> PooledRunnable obtainRunnable(
+ DodecConsumer<? super A, ? super B, ? super C, ? super D, ? super E, ? super F,
+ ? super G, ? super H, ? super I, ? super J, ? super K,
+ ? super L> function,
+ A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10,
+ K arg11, L arg12) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 12, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
+ arg9, arg10, arg11, arg12);
+ }
+
+ /**
+ * {@link PooledSupplier} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 parameter supplied to {@code function} on call
+ * @param arg5 parameter supplied to {@code function} on call
+ * @param arg6 parameter supplied to {@code function} on call
+ * @param arg7 parameter supplied to {@code function} on call
+ * @param arg8 parameter supplied to {@code function} on call
+ * @param arg9 parameter supplied to {@code function} on call
+ * @param arg10 parameter supplied to {@code function} on call
+ * @param arg11 parameter supplied to {@code function} on call
+ * @param arg12 parameter supplied to {@code function} on call
+ * @return a {@link PooledSupplier}, equivalent to lambda:
+ * {@code () -> function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10,
+ * arg11) }
+ */
+ static <A, B, C, D, E, F, G, H, I, J, K, L, R> PooledSupplier<R> obtainSupplier(
+ DodecFunction<? super A, ? super B, ? super C, ? super D, ? super E, ? super F,
+ ? super G, ? super H, ? super I, ? super J, ? super K, ? extends L,
+ ? extends R> function,
+ A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10,
+ K arg11, L arg12) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 11, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
+ arg9, arg10, arg11, arg12);
+ }
+
+ /**
+ * Factory of {@link Message}s that contain an
+ * ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its
+ * {@link Message#getCallback internal callback}.
+ *
+ * The callback is equivalent to one obtainable via
+ * {@link #obtainRunnable(QuintConsumer, Object, Object, Object, Object, Object)}
+ *
+ * Note that using this method with {@link android.os.Handler#handleMessage}
+ * is more efficient than the alternative of {@link android.os.Handler#post}
+ * with a {@link PooledRunnable} due to the lack of 2 separate synchronization points
+ * when obtaining {@link Message} and {@link PooledRunnable} from pools separately
+ *
+ * You may optionally set a {@link Message#what} for the message if you want to be
+ * able to cancel it via {@link android.os.Handler#removeMessages}, but otherwise
+ * there's no need to do so
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 parameter supplied to {@code function} on call
+ * @param arg5 parameter supplied to {@code function} on call
+ * @param arg6 parameter supplied to {@code function} on call
+ * @param arg7 parameter supplied to {@code function} on call
+ * @param arg8 parameter supplied to {@code function} on call
+ * @param arg9 parameter supplied to {@code function} on call
+ * @param arg10 parameter supplied to {@code function} on call
+ * @param arg11 parameter supplied to {@code function} on call
+ * @param arg12 parameter supplied to {@code function} on call
+ * @return a {@link Message} invoking {@code function(arg1, arg2, arg3, arg4, arg5, arg6,
+ * arg7, arg8, arg9, arg10, arg11) } when handled
+ */
+ static <A, B, C, D, E, F, G, H, I, J, K, L> Message obtainMessage(
+ DodecConsumer<? super A, ? super B, ? super C, ? super D, ? super E, ? super F,
+ ? super G, ? super H, ? super I, ? super J, ? super K, ? super L> function,
+ A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10,
+ K arg11, L arg12) {
+ synchronized (Message.sPoolSync) {
+ PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
+ function, 11, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
+ arg8, arg9, arg10, arg11, arg12);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java
index 1646a07..19f0816 100755
--- a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java
+++ b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java
@@ -28,6 +28,9 @@
import com.android.internal.util.function.DecConsumer;
import com.android.internal.util.function.DecFunction;
import com.android.internal.util.function.DecPredicate;
+import com.android.internal.util.function.DodecConsumer;
+import com.android.internal.util.function.DodecFunction;
+import com.android.internal.util.function.DodecPredicate;
import com.android.internal.util.function.HeptConsumer;
import com.android.internal.util.function.HeptFunction;
import com.android.internal.util.function.HeptPredicate;
@@ -458,6 +461,28 @@
}
}
} break;
+
+ case 12: {
+ switch (returnType) {
+ case LambdaType.ReturnType.VOID: {
+ ((DodecConsumer) mFunc).accept(popArg(0), popArg(1),
+ popArg(2), popArg(3), popArg(4), popArg(5),
+ popArg(6), popArg(7), popArg(8), popArg(9), popArg(10), popArg(11));
+ return null;
+ }
+ case LambdaType.ReturnType.BOOLEAN: {
+ return (R) (Object) ((DodecPredicate) mFunc).test(popArg(0),
+ popArg(1), popArg(2), popArg(3), popArg(4),
+ popArg(5), popArg(6), popArg(7), popArg(8), popArg(9), popArg(10),
+ popArg(11));
+ }
+ case LambdaType.ReturnType.OBJECT: {
+ return (R) ((DodecFunction) mFunc).apply(popArg(0), popArg(1),
+ popArg(2), popArg(3), popArg(4), popArg(5),
+ popArg(6), popArg(7), popArg(8), popArg(9), popArg(10), popArg(11));
+ }
+ }
+ } break;
}
throw new IllegalStateException("Unknown function type: " + LambdaType.toString(funcType));
}
@@ -523,7 +548,8 @@
*/
static <E extends PooledLambda> E acquire(Pool pool, Object func,
int fNumArgs, int numPlaceholders, int fReturnType, Object a, Object b, Object c,
- Object d, Object e, Object f, Object g, Object h, Object i, Object j, Object k) {
+ Object d, Object e, Object f, Object g, Object h, Object i, Object j, Object k,
+ Object l) {
PooledLambdaImpl r = acquire(pool);
if (DEBUG) {
Log.i(LOG_TAG,
@@ -543,6 +569,7 @@
+ ", i = " + i
+ ", j = " + j
+ ", k = " + k
+ + ", l = " + l
+ ")");
}
r.mFunc = Objects.requireNonNull(func);
@@ -560,6 +587,7 @@
setIfInBounds(r.mArgs, 8, i);
setIfInBounds(r.mArgs, 9, j);
setIfInBounds(r.mArgs, 10, k);
+ setIfInBounds(r.mArgs, 11, l);
return (E) r;
}
diff --git a/core/java/com/android/internal/view/ScrollCaptureViewSupport.java b/core/java/com/android/internal/view/ScrollCaptureViewSupport.java
index 8aa2d57..9e09006 100644
--- a/core/java/com/android/internal/view/ScrollCaptureViewSupport.java
+++ b/core/java/com/android/internal/view/ScrollCaptureViewSupport.java
@@ -198,12 +198,9 @@
private static final float LIGHT_RADIUS_DP = 800;
private static final String TAG = "ViewRenderer";
- private HardwareRenderer mRenderer;
- private RenderNode mCaptureRenderNode;
- private final RectF mTempRectF = new RectF();
- private final Rect mSourceRect = new Rect();
+ private final HardwareRenderer mRenderer;
+ private final RenderNode mCaptureRenderNode;
private final Rect mTempRect = new Rect();
- private final Matrix mTempMatrix = new Matrix();
private final int[] mTempLocation = new int[2];
private long mLastRenderedSourceDrawingId = -1;
private Surface mSurface;
@@ -313,11 +310,9 @@
}
private void transformToRoot(View local, Rect localRect, Rect outRect) {
- mTempMatrix.reset();
- local.transformMatrixToGlobal(mTempMatrix);
- mTempRectF.set(localRect);
- mTempMatrix.mapRect(mTempRectF);
- mTempRectF.round(outRect);
+ local.getLocationInWindow(mTempLocation);
+ outRect.set(localRect);
+ outRect.offset(mTempLocation[0], mTempLocation[1]);
}
public void setColorMode(@ColorMode int colorMode) {
diff --git a/core/java/com/android/internal/widget/CachingIconView.java b/core/java/com/android/internal/widget/CachingIconView.java
index 4a70f74..299cbe1 100644
--- a/core/java/com/android/internal/widget/CachingIconView.java
+++ b/core/java/com/android/internal/widget/CachingIconView.java
@@ -257,7 +257,7 @@
boolean hasColor = color != ColoredIconHelper.COLOR_INVALID;
if (background == null) {
// This is the pre-S style -- colored icon with no background.
- if (hasColor) {
+ if (hasColor && icon != null) {
icon.mutate().setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
}
} else {
@@ -265,7 +265,9 @@
// colorize the icon itself with the background color, creating an inverted effect.
if (hasColor) {
background.mutate().setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
- icon.mutate().setColorFilter(mBackgroundColor, PorterDuff.Mode.SRC_ATOP);
+ if (icon != null) {
+ icon.mutate().setColorFilter(mBackgroundColor, PorterDuff.Mode.SRC_ATOP);
+ }
} else {
background.mutate().setColorFilter(mBackgroundColor, PorterDuff.Mode.SRC_ATOP);
}
diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java
index 3d054a5..02ffe8c 100644
--- a/core/java/com/android/internal/widget/EditableInputConnection.java
+++ b/core/java/com/android/internal/widget/EditableInputConnection.java
@@ -99,6 +99,12 @@
}
@Override
+ public void endComposingRegionEditInternal() {
+ // The ContentCapture service is interested in Composing-state changes.
+ mTextView.notifyContentCaptureTextChanged();
+ }
+
+ @Override
public void closeConnection() {
super.closeConnection();
synchronized(this) {
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 73c5460..3f756d7 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -1524,7 +1524,9 @@
if (virtualViewId != ExploreByTouchHelper.INVALID_ID) {
int row = (virtualViewId - VIRTUAL_BASE_VIEW_ID) / 3;
int col = (virtualViewId - VIRTUAL_BASE_VIEW_ID) % 3;
- return !mPatternDrawLookup[row][col];
+ if (row < 3) {
+ return !mPatternDrawLookup[row][col];
+ }
}
return false;
}
@@ -1570,7 +1572,6 @@
final Rect bounds = mTempRect;
final int row = ordinal / 3;
final int col = ordinal % 3;
- final CellState cell = mCellStates[row][col];
float centerX = getCenterXForColumn(col);
float centerY = getCenterYForRow(row);
float cellheight = mSquareHeight * mHitFactor * 0.5f;
diff --git a/core/java/com/android/server/AppWidgetBackupBridge.java b/core/java/com/android/server/AppWidgetBackupBridge.java
index 7d82d35..8e834a8 100644
--- a/core/java/com/android/server/AppWidgetBackupBridge.java
+++ b/core/java/com/android/server/AppWidgetBackupBridge.java
@@ -47,9 +47,9 @@
: null;
}
- public static void restoreStarting(int userId) {
+ public static void systemRestoreStarting(int userId) {
if (sAppWidgetService != null) {
- sAppWidgetService.restoreStarting(userId);
+ sAppWidgetService.systemRestoreStarting(userId);
}
}
@@ -59,9 +59,9 @@
}
}
- public static void restoreFinished(int userId) {
+ public static void systemRestoreFinished(int userId) {
if (sAppWidgetService != null) {
- sAppWidgetService.restoreFinished(userId);
+ sAppWidgetService.systemRestoreFinished(userId);
}
}
}
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 6976ace..a8dcbaf 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -86,6 +86,7 @@
// and "allow-ignore-location-settings".
private static final int ALLOW_OVERRIDE_APP_RESTRICTIONS = 0x100;
private static final int ALLOW_IMPLICIT_BROADCASTS = 0x200;
+ private static final int ALLOW_VENDOR_APEX = 0x400;
private static final int ALLOW_ALL = ~0;
// property for runtime configuration differentiation
@@ -240,7 +241,7 @@
private final ArraySet<String> mRollbackWhitelistedPackages = new ArraySet<>();
private final ArraySet<String> mWhitelistedStagedInstallers = new ArraySet<>();
- private final ArraySet<String> mAllowedPartnerApexes = new ArraySet<>();
+ private final ArraySet<String> mAllowedVendorApexes = new ArraySet<>();
/**
* Map of system pre-defined, uniquely named actors; keys are namespace,
@@ -411,8 +412,8 @@
return mWhitelistedStagedInstallers;
}
- public Set<String> getAllowedPartnerApexes() {
- return mAllowedPartnerApexes;
+ public Set<String> getAllowedVendorApexes() {
+ return mAllowedVendorApexes;
}
public ArraySet<String> getAppDataIsolationWhitelistedApps() {
@@ -489,7 +490,7 @@
// Vendors are only allowed to customize these
int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS
- | ALLOW_ASSOCIATIONS;
+ | ALLOW_ASSOCIATIONS | ALLOW_VENDOR_APEX;
if (Build.VERSION.DEVICE_INITIAL_SDK_INT <= Build.VERSION_CODES.O_MR1) {
// For backward compatibility
vendorPermissionFlag |= (ALLOW_PERMISSIONS | ALLOW_APP_CONFIGS);
@@ -530,7 +531,8 @@
}
// Allow OEM to customize these
- int oemPermissionFlag = ALLOW_FEATURES | ALLOW_OEM_PERMISSIONS | ALLOW_ASSOCIATIONS;
+ int oemPermissionFlag = ALLOW_FEATURES | ALLOW_OEM_PERMISSIONS | ALLOW_ASSOCIATIONS
+ | ALLOW_VENDOR_APEX;
readPermissions(Environment.buildPath(
Environment.getOemDirectory(), "etc", "sysconfig"), oemPermissionFlag);
readPermissions(Environment.buildPath(
@@ -541,7 +543,8 @@
// the use of hidden APIs from the product partition.
int productPermissionFlag = ALLOW_FEATURES | ALLOW_LIBS | ALLOW_PERMISSIONS
| ALLOW_APP_CONFIGS | ALLOW_PRIVAPP_PERMISSIONS | ALLOW_HIDDENAPI_WHITELISTING
- | ALLOW_ASSOCIATIONS | ALLOW_OVERRIDE_APP_RESTRICTIONS | ALLOW_IMPLICIT_BROADCASTS;
+ | ALLOW_ASSOCIATIONS | ALLOW_OVERRIDE_APP_RESTRICTIONS | ALLOW_IMPLICIT_BROADCASTS
+ | ALLOW_VENDOR_APEX;
if (Build.VERSION.DEVICE_INITIAL_SDK_INT <= Build.VERSION_CODES.R) {
// TODO(b/157393157): This must check product interface enforcement instead of
// DEVICE_INITIAL_SDK_INT for the devices without product interface enforcement.
@@ -668,6 +671,7 @@
(permissionFlag & ALLOW_OVERRIDE_APP_RESTRICTIONS) != 0;
final boolean allowImplicitBroadcasts = (permissionFlag & ALLOW_IMPLICIT_BROADCASTS)
!= 0;
+ final boolean allowVendorApex = (permissionFlag & ALLOW_VENDOR_APEX) != 0;
while (true) {
XmlUtils.nextElement(parser);
if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
@@ -1217,15 +1221,14 @@
}
XmlUtils.skipCurrentTag(parser);
} break;
- case "allowed-partner-apex": {
- // TODO(b/189274479): should this be allowOemPermissions instead?
- if (allowAppConfigs) {
+ case "allowed-vendor-apex": {
+ if (allowVendorApex) {
String pkgName = parser.getAttributeValue(null, "package");
if (pkgName == null) {
Slog.w(TAG, "<" + name + "> without package in " + permFile
+ " at " + parser.getPositionDescription());
} else {
- mAllowedPartnerApexes.add(pkgName);
+ mAllowedVendorApexes.add(pkgName);
}
} else {
logNotAllowedInPartition(name, permFile, parser);
diff --git a/core/java/com/android/server/WidgetBackupProvider.java b/core/java/com/android/server/WidgetBackupProvider.java
index a2efbdd..5453c4d 100644
--- a/core/java/com/android/server/WidgetBackupProvider.java
+++ b/core/java/com/android/server/WidgetBackupProvider.java
@@ -28,7 +28,7 @@
public interface WidgetBackupProvider {
public List<String> getWidgetParticipants(int userId);
public byte[] getWidgetState(String packageName, int userId);
- public void restoreStarting(int userId);
+ public void systemRestoreStarting(int userId);
public void restoreWidgetState(String packageName, byte[] restoredState, int userId);
- public void restoreFinished(int userId);
+ public void systemRestoreFinished(int userId);
}
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 4a1a272..502849e 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -27,9 +27,11 @@
#include <sys/types.h>
#include <dirent.h>
+#include <algorithm>
#include <array>
#include <atomic>
#include <functional>
+#include <iterator>
#include <list>
#include <optional>
#include <sstream>
@@ -2005,6 +2007,9 @@
__builtin_unreachable();
}
+static std::set<int>* gPreloadFds = nullptr;
+static bool gPreloadFdsExtracted = false;
+
// Utility routine to fork a process from the zygote.
pid_t zygote::ForkCommon(JNIEnv* env, bool is_system_server,
const std::vector<int>& fds_to_close,
@@ -2030,9 +2035,12 @@
__android_log_close();
AStatsSocket_close();
- // If this is the first fork for this zygote, create the open FD table. If
- // it isn't, we just need to check whether the list of open files has changed
- // (and it shouldn't in the normal case).
+ // If this is the first fork for this zygote, create the open FD table,
+ // verifying that files are of supported type and allowlisted. Otherwise (not
+ // the first fork), check that the open files have not changed. Newly open
+ // files are not expected, and will be disallowed in the future. Currently
+ // they are allowed if they pass the same checks as in the
+ // FileDescriptorTable::Create() above.
if (gOpenFdTable == nullptr) {
gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore, fail_fn);
} else {
@@ -2128,7 +2136,12 @@
fds_to_ignore.push_back(gSystemServerSocketFd);
}
- pid_t pid = zygote::ForkCommon(env, false, fds_to_close, fds_to_ignore, true);
+ if (gPreloadFds && gPreloadFdsExtracted) {
+ fds_to_ignore.insert(fds_to_ignore.end(), gPreloadFds->begin(), gPreloadFds->end());
+ }
+
+ pid_t pid = zygote::ForkCommon(env, /* is_system_server= */ false, fds_to_close, fds_to_ignore,
+ true);
if (pid == 0) {
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, capabilities, capabilities,
@@ -2265,6 +2278,10 @@
}
fds_to_ignore.push_back(gSystemServerSocketFd);
}
+ if (gPreloadFds && gPreloadFdsExtracted) {
+ fds_to_ignore.insert(fds_to_ignore.end(), gPreloadFds->begin(), gPreloadFds->end());
+ }
+
return zygote::ForkCommon(env, /* is_system_server= */ false, fds_to_close,
fds_to_ignore, is_priority_fork == JNI_TRUE, purge);
}
@@ -2568,6 +2585,35 @@
#endif // defined(__aarch64__)
}
+static void com_android_internal_os_Zygote_nativeMarkOpenedFilesBeforePreload(JNIEnv* env, jclass) {
+ // Ignore invocations when too early or too late.
+ if (gPreloadFds) {
+ return;
+ }
+
+ // App Zygote Preload starts soon. Save FDs remaining open. After the
+ // preload finishes newly open files will be determined.
+ auto fail_fn = std::bind(zygote::ZygoteFailure, env, "zygote", nullptr, _1);
+ gPreloadFds = GetOpenFds(fail_fn).release();
+}
+
+static void com_android_internal_os_Zygote_nativeAllowFilesOpenedByPreload(JNIEnv* env, jclass) {
+ // Ignore invocations when too early or too late.
+ if (!gPreloadFds || gPreloadFdsExtracted) {
+ return;
+ }
+
+ // Find the newly open FDs, if any.
+ auto fail_fn = std::bind(zygote::ZygoteFailure, env, "zygote", nullptr, _1);
+ std::unique_ptr<std::set<int>> current_fds = GetOpenFds(fail_fn);
+ auto difference = std::make_unique<std::set<int>>();
+ std::set_difference(current_fds->begin(), current_fds->end(), gPreloadFds->begin(),
+ gPreloadFds->end(), std::inserter(*difference, difference->end()));
+ delete gPreloadFds;
+ gPreloadFds = difference.release();
+ gPreloadFdsExtracted = true;
+}
+
static const JNINativeMethod gMethods[] = {
{"nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/"
@@ -2616,6 +2662,10 @@
(void*)com_android_internal_os_Zygote_nativeSupportsTaggedPointers},
{"nativeCurrentTaggingLevel", "()I",
(void*)com_android_internal_os_Zygote_nativeCurrentTaggingLevel},
+ {"nativeMarkOpenedFilesBeforePreload", "()V",
+ (void*)com_android_internal_os_Zygote_nativeMarkOpenedFilesBeforePreload},
+ {"nativeAllowFilesOpenedByPreload", "()V",
+ (void*)com_android_internal_os_Zygote_nativeAllowFilesOpenedByPreload},
};
int register_com_android_internal_os_Zygote(JNIEnv* env) {
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 7fa627b..6f5cc53 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -52,7 +52,6 @@
static const char kFdPath[] = "/proc/self/fd";
-// static
FileDescriptorAllowlist* FileDescriptorAllowlist::Get() {
if (instance_ == nullptr) {
instance_ = new FileDescriptorAllowlist();
@@ -169,8 +168,8 @@
// Create a FileDescriptorInfo for a given file descriptor.
static FileDescriptorInfo* CreateFromFd(int fd, fail_fn_t fail_fn);
- // Checks whether the file descriptor associated with this object
- // refers to the same description.
+ // Checks whether the file descriptor associated with this object refers to
+ // the same description.
bool RefersToSameFile() const;
void ReopenOrDetach(fail_fn_t fail_fn) const;
@@ -185,8 +184,10 @@
const bool is_sock;
private:
+ // Constructs for sockets.
explicit FileDescriptorInfo(int fd);
+ // Constructs for non-socket file descriptors.
FileDescriptorInfo(struct stat stat, const std::string& file_path, int fd, int open_flags,
int fd_flags, int fs_flags, off_t offset);
@@ -204,7 +205,6 @@
DISALLOW_COPY_AND_ASSIGN(FileDescriptorInfo);
};
-// static
FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, fail_fn_t fail_fn) {
struct stat f_stat;
// This should never happen; the zygote should always have the right set
@@ -465,42 +465,24 @@
}
}
-// static
+// TODO: Move the definitions here and eliminate the forward declarations. They
+// temporarily help making code reviews easier.
+static int ParseFd(dirent* dir_entry, int dir_fd);
+static std::unique_ptr<std::set<int>> GetOpenFdsIgnoring(const std::vector<int>& fds_to_ignore,
+ fail_fn_t fail_fn);
+
FileDescriptorTable* FileDescriptorTable::Create(const std::vector<int>& fds_to_ignore,
fail_fn_t fail_fn) {
- DIR* proc_fd_dir = opendir(kFdPath);
- if (proc_fd_dir == nullptr) {
- fail_fn(std::string("Unable to open directory ").append(kFdPath));
- }
-
- int dir_fd = dirfd(proc_fd_dir);
- dirent* dir_entry;
-
+ std::unique_ptr<std::set<int>> open_fds = GetOpenFdsIgnoring(fds_to_ignore, fail_fn);
std::unordered_map<int, FileDescriptorInfo*> open_fd_map;
- while ((dir_entry = readdir(proc_fd_dir)) != nullptr) {
- const int fd = ParseFd(dir_entry, dir_fd);
- if (fd == -1) {
- continue;
- }
-
- if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) {
- continue;
- }
-
+ for (auto fd : *open_fds) {
open_fd_map[fd] = FileDescriptorInfo::CreateFromFd(fd, fail_fn);
}
-
- if (closedir(proc_fd_dir) == -1) {
- fail_fn("Unable to close directory");
- }
-
return new FileDescriptorTable(open_fd_map);
}
-void FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore, fail_fn_t fail_fn) {
- std::set<int> open_fds;
-
- // First get the list of open descriptors.
+static std::unique_ptr<std::set<int>> GetOpenFdsIgnoring(const std::vector<int>& fds_to_ignore,
+ fail_fn_t fail_fn) {
DIR* proc_fd_dir = opendir(kFdPath);
if (proc_fd_dir == nullptr) {
fail_fn(android::base::StringPrintf("Unable to open directory %s: %s",
@@ -508,6 +490,7 @@
strerror(errno)));
}
+ auto result = std::make_unique<std::set<int>>();
int dir_fd = dirfd(proc_fd_dir);
dirent* dir_entry;
while ((dir_entry = readdir(proc_fd_dir)) != nullptr) {
@@ -520,14 +503,26 @@
continue;
}
- open_fds.insert(fd);
+ result->insert(fd);
}
if (closedir(proc_fd_dir) == -1) {
fail_fn(android::base::StringPrintf("Unable to close directory: %s", strerror(errno)));
}
+ return result;
+}
- RestatInternal(open_fds, fail_fn);
+std::unique_ptr<std::set<int>> GetOpenFds(fail_fn_t fail_fn) {
+ const std::vector<int> nothing_to_ignore;
+ return GetOpenFdsIgnoring(nothing_to_ignore, fail_fn);
+}
+
+void FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore, fail_fn_t fail_fn) {
+ std::unique_ptr<std::set<int>> open_fds = GetOpenFdsIgnoring(fds_to_ignore, fail_fn);
+
+ // Check that the files did not change, and leave only newly opened FDs in
+ // |open_fds|.
+ RestatInternal(*open_fds, fail_fn);
}
// Reopens all file descriptors that are contained in the table.
@@ -548,6 +543,12 @@
: open_fd_map_(map) {
}
+FileDescriptorTable::~FileDescriptorTable() {
+ for (auto& it : open_fd_map_) {
+ delete it.second;
+ }
+}
+
void FileDescriptorTable::RestatInternal(std::set<int>& open_fds, fail_fn_t fail_fn) {
// ART creates a file through memfd for optimization purposes. We make sure
// there is at most one being created.
@@ -618,8 +619,7 @@
}
}
-// static
-int FileDescriptorTable::ParseFd(dirent* dir_entry, int dir_fd) {
+static int ParseFd(dirent* dir_entry, int dir_fd) {
char* end;
const int fd = strtol(dir_entry->d_name, &end, 10);
if ((*end) != '\0') {
diff --git a/core/jni/fd_utils.h b/core/jni/fd_utils.h
index 14c318e..a28ebf1 100644
--- a/core/jni/fd_utils.h
+++ b/core/jni/fd_utils.h
@@ -69,6 +69,9 @@
DISALLOW_COPY_AND_ASSIGN(FileDescriptorAllowlist);
};
+// Returns the set of file descriptors currently open by the process.
+std::unique_ptr<std::set<int>> GetOpenFds(fail_fn_t fail_fn);
+
// A FileDescriptorTable is a collection of FileDescriptorInfo objects
// keyed by their FDs.
class FileDescriptorTable {
@@ -79,6 +82,14 @@
static FileDescriptorTable* Create(const std::vector<int>& fds_to_ignore,
fail_fn_t fail_fn);
+ ~FileDescriptorTable();
+
+ // Checks that the currently open FDs did not change their metadata from
+ // stat(2), readlink(2) etc. Ignores FDs from |fds_to_ignore|.
+ //
+ // Temporary: allows newly open FDs if they pass the same checks as in
+ // Create(). This will be further restricted. See TODOs in the
+ // implementation.
void Restat(const std::vector<int>& fds_to_ignore, fail_fn_t fail_fn);
// Reopens all file descriptors that are contained in the table. Returns true
@@ -91,8 +102,6 @@
void RestatInternal(std::set<int>& open_fds, fail_fn_t fail_fn);
- static int ParseFd(dirent* e, int dir_fd);
-
// Invariant: All values in this unordered_map are non-NULL.
std::unordered_map<int, FileDescriptorInfo*> open_fd_map_;
diff --git a/core/proto/android/server/apphibernationservice.proto b/core/proto/android/server/apphibernationservice.proto
index d341c4b..64c2a32 100644
--- a/core/proto/android/server/apphibernationservice.proto
+++ b/core/proto/android/server/apphibernationservice.proto
@@ -39,4 +39,5 @@
message GlobalLevelHibernationStateProto {
optional string package_name = 1;
optional bool hibernated = 2;
+ optional int64 saved_byte = 3;
}
\ No newline at end of file
diff --git a/core/res/res/layout/splash_screen_view.xml b/core/res/res/layout/splash_screen_view.xml
index e6d724f..0b7b49c 100644
--- a/core/res/res/layout/splash_screen_view.xml
+++ b/core/res/res/layout/splash_screen_view.xml
@@ -18,12 +18,15 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
+ android:padding="0dp"
android:orientation="vertical">
<View android:id="@+id/splashscreen_icon_view"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_gravity="center"
+ android:padding="0dp"
+ android:background="@null"
android:contentDescription="@string/splash_screen_view_icon_description"/>
<View android:id="@+id/splashscreen_branding_view"
@@ -31,6 +34,8 @@
android:layout_width="wrap_content"
android:layout_gravity="center_horizontal|bottom"
android:layout_marginBottom="60dp"
+ android:padding="0dp"
+ android:background="@null"
android:contentDescription="@string/splash_screen_view_branding_description"/>
</android.window.SplashScreenView>
\ No newline at end of file
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index cd89318..a285cf7 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Probeer \'n ander vingerafdruk"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Te helder"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Probeer om dit te verstel"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Verander elke keer die posisie van jou vinger so effens"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Vingerafdruk is gestaaf"</string>
@@ -601,8 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Geen vingerafdrukke is geregistreer nie."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Hierdie toetstel het nie \'n vingerafdruksensor nie."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor is tydelik gedeaktiveer."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sensor benodig kalibrering"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Vinger <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Gebruik vingerafdruk"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Gebruik vingerafdruk of skermslot"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index b261c46..71a07f3 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"ሌላ የጣት አሻራ ይሞክሩ"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"በጣም ብርሃናማ"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"ለማስተካከል ይሞክሩ"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"የጣት አሻራ ትክክለኛነት ተረጋግጧል"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ምንም የጣት አሻራዎች አልተመዘገቡም።"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ይህ መሣሪያ የጣት አሻራ ዳሳሽ የለውም።"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ዳሳሽ ለጊዜው ተሰናክሏል።"</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"ዳሳሽ ማስተካከልን ይፈልጋል"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"ጣት <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"የጣት አሻራ ይጠቀሙ"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"የጣት አሻራ ወይም የማያ ገጽ መቆለፊያ ይጠቀሙ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index b38bf9f..661001b 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -597,6 +597,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"يمكنك تجربة بصمة إصبع أخرى."</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"الصورة ساطعة للغاية."</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"حاوِل تعديل بصمة الإصبع."</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"تم مصادقة بصمة الإصبع"</string>
@@ -613,8 +615,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ليست هناك بصمات إصبع مسجَّلة."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"لا يحتوي هذا الجهاز على مستشعِر بصمات إصبع."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"تم إيقاف جهاز الاستشعار مؤقتًا."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"يحتاج المستشعر إلى المعايرة."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"الإصبع <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"استخدام بصمة الإصبع"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"استخدام بصمة الإصبع أو قفل الشاشة"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 846fb2c..15190e7 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"অন্য এটা ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰি চাওক"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"অতি উজ্জ্বল"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"মিলাই চাওক"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ফিংগাৰপ্ৰিণ্টৰ সত্যাপন কৰা হ’ল"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"কোনো ফিংগাৰপ্ৰিণ্ট যোগ কৰা নহ\'ল।"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"এই ডিভাইচটোত ফিংগাৰপ্ৰিণ্ট ছেন্সৰ নাই।"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ছেন্সৰটো সাময়িকভাৱে অক্ষম হৈ আছে।"</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"ছেন্সৰৰ কেলিব্ৰেশ্বনৰ প্ৰয়োজন"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g> আঙুলি"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰক"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"ফিংগাৰপ্ৰিণ্ট অথবা স্ক্ৰীন লক ব্যৱহাৰ কৰক"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 6b4736f..25ae576 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Başqa bir barmaq izini sınayın"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Çox işıqlıdır"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Tənzimləməyə çalışın"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Barmaq izi doğrulandı"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Barmaq izi qeydə alınmayıb."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Bu cihazda barmaq izi sensoru yoxdur."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor müvəqqəti deaktivdir."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sensor tənzimlənməlidir"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Barmaq <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Barmaq izini istifadə edin"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Barmaq izi və ya ekran kilidindən istifadə edin"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 5fcd2df..ff17bab 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -588,6 +588,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Probajte sa drugim otiskom prsta"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Previše je svetlo"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Probajte da prilagodite"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Svaki put lagano promenite položaj prsta"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Otisak prsta je potvrđen"</string>
@@ -604,8 +605,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nije registrovan nijedan otisak prsta."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ovaj uređaj nema senzor za otisak prsta."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je privremeno onemogućen."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Senzor treba da se kalibriše"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Koristite otisak prsta"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Koristite otisak prsta ili zaključavanje ekrana"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 1af3ddd..a3eebb6 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -591,6 +591,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Паспрабуйце іншы адбітак пальца"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Занадта светла"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Паспрабуйце наладзіць"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Адбітак пальца распазнаны"</string>
@@ -607,8 +609,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Адбіткі пальцаў не зарэгістраваны."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"На гэтай прыладзе няма сканера адбіткаў пальцаў."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Датчык часова выключаны."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Патрабуецца каліброўка датчыка"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Палец <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Выкарыстоўваць адбітак пальца"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Выкарыстоўваць адбітак пальца ці блакіроўку экрана"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index b3722ab..38fdc499 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Опитайте с друг отпечатък"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Твърде светло е"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Опитайте да коригирате"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Отпечатъкът е удостоверен"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Няма регистрирани отпечатъци."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Това устройство няма сензор за отпечатъци."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сензорът е временно деактивиран."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"За сензора се изисква калибриране"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Пръст <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Използване на отпечатък"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Използване на отпечатък или опцията за заключване на екрана"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 69ddbb4..16ab224 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"অন্য আঙ্গুলের ছাপ দিয়ে চেষ্টা করুন"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"অত্যন্ত উজ্জ্বল"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"অ্যাডজাস্ট করার চেষ্টা করুন"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"আঙ্গুলের ছাপ যাচাই করা হয়েছে"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 74da24a..474e861 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -352,7 +352,7 @@
<string name="permdesc_expandStatusBar" msgid="7180756900448498536">"Dozvoljava aplikaciji proširivanje ili sužavanje statusne trake."</string>
<string name="permlab_fullScreenIntent" msgid="4310888199502509104">"prikaz obavještenja kao aktivnosti preko cijelog ekrana na zaključanom uređaju"</string>
<string name="permdesc_fullScreenIntent" msgid="1100721419406643997">"Dozvoljava aplikaciji da prikazuje obavještenja kao aktivnosti preko cijelog ekrana na zaključanom uređaju"</string>
- <string name="permlab_install_shortcut" msgid="7451554307502256221">"instaliranje prečica"</string>
+ <string name="permlab_install_shortcut" msgid="7451554307502256221">"Instaliranje prečica"</string>
<string name="permdesc_install_shortcut" msgid="4476328467240212503">"Omogućava aplikaciji dodavanje prečice za početni ekran bez intervencije korisnika."</string>
<string name="permlab_uninstall_shortcut" msgid="295263654781900390">"uklanjanje prečica"</string>
<string name="permdesc_uninstall_shortcut" msgid="1924735350988629188">"Omogućava aplikaciji uklanjanje prečice početnog ekrana bez intervencije korisnika."</string>
@@ -588,6 +588,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Pokušajte s drugim otiskom prsta"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Presvijetlo"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Pokušajte podesiti"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Svaki put lagano promijenite položaj prsta"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Otisak prsta je potvrđen"</string>
@@ -604,8 +605,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nije prijavljen nijedan otisak prsta."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ovaj uređaj nema senzor za otisak prsta."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je privremeno onemogućen."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Potrebno je kalibrirati senzor"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Koristi otisak prsta"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Koristi otisak prsta ili zaključavanje ekrana"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 03e7ef2..3afb3cb 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Prova una altra empremta digital"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Hi ha massa llum"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Prova d\'ajustar l\'empremta digital"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"L\'empremta digital s\'ha autenticat"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No s\'ha registrat cap empremta digital."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Aquest dispositiu no té sensor d\'empremtes digitals."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"El sensor està desactivat temporalment."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Cal calibrar el sensor"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Dit <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Utilitza l\'empremta digital"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Utilitza l\'empremta digital o el bloqueig de pantalla"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index bfd5634..07d1060 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -355,7 +355,7 @@
<string name="permdesc_expandStatusBar" msgid="7180756900448498536">"Umožňuje aplikaci rozbalit či sbalit stavový řádek."</string>
<string name="permlab_fullScreenIntent" msgid="4310888199502509104">"zobrazovat oznámení na celé obrazovce zamčeného zařízení"</string>
<string name="permdesc_fullScreenIntent" msgid="1100721419406643997">"Umožňuje aplikaci zobrazovat oznámení na celé obrazovce zamčeného zařízení"</string>
- <string name="permlab_install_shortcut" msgid="7451554307502256221">"instalace zástupců"</string>
+ <string name="permlab_install_shortcut" msgid="7451554307502256221">"Instalace zástupců"</string>
<string name="permdesc_install_shortcut" msgid="4476328467240212503">"Umožňuje aplikaci přidat zástupce na plochu bez zásahu uživatele."</string>
<string name="permlab_uninstall_shortcut" msgid="295263654781900390">"odinstalace zástupců"</string>
<string name="permdesc_uninstall_shortcut" msgid="1924735350988629188">"Umožňuje aplikaci odebrat zástupce z plochy bez zásahu uživatele."</string>
@@ -591,6 +591,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Zkuste jiný otisk prstu"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Je příliš světlo"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Zkuste provést úpravu"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Otisk byl ověřen"</string>
@@ -607,8 +609,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nejsou zaregistrovány žádné otisky prstů."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Toto zařízení nemá snímač otisků prstů."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je dočasně deaktivován."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Snímač vyžaduje kalibraci"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Použít otisk prstu"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Použít otisk prstu nebo zámek obrazovky"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 4231048..1099af6 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Prøv med et andet fingeraftryk"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Der er for lyst"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Prøv at justere den"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingeraftrykket blev godkendt"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Der er ikke registreret nogen fingeraftryk."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Denne enhed har ingen fingeraftrykslæser."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensoren er midlertidigt deaktiveret."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sensoren skal kalibreres"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Fingeraftryk <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Brug fingeraftryk"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Brug fingeraftryk eller skærmlås"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 7a75eea..000d93a 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Anderen Fingerabdruck verwenden"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Zu hell"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Versuche, den Finger anders aufzulegen"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingerabdruck wurde authentifiziert"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 523cde1..0dec36b 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Δοκιμάστε άλλο δακτυλικό αποτύπωμα"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Υπερβολικά έντονος φωτισμός"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Δοκιμάστε να το προσαρμόσετε"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Η ταυτότητα του δακτυλικού αποτυπώματος ελέγχθηκε"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Δεν έχουν καταχωριστεί δακτυλικά αποτυπώματα."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Αυτή η συσκευή δεν διαθέτει αισθητήρα δακτυλικού αποτυπώματος."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Ο αισθητήρας απενεργοποιήθηκε προσωρινά."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Ο αισθητήρας απαιτεί βαθμονόμηση"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Δάχτυλο <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Χρήση δακτυλικού αποτυπώματος"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Χρήση δακτυλικού αποτυπώματος ή κλειδώματος οθόνης"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index b2eaab0..dc7528b 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Try another fingerprint"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Too bright"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Try adjusting"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Change the position of your finger slightly each time"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingerprint authenticated"</string>
@@ -601,8 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No fingerprints enrolled."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor temporarily disabled."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sensor needs calibration"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Use fingerprint"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Use fingerprint or screen lock"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 0a257f4..db3d9f5 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Try another fingerprint"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Too bright"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Try adjusting"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Change the position of your finger slightly each time"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingerprint authenticated"</string>
@@ -601,8 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No fingerprints enrolled."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor temporarily disabled."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sensor needs calibration"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Use fingerprint"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Use fingerprint or screen lock"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 5eca8a68..c2ca314 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Try another fingerprint"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Too bright"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Try adjusting"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Change the position of your finger slightly each time"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingerprint authenticated"</string>
@@ -601,8 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No fingerprints enrolled."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor temporarily disabled."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sensor needs calibration"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Use fingerprint"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Use fingerprint or screen lock"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 74d32d4..994946f 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Try another fingerprint"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Too bright"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Try adjusting"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Change the position of your finger slightly each time"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingerprint authenticated"</string>
@@ -601,8 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No fingerprints enrolled."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor temporarily disabled."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sensor needs calibration"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Use fingerprint"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Use fingerprint or screen lock"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 385608f..2fe89de 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Try another fingerprint"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Too bright"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Try adjusting"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Change the position of your finger slightly each time"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingerprint authenticated"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index fafb766..e20574c 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Prueba con otra huella dactilar"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Demasiada luz"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Prueba ajustarla"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Cambia un poco la posición del dedo cada vez"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Se autenticó la huella dactilar"</string>
@@ -601,8 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No se registraron huellas digitales."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo no tiene sensor de huellas dactilares."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Se inhabilitó temporalmente el sensor."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Se debe calibrar el sensor"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Usar huella digital"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Usar bloqueo de huella dactilar o pantalla"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 3468da5..03d8529 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Prueba con otra huella digital"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Demasiada luz"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Prueba a mover el dedo"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Se ha autenticado la huella digital"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No se ha registrado ninguna huella digital."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo no tiene sensor de huellas digitales."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"El sensor está inhabilitado en estos momentos."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Hace falta calibrar el sensor"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Usar huella digital"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Usar huella digital o bloqueo de pantalla"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 0a60d66..efac8bc 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -349,7 +349,7 @@
<string name="permdesc_expandStatusBar" msgid="7180756900448498536">"Võimaldab rakendusel laiendada või ahendada olekuriba."</string>
<string name="permlab_fullScreenIntent" msgid="4310888199502509104">"Kuva märguanded lukustatud seadmes täisekraantegevustena"</string>
<string name="permdesc_fullScreenIntent" msgid="1100721419406643997">"Lubab rakendusel märguandeid lukustatud seadmes täisekraantegevustena kuvada"</string>
- <string name="permlab_install_shortcut" msgid="7451554307502256221">"otseteede installimine"</string>
+ <string name="permlab_install_shortcut" msgid="7451554307502256221">"Otseteede installimine"</string>
<string name="permdesc_install_shortcut" msgid="4476328467240212503">"Lubab rakendusel lisada avakuva otseteid ilma kasutaja sekkumiseta."</string>
<string name="permlab_uninstall_shortcut" msgid="295263654781900390">"otseteede desinstallimine"</string>
<string name="permdesc_uninstall_shortcut" msgid="1924735350988629188">"Lubab rakendusel eemaldada avakuva otseteid ilma kasutaja sekkumiseta."</string>
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Proovige teist sõrmejälge"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Liiga ere"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Proovige kohandada"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Sõrmejälg autenditi"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ühtegi sõrmejälge pole registreeritud."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Selles seadmes pole sõrmejäljeandurit."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Andur on ajutiselt keelatud."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Andurit on vaja kalibreerida"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Sõrmejälg <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Sõrmejälje kasutamine"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Sõrmejälje või ekraaniluku kasutamine"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index e36cc32..708d7d6 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Erabili beste hatz-marka bat"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Argi gehiegi dago"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Saiatu doituta"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Autentifikatu da hatz-marka"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ez da erregistratu hatz-markarik."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Gailu honek ez du hatz-marken sentsorerik."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sentsorea aldi baterako desgaitu da."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sentsorea kalibratu egin behar da"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>. hatza"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Erabili hatz-marka"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Erabili hatz-marka edo pantailaren blokeoa"</string>
@@ -1055,8 +1056,8 @@
<string name="last_month" msgid="1528906781083518683">"Azken hilabetea"</string>
<string name="older" msgid="1645159827884647400">"Zaharragoa"</string>
<string name="preposition_for_date" msgid="2780767868832729599">"<xliff:g id="DATE">%s</xliff:g>"</string>
- <string name="preposition_for_time" msgid="4336835286453822053">"ordua: <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="preposition_for_year" msgid="3149809685340130039">"urtea: <xliff:g id="YEAR">%s</xliff:g>"</string>
+ <string name="preposition_for_time" msgid="4336835286453822053">"<xliff:g id="TIME">%s</xliff:g>"</string>
+ <string name="preposition_for_year" msgid="3149809685340130039">"<xliff:g id="YEAR">%s</xliff:g>"</string>
<string name="day" msgid="8394717255950176156">"egun"</string>
<string name="days" msgid="4570879797423034973">"egun"</string>
<string name="hour" msgid="7796325297097314653">"ordu"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index add623a..0667fed 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"اثر انگشت دیگری را امتحان کنید"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"خیلی روشن است"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"اثر انگشت را تنظیم کنید"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"اثر انگشت اصالتسنجی شد"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"اثر انگشتی ثبت نشده است."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"این دستگاه حسگر اثر انگشت ندارد."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"حسگر بهطور موقت غیرفعال است."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"حسگر به واسنجی نیاز دارد"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"انگشت <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"استفاده از اثر انگشت"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"استفاده از اثر انگشت یا قفل صفحه"</string>
@@ -908,12 +909,12 @@
<string name="lockscreen_sim_puk_locked_instructions" msgid="5307979043730860995">"لطفاً به راهنمای کاربر مراجعه کرده یا با مرکز پشتیبانی از مشتریان تماس بگیرید."</string>
<string name="lockscreen_sim_locked_message" msgid="3160196135801185938">"سیم کارت قفل شد."</string>
<string name="lockscreen_sim_unlock_progress_dialog_message" msgid="2286497117428409709">"بازگشایی قفل سیم کارت…"</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6458790975898594240">"الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدهاید. \n\nپس از <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6458790975898594240">"الگوی بازگشایی قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدهاید. \n\nپساز <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="3118353451602377380">"گذرواژهٔ خود را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه تایپ کردهاید. \n\nپس از <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="2874278239714821984">"پین را<xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه تایپ کردهاید. \n\nپس از <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="3069635524964070596">"شما الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدهاید. بعد از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته میشود که برای بازگشایی قفل رایانهٔ لوحی خود به Google وارد شوید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="6399092175942158529">"<xliff:g id="NUMBER_0">%1$d</xliff:g> بار الگوی بازگشاییتان را اشتباه کشیدهاید. اگر <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر داشته باشید، از شما خواسته میشود با اطلاعات ورود به سیستم Google خود، قفل دستگاه Android TV را باز کنید.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دیگر دوباره امتحان کنید."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="5691623136957148335">"الگوی قفلگشایی را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدهاید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر از شما خواسته میشود که برای بازگشایی قفل گوشی خود به برنامه Google وارد شوید.\n\n پس از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="3069635524964070596">"الگوی بازگشایی قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدهاید. بعداز <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته میشود که برای بازگشایی قفل رایانهٔ لوحیتان به Google وارد شوید.\n\n لطفاً پساز <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="6399092175942158529">"الگوی بازگشایی قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدهاید. اگر <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر داشته باشید، از شما خواسته میشود با اطلاعات ورود به سیستم Google خود، قفل دستگاه Android TV را باز کنید.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دیگر دوباره امتحان کنید."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="5691623136957148335">"الگوی بازگشایی قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدهاید. پساز <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر، از شما خواسته میشود که برای بازگشایی قفل گوشی به برنامه Google وارد شوید.\n\n پساز <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="7914445759242151426">"شما به اشتباه <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اقدام به باز کردن قفل رایانهٔ لوحی کردهاید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر، رایانهٔ لوحی به پیشفرض کارخانه بازنشانی میشود و تمام دادههای کاربر از دست خواهد رفت."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="4275591249631864248">"<xliff:g id="NUMBER_0">%1$d</xliff:g> تلاش ناموفق برای باز کردن قفل Android TV خود داشتهاید. اگر <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر داشته باشید، دستگاه Android TV شما به تنظیمات پیشفرض کارخانه بازنشانی خواهد شد و همه دادههای کاربر ازدست خواهد رفت."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="1166532464798446579">"شما به اشتباه <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اقدام به باز کردن قفل تلفن کردهاید. پس از<xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر، تلفن به پیشفرض کارخانه بازنشانی میشود و تمام دادههای کاربر از دست خواهد رفت."</string>
@@ -1671,16 +1672,16 @@
<string name="kg_login_checking_password" msgid="4676010303243317253">"درحال بررسی حساب..."</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="23741434207544038">"پین خود را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه تایپ کردید. \n\nپس از <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="3328686432962224215">"گذرواژه خود را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه تایپ کردید. \n\nپس از <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="7357404233979139075">"الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدید. \n\nلطفاً پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="7357404233979139075">"الگوی بازگشایی قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدهاید. \n\nلطفاً پساز <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="3479940221343361587">"شما به اشتباه <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اقدام به باز کردن قفل رایانه لوحی کردهاید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر، رایانهٔ لوحی به پیشفرض کارخانه بازنشانی میشود و تمام دادههای کاربر از دست خواهد رفت."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="9064457748587850217">"<xliff:g id="NUMBER_0">%1$d</xliff:g> تلاش ناموفق برای باز کردن قفل Android TV خود داشتهاید. اگر <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر داشته باشید، دستگاه Android TV شما به تنظیمات پیشفرض کارخانه بازنشانی خواهد شد و همه دادههای کاربر ازدست خواهد رفت."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="5955398963754432548">"شما به اشتباه <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اقدام به باز کردن قفل تلفن کردهاید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر، تلفن به پیشفرض کارخانه بازنشانی میشود و تمام دادههای کاربر از دست خواهد رفت."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2299099385175083308">"شما به اشتباه <xliff:g id="NUMBER">%d</xliff:g> بار اقدام به باز کردن قفل رایانه لوحی کردهاید. رایانه لوحی اکنون به پیشفرض کارخانه بازنشانی میشود."</string>
<string name="kg_failed_attempts_now_wiping" product="tv" msgid="5045460916106267585">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل Android TV خود داشتهاید. اکنون دستگاه Android TV شما به تنظیمات پیشفرض کارخانه بازنشانی میشود."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="5043730590446071189">"شما به اشتباه <xliff:g id="NUMBER">%d</xliff:g> بار اقدام به باز کردن قفل تلفن کردهاید. این تلفن اکنون به پیشفرض کارخانه بازنشانی میشود."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="7086799295109717623">"شما الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدهاید. بعد از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته میشود که با استفاده از یک حساب ایمیل قفل رایانه لوحی خود را باز کنید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4670840383567106114">"<xliff:g id="NUMBER_0">%1$d</xliff:g> بار الگوی بازگشاییتان را اشتباه کشیدهاید. اگر <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر داشته باشید، از شما خواسته میشود بااستفاده از حساب ایمیل خود، قفل دستگاه Android TV را باز کنید.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دیگر دوباره امتحان کنید."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"شما الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدهاید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته میشود که با استفاده از یک حساب ایمیل قفل تلفن خود را باز کنید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="7086799295109717623">"الگوی بازگشایی قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدهاید. بعداز <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته میشود که بااستفاده از یک حساب ایمیل قفل رایانه لوحیتان را باز کنید.\n\n لطفاً پساز <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4670840383567106114">"الگوی بازگشایی قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدهاید. اگر <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر داشته باشید، از شما خواسته میشود بااستفاده از حساب ایمیلتان، قفل دستگاه Android TV را باز کنید.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دیگر دوباره امتحان کنید."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"الگوی بازگشایی قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدهاید. پساز <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته میشود که بااستفاده از یک حساب ایمیل قفل تلفنتان را باز کنید.\n\n لطفاً پساز <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"حذف"</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"میزان صدا را به بالاتر از حد توصیه شده افزایش میدهید؟\n\nگوش دادن به صداهای بلند برای مدت طولانی میتواند به شنواییتان آسیب وارد کند."</string>
@@ -1864,7 +1865,7 @@
<string name="managed_profile_label_badge_2" msgid="5673187309555352550">"کار دوم <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="6882151970556391957">"کار سوم <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"درخواست کد پین قبل از برداشتن پین"</string>
- <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"درخواست الگوی باز کردن قفل قبل از برداشتن سنجاق"</string>
+ <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"درخواست الگوی بازگشایی قفل قبلاز برداشتن سنجاق"</string>
<string name="lock_to_app_unlock_password" msgid="9126722403506560473">"درخواست گذرواژه قبل از برداشتن سنجاق"</string>
<string name="package_installed_device_owner" msgid="7035926868974878525">"توسط سرپرست سیستم نصب شد"</string>
<string name="package_updated_device_owner" msgid="7560272363805506941">"توسط سرپرست سیستم بهروزرسانی شد"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 5b4caa7..2ae93b8 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Kokeile toista sormenjälkeä"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Liian kirkas"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Kokeile muuttaa asentoa"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Sormenjälki tunnistettu"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Sormenjälkiä ei ole otettu käyttöön."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Laitteessa ei ole sormenjälkitunnistinta."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Tunnistin poistettu väliaikaisesti käytöstä."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Tunnistin on kalibroitava"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Sormi <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Käytä sormenjälkeä"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Käytä sormenjälkeä tai näytön lukitusta"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 29c9698..143f3be 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Essayez une autre empreinte digitale"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Trop lumineux"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Essayez de l\'ajuster"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Empreinte digitale authentifiée"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 23e599e..829c07c 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Essayez une autre empreinte"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Trop de lumière"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Essayez de repositionner le doigt"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Empreinte digitale authentifiée"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Aucune empreinte digitale enregistrée."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Aucun lecteur d\'empreinte digitale n\'est installé sur cet appareil."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Capteur temporairement désactivé."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Vous devez calibrer le capteur"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Doigt <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Utiliser l\'empreinte digitale"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Utiliser votre empreinte digitale ou le verrouillage de l\'écran"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 70f703a..22a25c9 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Proba con outra impresión dixital"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Hai demasiada luz"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Proba a axustar a impresión dixital"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Autenticouse a impresión dixital"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Non se rexistraron impresións dixitais."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo non ten sensor de impresión dixital."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Desactivouse o sensor temporalmente."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"É necesario calibrar o sensor"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Utilizar impresión dixital"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Utilizar impresión dixital ou credencial do dispositivo"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 4d27b10..702e169 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"અન્ય ફિંગરપ્રિન્ટ અજમાવી જુઓ"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"અતિશય પ્રકાશિત"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"ગોઠવણી કરી જુઓ"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ફિંગરપ્રિન્ટ પ્રમાણિત કરી"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 74f4f46..8c668dc 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"किसी दूसरे फ़िंगरप्रिंट से कोशिश करें"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"बहुत रोशनी है"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"सेंसर पर सही तरीके से उंगली लगाने की कोशिश करें"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"फ़िंगरप्रिंट की पुष्टि हो गई"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"कोई फ़िंगरप्रिंट रजिस्टर नहीं किया गया है."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"इस डिवाइस में फ़िंगरप्रिंट सेंसर नहीं है."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"सेंसर कुछ समय के लिए बंद कर दिया गया है."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"सेंसर को कैलिब्रेट करने की ज़रूरत है"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"फ़िंगरप्रिंट <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"फ़िंगरप्रिंट इस्तेमाल करें"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"फ़िंगरप्रिंट या स्क्रीन लॉक का क्रेडेंशियल इस्तेमाल करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 13a7c45..eb90708 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -588,6 +588,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Isprobajte drugi otisak prsta"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Presvijetlo"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Pokušajte ga prilagoditi"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Svaki put lagano promijenite položaj prsta"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Autentificirano otiskom prsta"</string>
@@ -604,8 +605,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nije registriran nijedan otisak prsta."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ovaj uređaj nema senzor otiska prsta."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je privremeno onemogućen."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Potrebno je kalibrirati senzor"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Upotreba otiska prsta"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Upotreba otiska prsta ili zaključavanja zaslona"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index a478e67..77db9e6 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Próbálkozzon másik ujjlenyomattal"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Túl világos"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Próbálja beállítani"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Ujjlenyomat hitelesítve"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nincsenek regisztrált ujjlenyomatok."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ez az eszköz nem rendelkezik ujjlenyomat-érzékelővel."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Az érzékelő átmenetileg le van tiltva."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Az érzékelő kalibrálást igényel"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>. ujj"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Ujjlenyomat használata"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"A folytatás ujjlenyomattal vagy képernyőzárral lehetséges"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index e42eccb..0a18bfa 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Փորձեք մեկ այլ մատնահետք"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Շատ լուսավոր է"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Փորձեք փոխել մատի դիրքը"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Ամեն անգամ թեթևակի փոխեք մատի դիրքը"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Մատնահետքը նույնականացվեց"</string>
@@ -601,8 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Գրանցված մատնահետք չկա:"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Այս սարքը չունի մատնահետքերի սկաներ։"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Տվիչը ժամանակավորապես անջատված է:"</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Սկաներն անհրաժեշտ է չափաբերել"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Մատնահետք <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Օգտագործել մատնահետք"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Օգտագործել մատնահետք կամ էկրանի կողպում"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index f50c470..58cfdd7 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Coba sidik jari lain"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Terlalu terang"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Coba sesuaikan"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Sidik jari diautentikasi"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Tidak ada sidik jari yang terdaftar."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Perangkat ini tidak memiliki sensor sidik jari."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor dinonaktifkan untuk sementara."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sensor memerlukan kalibrasi"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Jari <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Gunakan sidik jari"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Gunakan sidik jari atau kunci layar"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index bfc7476..210be91 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Prófaðu annað fingrafar"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Of bjart"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Prófaðu að breyta stöðu fingursins"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingrafar staðfest"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Engin fingraför hafa verið skráð."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Þetta tæki er ekki með fingrafaralesara."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Slökkt tímabundið á skynjara."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Kvarða þarf skynjarann"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Fingur <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Nota fingrafar"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Nota fingrafar eða skjálás"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 708841d..7d08000 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Prova con un\'altra impronta"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Troppa luce"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Prova a regolare"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Cambia leggermente la posizione del dito ogni volta"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Impronta autenticata"</string>
@@ -601,8 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nessuna impronta digitale registrata."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Questo dispositivo non dispone di sensore di impronte."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensore temporaneamente disattivato."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"È necessario calibrare il sensore"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Dito <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Usa l\'impronta"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Usa l\'impronta o il blocco schermo"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index fabffbf..8b3aece 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -591,6 +591,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"יש להשתמש בטביעת אצבע אחרת"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"בהיר מדי"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"יש לנסות ולשנות את תנוחת האצבע"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"טביעת האצבע אומתה"</string>
@@ -607,8 +609,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"לא נסרקו טביעות אצבע."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"במכשיר הזה אין חיישן טביעות אצבע."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"החיישן מושבת באופן זמני."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"צריך לכייל את החיישן"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"אצבע <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"שימוש בטביעת אצבע"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"שימוש בטביעת אצבע או בנעילת מסך"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index e275df03..7b62919 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"別の指紋をお試しください"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"明るすぎます"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"調整してみてください"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"指紋認証を完了しました"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"指紋が登録されていません。"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"このデバイスには指紋認証センサーがありません。"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"センサーが一時的に無効になっています。"</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"センサーの調整が必要です"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"指紋 <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"指紋の使用"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"指紋または画面ロックの使用"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index bd85e61..8d9b99c 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"ცადეთ სხვა თითის ანაბეჭდი"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"ზედმეტად ნათელია"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"ცადეთ დარეგულირება"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"თითის ანაბეჭდი ავტორიზებულია"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"თითის ანაბეჭდები რეგისტრირებული არ არის."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ამ მოწყობილობას არ აქვს თითის ანაბეჭდის სენსორი."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"სენსორი დროებით გათიშულია."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"სენსორს კალიბრაცია სჭირდება"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"თითი <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"გამოიყენეთ თითის ანაბეჭდი"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"გამოიყენეთ თითის ანაბეჭდი ან ეკრანის დაბლოკვა"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 16da28f..80bddc7 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Басқа саусақ ізін байқап көріңіз."</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Тым жарық."</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Дұрыстап қойып көріңіз."</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Саусақ ізі аутентификацияланды"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Саусақ іздері тіркелмеген."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Бұл құрылғыда саусақ ізін оқу сканері жоқ."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Датчик уақытша өшірулі."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Датчикті калибрлеу қажет."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>-саусақ"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Саусақ ізін пайдалану"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Саусақ ізін немесе экран құлпын пайдалану"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index e72db13..aaa188b 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"សាកល្បងប្រើស្នាមម្រាមដៃផ្សេងទៀត"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"ភ្លឺពេក"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"សាកល្បងកែតម្រូវ"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"បានផ្ទៀងផ្ទាត់ស្នាមម្រាមដៃ"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"មិនមានការចុះឈ្មោះស្នាមម្រាមដៃទេ។"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ឧបករណ៍នេះមិនមានឧបករណ៍ចាប់ស្នាមម្រាមដៃទេ។"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"បានបិទឧបករណ៍ចាប់សញ្ញាជាបណ្តោះអាសន្ន។"</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"ឧបករណ៍ចាប់សញ្ញាត្រូវការកែសម្រួល"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"ម្រាមដៃ <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"ប្រើស្នាមម្រាមដៃ"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"ប្រើស្នាមម្រាមដៃ ឬការចាក់សោអេក្រង់"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 8858d0b..fc7fa3b 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"ಮತ್ತೊಂದು ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಪ್ರಯತ್ನಿಸಿ"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"ತುಂಬಾ ಪ್ರಕಾಶಮಾನವಾಗಿದೆ"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"ಹೊಂದಿಸಲು ಪ್ರಯತ್ನಿಸಿ"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಅನ್ನು ಪ್ರಮಾಣೀಕರಣ ಮಾಡಲಾಗಿದೆ"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ಯಾವುದೇ ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಅನ್ನು ನೋಂದಣಿ ಮಾಡಿಲ್ಲ."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ಈ ಸಾಧನವು ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ಅನ್ನು ಹೊಂದಿಲ್ಲ."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ಸೆನ್ಸಾರ್ ಅನ್ನು ತಾತ್ಕಾಲಿಕವಾಗಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"ಸೆನ್ಸರ್ಗೆ ಕ್ಯಾಲಿಬ್ರೇಶನ್ನ ಅಗತ್ಯವಿದೆ"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"ಫಿಂಗರ್ <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"ಫಿಂಗರ್ ಪ್ರಿಂಟ್ ಬಳಸಿ"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"ಫಿಂಗರ್ ಪ್ರಿಂಟ್ ಅಥವಾ ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಬಳಸಿ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index e9d0fc5..14b8514 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"다른 지문으로 시도"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"너무 밝음"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"조정 시도"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"지문이 인증됨"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"등록된 지문이 없습니다."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"기기에 지문 센서가 없습니다."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"센서가 일시적으로 사용 중지되었습니다."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"센서 보정 필요"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"손가락 <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"지문 사용"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"지문 또는 화면 잠금 사용"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index c1961db..ccfdef8 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Башка манжа изин байкап көрүңүз"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Өтө жарык"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Тууралап көрүңүз"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Манжа изи текшерилди"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Бир да манжа изи катталган эмес."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Бул түзмөктө манжа изинин сенсору жок."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сенсор убактылуу өчүрүлгөн."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Сенсорду тууралоо керек"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>-манжа"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Манжа изин колдонуу"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Манжа изин же экрандын кулпусун колдонуу"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 65643c3..e89dba7 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"ລອງໃຊ້ລາຍນິ້ວມືອື່ນ"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"ແຈ້ງເກີນໄປ"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"ກະລຸນາລອງປັບແກ້"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"ປ່ຽນຕຳແໜ່ງຂອງນິ້ວມືຂອງທ່ານເລັກນ້ອຍໃນແຕ່ລະເທື່ອ"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ພິສູດຢືນຢັນລາຍນິ້ວມືແລ້ວ"</string>
@@ -601,8 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ບໍ່ມີການລົງທະບຽນລາຍນິ້ວມື."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ອຸປະກອນນີ້ບໍ່ມີເຊັນເຊີລາຍນິ້ວມື."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ປິດການເຮັດວຽກຂອງເຊັນເຊີໄວ້ຊົ່ວຄາວແລ້ວ."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"ຕ້ອງປັບທຽບມາດຕະຖານເຊັນເຊີ"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"ນີ້ວມື <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"ໃຊ້ລາຍນິ້ວມື"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"ໃຊ້ລາຍນິ້ວມື ຫຼື ການລັອກໜ້າຈໍ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 9849124..ee9e61d 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -591,6 +591,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Pabandykite kitą kontrolinį kodą"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Per šviesu"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Pabandykite koreguoti"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Piršto antspaudas autentifikuotas"</string>
@@ -607,8 +609,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Neužregistruota jokių kontrolinių kodų."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Šiame įrenginyje nėra kontrolinio kodo jutiklio."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Jutiklis laikinai išjungtas."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Reikia sukalibruoti jutiklį"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g> pirštas"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Naudoti kontrolinį kodą"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Naudoti kontrolinį kodą arba ekrano užraktą"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 8407622..1a90a81 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -588,6 +588,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Izmēģiniet citu pirksta nospiedumu"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Pārāk spilgts"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Mēģiniet mainīt pozīciju"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Pirksta nospiedums tika autentificēts."</string>
@@ -604,8 +606,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nav reģistrēts neviens pirksta nospiedums."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Šajā ierīcē nav pirksta nospieduma sensora."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensors ir īslaicīgi atspējots."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Nepieciešama sensora kalibrēšana."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>. pirksts"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Pirksta nospieduma izmantošana"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Pirksta nospieduma vai ekrāna bloķēšanas metodes izmantošana"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 42a55c2..e028307 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Пробајте со друг отпечаток"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Премногу светло"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Пробајте да го приспособите прстот"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Отпечатокот е проверен"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Не се запишани отпечатоци."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Уредов нема сензор за отпечатоци."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сензорот е привремено оневозможен."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Сензорот треба да се калибрира"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Прст <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Користи отпечаток"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Користи отпечаток или заклучување екран"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index f4a79e3..1b2e595 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"മറ്റൊരു ഫിംഗർപ്രിന്റ് ഉപയോഗിച്ച് നോക്കുക"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"തെളിച്ചം വളരെയധികമാണ്"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"അൽപ്പം നീക്കി നോക്കൂ"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ഫിംഗർപ്രിന്റ് പരിശോധിച്ചുറപ്പിച്ചു"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"വിരലടയാളങ്ങൾ എൻറോൾ ചെയ്തിട്ടില്ല."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ഈ ഉപകരണത്തിൽ ഫിംഗർപ്രിന്റ് സെൻസറില്ല."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"സെൻസർ താൽക്കാലികമായി പ്രവർത്തനരഹിതമാക്കി."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"സെൻസറിന് കാലിബ്രേഷൻ ആവശ്യമാണ്"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"ഫിംഗർ <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"ഫിംഗർപ്രിന്റ് ഉപയോഗിക്കുക"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"ഫിംഗർപ്രിന്റ് അല്ലെങ്കിൽ സ്ക്രീൻ ലോക്ക് ഉപയോഗിക്കുക"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 7d0a643..d21ce23 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Өөр хурууны хээ туршина уу"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Хэт гэрэлтэй байна"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Тохируулж үзнэ үү"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Хурууны хээг нотолсон"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Бүртгүүлсэн хурууны хээ алга."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Энэ төхөөрөмжид хурууны хээ мэдрэгч алга."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Мэдрэгчийг түр хугацаанд идэвхгүй болгосон."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Мэдрэгчид тохируулга шаардлагатай"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Хурууны хээ <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Хурууны хээ ашиглах"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Хурууны хээ эсвэл дэлгэцийн түгжээ ашиглах"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 3933bf3..f1b21c0 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -349,7 +349,7 @@
<string name="permdesc_expandStatusBar" msgid="7180756900448498536">"स्टेटस बार विस्तृत करण्यासाठी किंवा संक्षिप्त करण्यासाठी अॅप ला अनुमती देते."</string>
<string name="permlab_fullScreenIntent" msgid="4310888199502509104">"लॉक केलेल्या डिव्हाइसवर फुल स्क्रीन अॅक्टिव्हिटी म्हणून सूचना प्रदर्शित करणे"</string>
<string name="permdesc_fullScreenIntent" msgid="1100721419406643997">"लॉक केलेल्या डिव्हाइसवर फुल स्क्रीन अॅक्टिव्हिटी म्हणून सूचना प्रदर्शित करण्यासाठी ॲपला अनुमती द्या"</string>
- <string name="permlab_install_shortcut" msgid="7451554307502256221">"शॉर्टकट स्थापित करा"</string>
+ <string name="permlab_install_shortcut" msgid="7451554307502256221">"शॉर्टकट इंस्टॉल करा"</string>
<string name="permdesc_install_shortcut" msgid="4476328467240212503">"अनुप्रयोगाला वापरकर्ता हस्तक्षेपाशिवाय मुख्यस्क्रीन शॉर्टकट जोडण्याची अनुमती देते."</string>
<string name="permlab_uninstall_shortcut" msgid="295263654781900390">"शॉर्टकट विस्थापित करा"</string>
<string name="permdesc_uninstall_shortcut" msgid="1924735350988629188">"अनुप्रयोगाला वापरकर्ता हस्तक्षेपाशिवाय मुख्यस्क्रीन शॉर्टकट काढण्याची अनुमती देते."</string>
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"दुसरी फिंगरप्रिंट वापरून पाहा"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"खूप प्रखर"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"अॅडजस्ट करण्याचा प्रयत्न करा"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"फिंगरप्रिंट ऑथेंटिकेट केली आहे"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 2ad6baf..bcc502a 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Cuba cap jari lain"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Terlalu terang"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Cuba selaraskan"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Cap jari disahkan"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Tiada cap jari didaftarkan."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Peranti ini tiada penderia cap jari."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Penderia dilumpuhkan sementara."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Penderia memerlukan penentukuran"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Jari <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Gunakan cap jari"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Gunakan cap jari atau kunci skrin"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 3543be0f..97db715 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"အခြားလက်ဗွေဖြင့် စမ်းကြည့်ပါ"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"အလွန် လင်းသည်"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"ပြင်ဆင်ကြည့်ပါ"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"လက်ဗွေကို အထောက်အထား စိစစ်ပြီးပါပြီ"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"မည်သည့် လက်ဗွေကိုမျှ ထည့်သွင်းမထားပါ။"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ဤစက်တွင် လက်ဗွေအာရုံခံကိရိယာ မရှိပါ။"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"အာရုံခံကိရိယာကို ယာယီပိတ်ထားသည်။"</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"အာရုံခံကိရိယာက စံကိုက်ချိန်ညှိခြင်း လိုအပ်သည်"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"လက်ချောင်း <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"လက်ဗွေ သုံးခြင်း"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"လက်ဗွေ (သို့) ဖန်သားပြင်လော့ခ်ချခြင်းကို သုံးခြင်း"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 9ed34e0..bb29d8e 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Prøv et annet fingeravtrykk"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"For lyst"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Prøv å justere"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingeravtrykket er godkjent"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ingen fingeravtrykk er registrert."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Denne enheten har ikke fingeravtrykkssensor."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensoren er midlertidig slått av."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sensoren må kalibreres"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Bruk fingeravtrykk"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Bruk fingeravtrykk eller skjermlås"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 25f59c2..c712fbd 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -349,7 +349,7 @@
<string name="permdesc_expandStatusBar" msgid="7180756900448498536">"एपलाई स्थिति पट्टि विस्तार वा संकुचन गर्न अनुमति दिन्छ।"</string>
<string name="permlab_fullScreenIntent" msgid="4310888199502509104">"लक गरिएको डिभाइसमा स्क्रिनभरि देखिने सूचनाहरू देखाइयोस्"</string>
<string name="permdesc_fullScreenIntent" msgid="1100721419406643997">"यो अनुमति दिइएमा एपले लक गरिएको डिभाइसमा स्क्रिनभरि देखिने सूचनाहरू देखाउन सक्छ"</string>
- <string name="permlab_install_shortcut" msgid="7451554307502256221">"सर्टकट स्थापना गर्नुहोस्"</string>
+ <string name="permlab_install_shortcut" msgid="7451554307502256221">"सर्टकट इन्स्टल गर्ने"</string>
<string name="permdesc_install_shortcut" msgid="4476328467240212503">"प्रयोगकर्ताको हस्तक्षेप बिना एउटा एपलाई सर्टकटमा थप्नको लागि अनुमति दिन्छ।"</string>
<string name="permlab_uninstall_shortcut" msgid="295263654781900390">"सर्टकटहरूको स्थापन रद्द गर्नुहोस्"</string>
<string name="permdesc_uninstall_shortcut" msgid="1924735350988629188">"प्रयोगकर्ताको हस्तक्षेप बिना एउटा एपलाई सर्टकटमा हटाउनको लागि अनुमति दिन्छ।"</string>
@@ -438,9 +438,9 @@
<string name="permlab_accessLocationExtraCommands" msgid="5162339812057983988">"अधिक स्थान प्रदायक आदेशहरू पहुँच गर्नुहोस्"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"एपलाई अतिरिक्त स्थान प्रदायक आदेशहरू पहुँच गर्न अनुमति दिन्छ। यो एपलाई GPS वा अन्य स्थान स्रोतहरूको संचालन साथै हस्तक्षेप गर्न अनुमति दिन सक्छ।"</string>
<string name="permlab_accessFineLocation" msgid="6426318438195622966">"अग्रभूमिमा मात्र सटीक स्थानमाथि पहुँच राख्नुहोस्"</string>
- <string name="permdesc_accessFineLocation" msgid="6732174080240016335">"यो एप चलाएका बेला यसले लोकेसनमा आधारित सेवाहरूबाट तपाईंको स्थानको सटीक जानकारी प्राप्त गर्न सक्छ। तपाईंको डिभाइसमा लोकेसनमा आधारित सेवाहरू सक्रिय गरिएको छ भने मात्र यो एपले स्थानको जानकारी प्राप्त गर्न सक्छ। यसले ब्याट्रीको उपयोग बढाउन सक्छ।"</string>
+ <string name="permdesc_accessFineLocation" msgid="6732174080240016335">"यो एप चलाएका बेला यसले लोकेसन सर्भिसबाट तपाईंको स्थानको सटीक जानकारी प्राप्त गर्न सक्छ। तपाईंको डिभाइसमा लोकेसन सर्भिस सक्रिय गरिएको छ भने मात्र यो एपले स्थानको जानकारी प्राप्त गर्न सक्छ। यसले ब्याट्रीको उपयोग बढाउन सक्छ।"</string>
<string name="permlab_accessCoarseLocation" msgid="1561042925407799741">"अग्रभागमा मात्र अनुमानित स्थानमाथि पहुँच राख्नुहोस्"</string>
- <string name="permdesc_accessCoarseLocation" msgid="778521847873199160">"यो एप चलाएका बेला यसले लोकेसनमा आधारित सेवाहरूबाट तपाईंको स्थानको अनुमानित जानकारी प्राप्त गर्न सक्छ। तपाईंको डिभाइसमा लोकेसनमा आधारित सेवाहरू सक्रिय गरिएको छ भने मात्र यो एपले स्थानको जानकारी प्राप्त गर्न सक्छ।"</string>
+ <string name="permdesc_accessCoarseLocation" msgid="778521847873199160">"यो एप चलाएका बेला यसले लोकेसन सर्भिसबाट तपाईंको स्थानको अनुमानित जानकारी प्राप्त गर्न सक्छ। तपाईंको डिभाइसमा लोकेसन सर्भिस सक्रिय गरिएको छ भने मात्र यो एपले स्थानको जानकारी प्राप्त गर्न सक्छ।"</string>
<string name="permlab_accessBackgroundLocation" msgid="1721164702777366138">"पृष्ठभूमिमा स्थानसम्बन्धी पहुँच"</string>
<string name="permdesc_accessBackgroundLocation" msgid="8264885066095638105">"यो एपले जुनसुकै बेला (एप नचलाएका बेलामा पनि) स्थानमाथि पहुँच राख्न सक्छ।"</string>
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"तपाईँका अडियो सेटिङहरू परिवर्तन गर्नुहोस्"</string>
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"अर्को फिंगरप्रिन्ट प्रयोग गरी हेर्नुहोस्"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"ज्यादै उज्यालो छ"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"सेन्सरमा सही तरिकाले औँला राखेर हेर्नुहोस्"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"फिंगरप्रिन्ट प्रमाणीकरण गरियो"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 307c125..cc75bd6 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Probeer een andere vingerafdruk"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Te veel licht"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Verplaats je vinger"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Verander de positie van je vinger steeds een beetje"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Vingerafdruk geverifieerd"</string>
@@ -601,8 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Geen vingerafdrukken geregistreerd."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Dit apparaat heeft geen vingerafdruksensor."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor staat tijdelijk uit."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sensor moet worden gekalibreerd"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Vinger <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Vingerafdruk gebruiken"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Vingerafdruk of schermvergrendeling gebruiken"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 1e6eb37..f2fbbd0 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"ଅନ୍ୟ ଏକ ଟିପଚିହ୍ନ ବ୍ୟବହାର କରି ଦେଖନ୍ତୁ"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"ବହୁତ ଉଜ୍ଜ୍ୱଳ"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"ଆଡଜଷ୍ଟ କରି ଦେଖନ୍ତୁ"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ଟିପଚିହ୍ନ ପ୍ରମାଣିତ ହେଲା"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index fbccb25..1804680 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"ਕੋਈ ਹੋਰ ਫਿੰਗਰਪ੍ਰਿੰਟ ਵਰਤ ਕੇ ਦੇਖੋ"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"ਬਹੁਤ ਜ਼ਿਆਦਾ ਚਮਕ"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"ਵਿਵਸਥਿਤ ਕਰਕੇ ਦੇਖੋ"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਪ੍ਰਮਾਣਿਤ ਹੋਇਆ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 0671787..06c7779 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -591,6 +591,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Użyj odcisku innego palca"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Zbyt jasno"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Popraw"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Za każdym razem lekko zmieniaj ułożenie palca"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Uwierzytelniono odciskiem palca"</string>
@@ -607,8 +608,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nie zarejestrowano odcisków palców."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"To urządzenie nie jest wyposażone w czytnik linii papilarnych."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Czujnik jest tymczasowo wyłączony."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Czujnik wymaga kalibracji"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Odcisk palca <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Używaj odcisku palca"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Używaj odcisku palca lub blokady ekranu"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 8c6b146..8729940 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Use outra impressão digital"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Claro demais"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Ajuste a posição do dedo"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Mude a posição do dedo ligeiramente a cada momento"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Impressão digital autenticada"</string>
@@ -601,8 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nenhuma impressão digital registrada."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo não tem um sensor de impressão digital."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor desativado temporariamente."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"O sensor precisa ser calibrado"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Usar impressão digital"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Usar impressão digital ou bloqueio de tela"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 0fa0e50..543abc3 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Experimente outra impressão digital"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Está demasiado claro"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Experimente ajustar"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Altere a posição do seu dedo ligeiramente de cada vez"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"A impressão digital foi autenticada."</string>
@@ -601,8 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nenhuma impressão digital registada."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo não tem sensor de impressões digitais."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor temporariamente desativado."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"O sensor necessita de calibração"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Utilizar a impressão digital"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Utilizar o bloqueio de ecrã ou a impressão digital"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 8c6b146..8729940 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Use outra impressão digital"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Claro demais"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Ajuste a posição do dedo"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Mude a posição do dedo ligeiramente a cada momento"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Impressão digital autenticada"</string>
@@ -601,8 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nenhuma impressão digital registrada."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo não tem um sensor de impressão digital."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor desativado temporariamente."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"O sensor precisa ser calibrado"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Usar impressão digital"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Usar impressão digital ou bloqueio de tela"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 7bbf3e1..8e005e6 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -352,7 +352,7 @@
<string name="permdesc_expandStatusBar" msgid="7180756900448498536">"Permite aplicației să extindă sau să restrângă bara de stare."</string>
<string name="permlab_fullScreenIntent" msgid="4310888199502509104">"să afișeze notificări ca activități pe ecran complet pe un dispozitiv blocat"</string>
<string name="permdesc_fullScreenIntent" msgid="1100721419406643997">"Permite aplicației să afișeze notificări ca activități pe ecran complet pe un dispozitiv blocat"</string>
- <string name="permlab_install_shortcut" msgid="7451554307502256221">"instalează comenzi rapide"</string>
+ <string name="permlab_install_shortcut" msgid="7451554307502256221">"Instalarea de comenzi rapide"</string>
<string name="permdesc_install_shortcut" msgid="4476328467240212503">"Permite unei aplicații să adauge comenzi rapide pe ecranul de pornire, fără intervenția utilizatorului."</string>
<string name="permlab_uninstall_shortcut" msgid="295263654781900390">"dezinstalează comenzi rapide"</string>
<string name="permdesc_uninstall_shortcut" msgid="1924735350988629188">"Permite aplicației să elimine comenzi rapide de pe ecranul de pornire, fără intervenția utilizatorului."</string>
@@ -588,6 +588,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Încercați altă amprentă"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Prea luminos"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Încercați să ajustați"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Amprentă autentificată"</string>
@@ -604,8 +606,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nu au fost înregistrate amprente."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Dispozitivul nu are senzor de amprentă."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzorul este dezactivat temporar."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Senzorul necesită calibrare"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Degetul <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Folosiți amprenta"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Folosiți amprenta sau blocarea ecranului"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index ebe46e8..2d177cc 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -591,6 +591,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Попробуйте сохранить отпечаток другого пальца."</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Слишком светло."</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Попробуйте изменить положение пальца."</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Отпечаток пальца проверен"</string>
@@ -607,8 +609,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Нет отсканированных отпечатков пальцев"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"На этом устройстве нет сканера отпечатков пальцев."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сканер отпечатков пальцев временно отключен."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Требуется калибровка датчика."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Отпечаток <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Использовать отпечаток пальца"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Использовать отпечаток пальца или блокировку экрана"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index eea2594..e6d7956 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"තවත් ඇඟිලි සලකුණක් උත්සාහ කරන්න"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"දීප්තිය වැඩියි"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"සීරුමාරු කිරීම උත්සාහ කරන්න"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ඇඟිලි සලකුණ සත්යාපනය කරන ලදී"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ඇඟිලි සලකුණු ඇතුළත් කර නොමැත."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"මෙම උපාංගයේ ඇඟිලි සලකුණු සංවේදකයක් නොමැත."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"සංවේදකය තාවකාලිකව අබල කර ඇත."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"සංවේදකයට ක්රමාංකනය අවශ්යයි"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"ඇඟිලි <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"ඇඟිලි සලකුණ භාවිත කරන්න"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"ඇඟිලි සලකුණ හෝ තිර අගුල භාවිත කරන්න"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 234e3a8..18dcef3 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -591,6 +591,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Vyskúšajte iný odtlačok prsta"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Príliš jasno"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Vyskúšajte upraviť"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Odtlačok prsta bol overený"</string>
@@ -607,8 +609,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Neregistrovali ste žiadne odtlačky prstov."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Toto zariadenie nemá senzor odtlačkov prstov."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je dočasne vypnutý."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Senzor vyžaduje kalibráciu"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Prst: <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Použiť odtlačok prsta"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Použiť odtlačok prsta alebo zámku obrazovky"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 19c4434..0f13454 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -591,6 +591,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Poskusite z drugim prstnim odtisom."</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Presvetlo je."</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Poskusite popraviti položaj prsta."</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Pristnost prstnega odtisa je preverjena"</string>
@@ -607,8 +609,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ni registriranih prstnih odtisov."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ta naprava nima tipala prstnih odtisov."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Tipalo je začasno onemogočeno."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Tipalo je treba umeriti"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Uporaba prstnega odtisa"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Uporaba prstnega odtisa ali odklepanja s poverilnico"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 7934473..2d45dd3 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Provo një gjurmë gishti tjetër"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Me shumë ndriçim"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Provo ta rregullosh"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Gjurma e gishtit u vërtetua"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nuk ka asnjë gjurmë gishti të regjistruar."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Kjo pajisje nuk ka sensor të gjurmës së gishtit."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensori është çaktivizuar përkohësisht."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sensori ka nevojë për kalibrim"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Gishti <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Përdor gjurmën e gishtit"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Përdor gjurmën e gishtit ose kyçjen e ekranit"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index a0ae389..6b96632 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -588,6 +588,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Пробајте са другим отиском прста"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Превише је светло"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Пробајте да прилагодите"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Сваки пут лагано промените положај прста"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Отисак прста је потврђен"</string>
@@ -604,8 +605,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Није регистрован ниједан отисак прста."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Овај уређај нема сензор за отисак прста."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сензор је привремено онемогућен."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Сензор треба да се калибрише"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Прст <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Користите отисак прста"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Користите отисак прста или закључавање екрана"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 34d5e2c..58fcd9d 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Testa ett annat fingeravtryck"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Det är för ljust"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Testa att justera fingeravtrycket"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingeravtrycket har autentiserats"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Inga fingeravtryck har registrerats."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Enheten har ingen fingeravtryckssensor."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensorn har tillfälligt inaktiverats."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sensorn måste kalibreras"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Använd ditt fingeravtryck"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Använd ditt fingeravtryck eller skärmlåset"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index cc8d644..8b34ba2 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Jaribu alama nyingine ya kidole"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Inang\'aa mno"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Jaribu kurekebisha"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Badilisha mkao wa kidole chako kiasi kila wakati"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Imethibitisha alama ya kidole"</string>
@@ -601,8 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Hakuna alama za vidole zilizojumuishwa."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Kifaa hiki hakina kitambua alama ya kidole."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Kitambuzi kimezimwa kwa muda."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Kitambuzi kinahitaji kurekebishwa"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Kidole cha <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Tumia alama ya kidole"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Tumia alama ya kidole au mbinu ya kufunga skrini"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 0d28151..adb8c47 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"வேறு கைரேகையை முயலவும்"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"அதிக வெளிச்சமாக உள்ளது"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"விரலைச் சரியாக வைக்கவும்"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"கைரேகை அங்கீகரிக்கப்பட்டது"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"கைரேகைப் பதிவுகள் எதுவும் இல்லை."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"இந்தச் சாதனத்தில் கைரேகை சென்சார் இல்லை."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"சென்சார் தற்காலிகமாக முடக்கப்பட்டுள்ளது."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"சென்சாரைச் சீரமைக்க வேண்டும்"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"கைரேகை <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"கைரேகையைப் பயன்படுத்து"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"கைரேகையையோ திரைப் பூட்டையோ பயன்படுத்து"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 936b758..dac4c51 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"మరొక వేలిముద్రను ట్రై చేయండి"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"వెలుతురు అధికంగా ఉంది"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"సర్దుబాటు చేయడానికి ట్రై చేయండి"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"వేలిముద్ర ప్రమాణీకరించబడింది"</string>
diff --git a/core/res/res/values-television/config.xml b/core/res/res/values-television/config.xml
index 3ecb1dd..55e5685 100644
--- a/core/res/res/values-television/config.xml
+++ b/core/res/res/values-television/config.xml
@@ -42,4 +42,8 @@
<!-- Allow SystemUI to show the shutdown dialog -->
<bool name="config_showSysuiShutdown">true</bool>
+
+ <!-- Component name of the activity used to inform a user about a sensory being blocked because
+ of privacy settings. -->
+ <string name="config_sensorUseStartedActivity">com.android.systemui/com.android.systemui.sensorprivacy.television.TvUnblockSensorActivity</string>
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 9b2966f..b9ab264 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"ลองลายนิ้วมืออื่น"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"สว่างเกินไป"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"ลองปรับการวางนิ้ว"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ตรวจสอบสิทธิ์ลายนิ้วมือแล้ว"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ไม่มีลายนิ้วมือที่ลงทะเบียน"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"อุปกรณ์นี้ไม่มีเซ็นเซอร์ลายนิ้วมือ"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ปิดใช้เซ็นเซอร์ชั่วคราวแล้ว"</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"ต้องปรับเทียบเซ็นเซอร์"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"นิ้ว <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"ใช้ลายนิ้วมือ"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"ใช้ลายนิ้วมือหรือการล็อกหน้าจอ"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index a34ac28..7678869 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Sumubok ng ibang fingerprint"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Masyadong maliwanag"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Subukang isaayos"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Na-authenticate ang fingerprint"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Walang naka-enroll na fingerprint."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Walang sensor ng fingerprint ang device na ito."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Pansamantalang na-disable ang sensor."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Kailangang i-calibrate ang sensor"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Daliri <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Gumamit ng fingerprint"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Gumamit ng fingerprint o lock ng screen"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index a08dcb2..2f9a8b6 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Başka bir parmak izi deneyin"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Çok parlak"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Ayarlamayı deneyin"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Her defasında parmağınızın konumunu biraz değiştirin"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Parmak izi kimlik doğrulaması yapıldı"</string>
@@ -601,8 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Parmak izi kaydedilmedi."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Bu cihazda parmak izi sensörü yok."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensör geçici olarak devre dışı bırakıldı."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sensörün kalibre edilmesi gerekiyor"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>. parmak"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Parmak izi kullan"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Parmak izi veya ekran kilidi kullan"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 8be7da6..c04e3f0 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -591,6 +591,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Спробуйте інший відбиток пальця"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Надто яскраво"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Спробуйте відкоригувати відбиток пальця"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Щоразу трохи змінюйте положення пальця"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Відбиток пальця автентифіковано"</string>
@@ -607,8 +608,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Відбитки пальців не зареєстровано."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"На цьому пристрої немає сканера відбитків пальців."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Датчик тимчасово вимкнено."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Потрібно відкалібрувати датчик"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Відбиток пальця <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Доступ за відбитком пальця"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Використовувати відбиток пальця або дані для розблокування екрана"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index e0344e0..07d683b 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"دوسرا فنگر پرنٹ آزمائیں"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"کافی روشنی ہے"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"ایڈجسٹ کرنے کی کوشش کریں"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"فنگر پرنٹ کی تصدیق ہو گئی"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"کوئی فنگر پرنٹ مندرج شدہ نہیں ہے۔"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"اس آلہ میں فنگر پرنٹ سینسر نہیں ہے۔"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"سینسر عارضی طور غیر فعال ہے۔"</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"سینسر کو کیلیبریشن کی ضرورت ہے"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"انگلی <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"فنگر پرنٹ استعمال کریں"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"فنگر پرنٹ یا اسکرین لاک استعمال کریں"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 25a6a1a..a64c1a8 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Boshqa barmoq izi bilan urining"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Juda yorqin"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Moslashga urining"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Barmoq izi tekshirildi"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Hech qanday barmoq izi qayd qilinmagan."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Bu qurilmada barmoq izi skaneri mavjud emas."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor vaqtincha faol emas."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sensorni sozlash kerak"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Barmoq izi <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Barmoq izi ishlatish"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Barmoq izi yoki ekran qulfi"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index a5cfbaf..669adef 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Hãy thử một vân tay khác"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Quá sáng"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Hãy thử điều chỉnh"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Đã xác thực vân tay"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Chưa đăng ký vân tay."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Thiết bị này không có cảm biến vân tay."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Đã tạm thời tắt cảm biến."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Cảm biến cần hiệu chỉnh"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Ngón tay <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Dùng vân tay"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Dùng vân tay hoặc phương thức khóa màn hình"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 23832eb..ec8a7751e 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"请试试其他指纹"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"光线太亮"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"请尝试调整指纹"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"已验证指纹"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"未注册任何指纹。"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"此设备没有指纹传感器。"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"传感器已暂时停用。"</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"传感器需要校准"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"手指 <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"使用指纹"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"使用指纹或屏幕锁定凭据"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 0b59e52..c91a426 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"改用其他指紋"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"太亮"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"嘗試調整"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"驗證咗指紋"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"未註冊任何指紋"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"此裝置沒有指紋感應器。"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"感應器已暫時停用。"</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"需要校正感應器"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"手指 <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"使用指紋鎖定"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"使用指紋或螢幕鎖定"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 8f81d83..89b48d6 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"改用其他指紋"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"太亮"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"請試著調整"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"指紋驗證成功"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"未登錄任何指紋。"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"這個裝置沒有指紋感應器。"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"感應器已暫時停用。"</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"必須校正感應器"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"手指 <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"使用指紋"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"使用指紋或螢幕鎖定功能"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index c5c7818..671f5f70 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Zama ezinye izigxivizo zeminwe"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Kukhanya kakhulu"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Zama ukulungisa"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Izigxivizo zeminwe zigunyaziwe"</string>
@@ -601,8 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Azikho izigxivizo zeminwe ezibhalisiwe."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Le divayisi ayinayo inzwa yezigxivizo zeminwe."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Inzwa ikhutshazwe okwesikhashana."</string>
- <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
- <skip />
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Inzwa idinga ukulinganisa"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Umunwe ongu-<xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Sebenzisa izigxivizo zeminwe"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Sebenzisa izigxivizo zeminwe noma ukukhiya isikrini"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f4aff94..67d29b5 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1706,6 +1706,10 @@
config_enableFusedLocationOverlay is false. -->
<string name="config_fusedLocationProviderPackageName" translatable="false">com.android.location.fused</string>
+ <!-- Default value for the ADAS GNSS Location Enabled setting if this setting has never been
+ set before. -->
+ <bool name="config_defaultAdasGnssLocationEnabled" translatable="false">false</bool>
+
<string-array name="config_locationExtraPackageNames" translatable="false"></string-array>
<!-- The package name of the default network recommendation app.
@@ -1890,6 +1894,9 @@
STREAM_MUSIC as if it's on TV platform. -->
<bool name="config_single_volume">false</bool>
+ <!-- Flag indicating whether the volume panel should show remote sessions. -->
+ <bool name="config_volumeShowRemoteSessions">true</bool>
+
<!-- Flag indicating that an outbound call must have a call capable phone account
that has declared it can process the call's handle. -->
<bool name="config_requireCallCapableAccountForHandle">false</bool>
@@ -4628,6 +4635,15 @@
<!-- The package name for the default bug report handler app from power menu short press. This app must be allowlisted. -->
<string name="config_defaultBugReportHandlerApp" translatable="false"></string>
+ <!-- When true, enables the allowlisted app to upload profcollect reports. -->
+ <bool name="config_profcollectReportUploaderEnabled">false</bool>
+
+ <!-- The package name for the default profcollect report uploader app. This app must be allowlisted. -->
+ <string name="config_defaultProfcollectReportUploaderApp" translatable="false"></string>
+
+ <!-- The action name for the default profcollect report uploader app. -->
+ <string name="config_defaultProfcollectReportUploaderAction" translatable="false"></string>
+
<!-- The default value used for RawContacts.ACCOUNT_NAME when contacts are inserted without this
column set. These contacts are stored locally on the device and will not be removed even
if no android.account.Account with this name exists. A null string will be used if the
@@ -5007,6 +5023,10 @@
<!-- Default value for Settings.ASSIST_TOUCH_GESTURE_ENABLED -->
<bool name="config_assistTouchGestureEnabledDefault">true</bool>
+ <!-- The maximum byte size of the information contained in the bundle of
+ HotwordDetectedResult. -->
+ <integer translatable="false" name="config_hotwordDetectedResultMaxBundleSize">0</integer>
+
<!-- The amount of dimming to apply to wallpapers with mid range luminance. 0 displays
the wallpaper at full brightness. 1 displays the wallpaper as fully black. -->
<item name="config_wallpaperDimAmount" format="float" type="dimen">0.05</item>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d4ddab1..bcd121a 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1603,6 +1603,8 @@
<string name="fingerprint_acquired_too_bright">Too bright</string>
<!-- Message shown during fingerprint acquisition when a fingerprint must be adjusted.[CHAR LIMIT=50] -->
<string name="fingerprint_acquired_try_adjusting">Try adjusting</string>
+ <!-- Message shown during fingerprint acquisition when a fingeprint area has already been captured during enrollment [CHAR LIMIT=100] -->
+ <string name="fingerprint_acquired_immobile">Change the position of your finger slightly each time</string>
<!-- Array containing custom messages shown during fingerprint acquisision from vendor. Vendor is expected to add and translate these strings -->
<string-array name="fingerprint_acquired_vendor">
</string-array>
@@ -1661,9 +1663,9 @@
<!-- Notification name shown when the system requires the user to re-enroll their face. [CHAR LIMIT=NONE] -->
<string name="face_recalibrate_notification_name">Face Unlock</string>
<!-- Notification title shown when the system requires the user to re-enroll their face. [CHAR LIMIT=NONE] -->
- <string name="face_recalibrate_notification_title">Re-enroll your face</string>
+ <string name="face_recalibrate_notification_title">Issue with Face Unlock</string>
<!-- Notification content shown when the system requires the user to re-enroll their face. [CHAR LIMIT=NONE] -->
- <string name="face_recalibrate_notification_content">To improve recognition, please re-enroll your face</string>
+ <string name="face_recalibrate_notification_content">Tap to delete your face model, then add your face again</string>
<!-- Title of a notification that directs the user to set up Face Unlock by enrolling their face. [CHAR LIMIT=NONE] -->
<string name="face_setup_notification_title">Set up Face Unlock</string>
<!-- Contents of a notification that directs the user to set up face unlock by enrolling their face. [CHAR LIMIT=NONE] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 46a834a..ea28215 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1918,6 +1918,7 @@
<java-symbol type="bool" name="config_tintNotificationActionButtons" />
<java-symbol type="bool" name="config_dozeAfterScreenOffByDefault" />
<java-symbol type="bool" name="config_enableActivityRecognitionHardwareOverlay" />
+ <java-symbol type="bool" name="config_defaultAdasGnssLocationEnabled" />
<java-symbol type="bool" name="config_enableFusedLocationOverlay" />
<java-symbol type="bool" name="config_enableGeocoderOverlay" />
<java-symbol type="bool" name="config_enableGeofenceOverlay" />
@@ -2539,6 +2540,7 @@
<java-symbol type="string" name="fingerprint_error_hw_not_present" />
<java-symbol type="string" name="fingerprint_error_security_update_required" />
<java-symbol type="string" name="fingerprint_error_bad_calibration" />
+ <java-symbol type="string" name="fingerprint_acquired_immobile" />
<!-- Fingerprint config -->
<java-symbol type="integer" name="config_fingerprintMaxTemplatesPerUser"/>
@@ -4017,6 +4019,11 @@
<java-symbol type="bool" name="config_bugReportHandlerEnabled" />
<java-symbol type="string" name="config_defaultBugReportHandlerApp" />
+ <!-- For profcollect report uploader -->
+ <java-symbol type="bool" name="config_profcollectReportUploaderEnabled" />
+ <java-symbol type="string" name="config_defaultProfcollectReportUploaderApp" />
+ <java-symbol type="string" name="config_defaultProfcollectReportUploaderAction" />
+
<java-symbol type="string" name="usb_device_resolve_prompt_warn" />
<!-- For Accessibility system actions -->
@@ -4403,5 +4410,9 @@
<java-symbol type="bool" name="config_assistLongPressHomeEnabledDefault" />
<java-symbol type="bool" name="config_assistTouchGestureEnabledDefault" />
+ <java-symbol type="integer" name="config_hotwordDetectedResultMaxBundleSize" />
+
<java-symbol type="dimen" name="config_wallpaperDimAmount" />
+
+ <java-symbol type="bool" name="config_volumeShowRemoteSessions" />
</resources>
diff --git a/core/tests/coretests/src/android/app/appsearch/external/app/PutDocumentsRequestTest.java b/core/tests/coretests/src/android/app/appsearch/external/app/PutDocumentsRequestTest.java
deleted file mode 100644
index 6fad4b8d..0000000
--- a/core/tests/coretests/src/android/app/appsearch/external/app/PutDocumentsRequestTest.java
+++ /dev/null
@@ -1,44 +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 com.google.common.truth.Truth.assertThat;
-
-import com.android.server.appsearch.testing.AppSearchEmail;
-
-import com.google.common.collect.ImmutableSet;
-
-import org.junit.Test;
-
-import java.util.Set;
-
-public class PutDocumentsRequestTest {
-
- @Test
- public void addGenericDocument_byCollection() {
- Set<AppSearchEmail> emails =
- ImmutableSet.of(
- new AppSearchEmail.Builder("namespace", "test1").build(),
- new AppSearchEmail.Builder("namespace", "test2").build());
- PutDocumentsRequest request =
- new PutDocumentsRequest.Builder().addGenericDocuments(emails).build();
-
- assertThat(request.getGenericDocuments().get(0).getId()).isEqualTo("test1");
- assertThat(request.getGenericDocuments().get(1).getId()).isEqualTo("test2");
- }
-}
diff --git a/core/tests/coretests/src/android/app/appsearch/external/util/IndentingStringBuilderTest.java b/core/tests/coretests/src/android/app/appsearch/external/util/IndentingStringBuilderTest.java
new file mode 100644
index 0000000..057ecbd
--- /dev/null
+++ b/core/tests/coretests/src/android/app/appsearch/external/util/IndentingStringBuilderTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appsearch.util;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import org.junit.Test;
+
+public class IndentingStringBuilderTest {
+ @Test
+ public void testAppendIndentedStrings() {
+ IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
+ stringBuilder
+ .increaseIndentLevel()
+ .append("\nIndentLevel1\nIndentLevel1\n")
+ .decreaseIndentLevel()
+ .append("IndentLevel0,\n");
+
+ String str = stringBuilder.toString();
+ String expectedString = "\n IndentLevel1\n IndentLevel1\nIndentLevel0,\n";
+
+ assertThat(str).isEqualTo(expectedString);
+ }
+
+ @Test
+ public void testDecreaseIndentLevel_throwsException() {
+ IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
+
+ Exception e =
+ assertThrows(
+ IllegalStateException.class, () -> stringBuilder.decreaseIndentLevel());
+ assertThat(e).hasMessageThat().contains("Cannot set indent level below 0.");
+ }
+
+ @Test
+ public void testAppendIndentedObjects() {
+ IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
+ Object stringProperty = "String";
+ Object longProperty = 1L;
+ Object booleanProperty = true;
+
+ stringBuilder
+ .append(stringProperty)
+ .append("\n")
+ .increaseIndentLevel()
+ .append(longProperty)
+ .append("\n")
+ .decreaseIndentLevel()
+ .append(booleanProperty);
+
+ String str = stringBuilder.toString();
+ String expectedString = "String\n 1\ntrue";
+
+ assertThat(str).isEqualTo(expectedString);
+ }
+
+ @Test
+ public void testAppendIndentedStrings_doesNotIndentLineBreak() {
+ IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
+
+ stringBuilder
+ .append("\n")
+ .increaseIndentLevel()
+ .append("\n\n")
+ .decreaseIndentLevel()
+ .append("\n");
+
+ String str = stringBuilder.toString();
+ String expectedString = "\n\n\n\n";
+
+ assertThat(str).isEqualTo(expectedString);
+ }
+}
diff --git a/core/tests/coretests/src/android/os/VibratorTest.java b/core/tests/coretests/src/android/os/VibratorTest.java
index 8f9168b..0ece793 100644
--- a/core/tests/coretests/src/android/os/VibratorTest.java
+++ b/core/tests/coretests/src/android/os/VibratorTest.java
@@ -16,6 +16,8 @@
package android.os;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
import static junit.framework.TestCase.assertEquals;
import static org.mockito.ArgumentMatchers.any;
@@ -26,6 +28,7 @@
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import android.hardware.vibrator.IVibrator;
import android.media.AudioAttributes;
import android.platform.test.annotations.Presubmit;
@@ -70,6 +73,54 @@
}
@Test
+ public void areEffectsSupported_noVibrator_returnsAlwaysNo() {
+ SystemVibrator.AllVibratorsInfo info = new SystemVibrator.AllVibratorsInfo(
+ new VibratorInfo[0]);
+ assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_NO,
+ info.isEffectSupported(VibrationEffect.EFFECT_CLICK));
+ }
+
+ @Test
+ public void areEffectsSupported_unsupportedInOneVibrator_returnsNo() {
+ VibratorInfo supportedVibrator = new VibratorInfo.Builder(/* id= */ 1)
+ .setSupportedEffects(VibrationEffect.EFFECT_CLICK)
+ .build();
+ VibratorInfo unsupportedVibrator = new VibratorInfo.Builder(/* id= */ 2)
+ .setSupportedEffects(new int[0])
+ .build();
+ SystemVibrator.AllVibratorsInfo info = new SystemVibrator.AllVibratorsInfo(
+ new VibratorInfo[]{supportedVibrator, unsupportedVibrator});
+ assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_NO,
+ info.isEffectSupported(VibrationEffect.EFFECT_CLICK));
+ }
+
+ @Test
+ public void areEffectsSupported_unknownInOneVibrator_returnsUnknown() {
+ VibratorInfo supportedVibrator = new VibratorInfo.Builder(/* id= */ 1)
+ .setSupportedEffects(VibrationEffect.EFFECT_CLICK)
+ .build();
+ VibratorInfo unknownSupportVibrator = VibratorInfo.EMPTY_VIBRATOR_INFO;
+ SystemVibrator.AllVibratorsInfo info = new SystemVibrator.AllVibratorsInfo(
+ new VibratorInfo[]{supportedVibrator, unknownSupportVibrator});
+ assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_UNKNOWN,
+ info.isEffectSupported(VibrationEffect.EFFECT_CLICK));
+ }
+
+ @Test
+ public void arePrimitivesSupported_supportedInAllVibrators_returnsYes() {
+ VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
+ .setSupportedEffects(VibrationEffect.EFFECT_CLICK)
+ .build();
+ VibratorInfo secondVibrator = new VibratorInfo.Builder(/* id= */ 2)
+ .setSupportedEffects(VibrationEffect.EFFECT_CLICK)
+ .build();
+ SystemVibrator.AllVibratorsInfo info = new SystemVibrator.AllVibratorsInfo(
+ new VibratorInfo[]{firstVibrator, secondVibrator});
+ assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_YES,
+ info.isEffectSupported(VibrationEffect.EFFECT_CLICK));
+ }
+
+ @Test
public void arePrimitivesSupported_returnsArrayOfSameSize() {
assertEquals(0, mVibratorSpy.arePrimitivesSupported(new int[0]).length);
assertEquals(1, mVibratorSpy.arePrimitivesSupported(
@@ -80,6 +131,40 @@
}
@Test
+ public void arePrimitivesSupported_noVibrator_returnsAlwaysFalse() {
+ SystemVibrator.AllVibratorsInfo info = new SystemVibrator.AllVibratorsInfo(
+ new VibratorInfo[0]);
+ assertFalse(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK));
+ }
+
+ @Test
+ public void arePrimitivesSupported_unsupportedInOneVibrator_returnsFalse() {
+ VibratorInfo supportedVibrator = new VibratorInfo.Builder(/* id= */ 1)
+ .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 10)
+ .build();
+ VibratorInfo unsupportedVibrator = VibratorInfo.EMPTY_VIBRATOR_INFO;
+ SystemVibrator.AllVibratorsInfo info = new SystemVibrator.AllVibratorsInfo(
+ new VibratorInfo[]{supportedVibrator, unsupportedVibrator});
+ assertFalse(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK));
+ }
+
+ @Test
+ public void arePrimitivesSupported_supportedInAllVibrators_returnsTrue() {
+ VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
+ .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 5)
+ .build();
+ VibratorInfo secondVibrator = new VibratorInfo.Builder(/* id= */ 2)
+ .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 15)
+ .build();
+ SystemVibrator.AllVibratorsInfo info = new SystemVibrator.AllVibratorsInfo(
+ new VibratorInfo[]{firstVibrator, secondVibrator});
+ assertTrue(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK));
+ }
+
+ @Test
public void getPrimitivesDurations_returnsArrayOfSameSize() {
assertEquals(0, mVibratorSpy.getPrimitiveDurations(new int[0]).length);
assertEquals(1, mVibratorSpy.getPrimitiveDurations(
@@ -90,6 +175,40 @@
}
@Test
+ public void getPrimitivesDurations_noVibrator_returnsAlwaysZero() {
+ SystemVibrator.AllVibratorsInfo info = new SystemVibrator.AllVibratorsInfo(
+ new VibratorInfo[0]);
+ assertEquals(0, info.getPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK));
+ }
+
+ @Test
+ public void getPrimitivesDurations_unsupportedInOneVibrator_returnsZero() {
+ VibratorInfo supportedVibrator = new VibratorInfo.Builder(/* id= */ 1)
+ .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 10)
+ .build();
+ VibratorInfo unsupportedVibrator = VibratorInfo.EMPTY_VIBRATOR_INFO;
+ SystemVibrator.AllVibratorsInfo info = new SystemVibrator.AllVibratorsInfo(
+ new VibratorInfo[]{supportedVibrator, unsupportedVibrator});
+ assertEquals(0, info.getPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK));
+ }
+
+ @Test
+ public void getPrimitivesDurations_supportedInAllVibrators_returnsMaxDuration() {
+ VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
+ .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 10)
+ .build();
+ VibratorInfo secondVibrator = new VibratorInfo.Builder(/* id= */ 2)
+ .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 20)
+ .build();
+ SystemVibrator.AllVibratorsInfo info = new SystemVibrator.AllVibratorsInfo(
+ new VibratorInfo[]{firstVibrator, secondVibrator});
+ assertEquals(20, info.getPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK));
+ }
+
+ @Test
public void vibrate_withAudioAttributes_createsVibrationAttributesWithSameUsage() {
VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
AudioAttributes audioAttributes = new AudioAttributes.Builder().setUsage(
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index 89d2b74..72a145f 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -151,7 +151,7 @@
* Gets the {@link KeyStore} operation handle corresponding to the provided JCA crypto
* primitive.
*
- * <p>The following primitives are supported: {@link Cipher} and {@link Mac}.
+ * <p>The following primitives are supported: {@link Cipher}, {@link Signature} and {@link Mac}.
*
* @return KeyStore operation handle or {@code 0} if the provided primitive's KeyStore operation
* is not in progress.
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 70f03d2..f28ee82 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -117,7 +117,9 @@
<!-- This should be at least the size of bubble_expanded_view_padding; it is used to include
a slight touch slop around the expanded view. -->
<dimen name="bubble_expanded_view_slop">8dp</dimen>
- <!-- Default (and minimum) height of the expanded view shown when the bubble is expanded -->
+ <!-- Default (and minimum) height of the expanded view shown when the bubble is expanded.
+ If this value changes then R.dimen.bubble_expanded_view_min_height in CtsVerifier
+ should also be updated. -->
<dimen name="bubble_expanded_default_height">180dp</dimen>
<!-- On large screens the width of the expanded view is restricted to this size. -->
<dimen name="bubble_expanded_view_tablet_width">412dp</dimen>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index b2ac61c..cb27ad9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -249,6 +249,7 @@
!activeControl.getSurfacePosition().equals(lastSurfacePosition);
final boolean leashChanged =
!haveSameLeash(mImeSourceControl, activeControl);
+ final InsetsSourceControl lastImeControl = mImeSourceControl;
mImeSourceControl = activeControl;
if (mAnimation != null) {
if (positionChanged) {
@@ -262,6 +263,9 @@
removeImeSurface();
}
}
+ if (lastImeControl != null) {
+ lastImeControl.release(SurfaceControl::release);
+ }
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index 46db35a..670af96 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -288,6 +288,7 @@
// create splash screen view finished.
final SplashScreenViewSupplier viewSupplier = new SplashScreenViewSupplier();
final FrameLayout rootLayout = new FrameLayout(context);
+ rootLayout.setPadding(0, 0, 0, 0);
final Runnable setViewSynchronized = () -> {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "addSplashScreenView");
// waiting for setContentView before relayoutWindow
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index c770150..45a4f6c 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -331,6 +331,8 @@
mSkiaLayer.reset();
}
+ mProperties.mutateLayerProperties().mutableStretchEffect().clear();
+ mStretchMask.clear();
// Clear out the previous snapshot and the image filter the previous
// snapshot was created with whenever the layer changes.
mSnapshotResult.snapshot = nullptr;
diff --git a/libs/hwui/effects/StretchEffect.cpp b/libs/hwui/effects/StretchEffect.cpp
index 43f805d..17cd3ce 100644
--- a/libs/hwui/effects/StretchEffect.cpp
+++ b/libs/hwui/effects/StretchEffect.cpp
@@ -186,6 +186,7 @@
static const float ZERO = 0.f;
static const float INTERPOLATION_STRENGTH_VALUE = 0.7f;
+static const char CONTENT_TEXTURE[] = "uContentTexture";
sk_sp<SkShader> StretchEffect::getShader(float width, float height,
const sk_sp<SkImage>& snapshotImage,
@@ -207,7 +208,7 @@
mBuilder = std::make_unique<SkRuntimeShaderBuilder>(getStretchEffect());
}
- mBuilder->child("uContentTexture") =
+ mBuilder->child(CONTENT_TEXTURE) =
snapshotImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
SkSamplingOptions(SkFilterMode::kLinear), matrix);
mBuilder->uniform("uInterpolationStrength").set(&INTERPOLATION_STRENGTH_VALUE, 1);
@@ -226,7 +227,9 @@
mBuilder->uniform("viewportWidth").set(&width, 1);
mBuilder->uniform("viewportHeight").set(&height, 1);
- return mBuilder->makeShader(nullptr, false);
+ auto result = mBuilder->makeShader(nullptr, false);
+ mBuilder->child(CONTENT_TEXTURE) = nullptr;
+ return result;
}
sk_sp<SkRuntimeEffect> StretchEffect::getStretchEffect() {
diff --git a/libs/hwui/effects/StretchEffect.h b/libs/hwui/effects/StretchEffect.h
index 25777c2..3eab9f0 100644
--- a/libs/hwui/effects/StretchEffect.h
+++ b/libs/hwui/effects/StretchEffect.h
@@ -113,6 +113,10 @@
return !isEmpty();
}
+ void clear() {
+ mBuilder = nullptr;
+ }
+
private:
static sk_sp<SkRuntimeEffect> getStretchEffect();
mutable SkVector mStretchDirection{0, 0};
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index 4cd3616..ecdd4b6 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -214,6 +214,25 @@
*
* <p> When this bit is unset, the {@link #getAccumulatedDeltaRangeMeters()} corresponds to the
* carrier phase measurement plus an accumulated integer number of carrier half cycles.
+ *
+ * <p> For signals that have databits, the carrier phase tracking loops typically use a costas
+ * loop discriminator. This type of tracking loop introduces a half-cycle ambiguity that is
+ * resolved by searching through the received data for known patterns of databits (e.g. GPS uses
+ * the TLM word) which then determines the polarity of the incoming data and resolves the
+ * half-cycle ambiguity.
+ *
+ * <p>Before the half-cycle ambiguity has been resolved it is possible that the ADR_STATE_VALID
+ * flag is set:
+ *
+ * <ul>
+ * <li> In cases where ADR_STATE_HALF_CYCLE_REPORTED is not set, the
+ * ADR_STATE_HALF_CYCLE_RESOLVED flag will not be available. Here, a half wave length will be
+ * added to the returned accumulated delta range uncertainty to indicate the half cycle
+ * ambiguity.
+ * <li> In cases where ADR_STATE_HALF_CYCLE_REPORTED is set, half cycle ambiguity will be
+ * indicated via both the ADR_STATE_HALF_CYCLE_RESOLVED flag and as well a half wave length
+ * added to the returned accumulated delta range uncertainty.
+ * </ul>
*/
public static final int ADR_STATE_HALF_CYCLE_RESOLVED = (1<<3);
@@ -1039,9 +1058,6 @@
* with integer ambiguity resolution, to determine highly precise relative location between
* receivers.
*
- * <p>This includes ensuring that all half-cycle ambiguities are resolved before this value is
- * reported as {@link #ADR_STATE_VALID}.
- *
* <p>The alignment of the phase measurement will not be adjusted by the receiver so the
* in-phase and quadrature phase components will have a quarter cycle offset as they do when
* transmitted from the satellites. If the measurement is from a combination of the in-phase
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index c9e4e0a..5d5c0fc 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -122,6 +122,9 @@
boolean isLocationEnabledForUser(int userId);
void setLocationEnabledForUser(boolean enabled, int userId);
+ boolean isAdasGnssLocationEnabledForUser(int userId);
+ void setAdasGnssLocationEnabledForUser(boolean enabled, int userId);
+
void addTestProvider(String name, in ProviderProperties properties,
in List<String> locationTags, String packageName, @nullable String attributionTag);
void removeTestProvider(String provider, String packageName, @nullable String attributionTag);
diff --git a/location/java/android/location/LastLocationRequest.java b/location/java/android/location/LastLocationRequest.java
index 9ea8048..0970c1c 100644
--- a/location/java/android/location/LastLocationRequest.java
+++ b/location/java/android/location/LastLocationRequest.java
@@ -34,12 +34,15 @@
public final class LastLocationRequest implements Parcelable {
private final boolean mHiddenFromAppOps;
+ private final boolean mAdasGnssBypass;
private final boolean mLocationSettingsIgnored;
private LastLocationRequest(
boolean hiddenFromAppOps,
+ boolean adasGnssBypass,
boolean locationSettingsIgnored) {
mHiddenFromAppOps = hiddenFromAppOps;
+ mAdasGnssBypass = adasGnssBypass;
mLocationSettingsIgnored = locationSettingsIgnored;
}
@@ -56,6 +59,21 @@
}
/**
+ * Returns true if this request may access GNSS even if location settings would normally deny
+ * this, in order to enable automotive safety features. This field is only respected on
+ * automotive devices, and only if the client is recognized as a legitimate ADAS (Advanced
+ * Driving Assistance Systems) application.
+ *
+ * @return true if all limiting factors will be ignored to satisfy GNSS request
+ * @hide
+ */
+ // TODO: make this system api
+ public boolean isAdasGnssBypass() {
+ return mAdasGnssBypass;
+ }
+
+
+ /**
* Returns true if location settings, throttling, background location limits, and any other
* possible limiting factors will be ignored in order to satisfy this last location request.
*
@@ -65,12 +83,22 @@
return mLocationSettingsIgnored;
}
+ /**
+ * Returns true if any bypass flag is set on this request. For internal use only.
+ *
+ * @hide
+ */
+ public boolean isBypass() {
+ return mAdasGnssBypass || mLocationSettingsIgnored;
+ }
+
public static final @NonNull Parcelable.Creator<LastLocationRequest> CREATOR =
new Parcelable.Creator<LastLocationRequest>() {
@Override
public LastLocationRequest createFromParcel(Parcel in) {
return new LastLocationRequest(
/* hiddenFromAppOps= */ in.readBoolean(),
+ /* adasGnssBypass= */ in.readBoolean(),
/* locationSettingsIgnored= */ in.readBoolean());
}
@Override
@@ -86,6 +114,7 @@
@Override
public void writeToParcel(@NonNull Parcel parcel, int flags) {
parcel.writeBoolean(mHiddenFromAppOps);
+ parcel.writeBoolean(mAdasGnssBypass);
parcel.writeBoolean(mLocationSettingsIgnored);
}
@@ -99,12 +128,13 @@
}
LastLocationRequest that = (LastLocationRequest) o;
return mHiddenFromAppOps == that.mHiddenFromAppOps
+ && mAdasGnssBypass == that.mAdasGnssBypass
&& mLocationSettingsIgnored == that.mLocationSettingsIgnored;
}
@Override
public int hashCode() {
- return Objects.hash(mHiddenFromAppOps, mLocationSettingsIgnored);
+ return Objects.hash(mHiddenFromAppOps, mAdasGnssBypass, mLocationSettingsIgnored);
}
@NonNull
@@ -115,8 +145,11 @@
if (mHiddenFromAppOps) {
s.append("hiddenFromAppOps, ");
}
+ if (mAdasGnssBypass) {
+ s.append("adasGnssBypass, ");
+ }
if (mLocationSettingsIgnored) {
- s.append("locationSettingsIgnored, ");
+ s.append("settingsBypass, ");
}
if (s.length() > "LastLocationRequest[".length()) {
s.setLength(s.length() - 2);
@@ -131,6 +164,7 @@
public static final class Builder {
private boolean mHiddenFromAppOps;
+ private boolean mAdasGnssBypass;
private boolean mLocationSettingsIgnored;
/**
@@ -138,6 +172,7 @@
*/
public Builder() {
mHiddenFromAppOps = false;
+ mAdasGnssBypass = false;
mLocationSettingsIgnored = false;
}
@@ -146,6 +181,7 @@
*/
public Builder(@NonNull LastLocationRequest lastLocationRequest) {
mHiddenFromAppOps = lastLocationRequest.mHiddenFromAppOps;
+ mAdasGnssBypass = lastLocationRequest.mAdasGnssBypass;
mLocationSettingsIgnored = lastLocationRequest.mLocationSettingsIgnored;
}
@@ -164,6 +200,25 @@
}
/**
+ * If set to true, indicates that the client is an ADAS (Advanced Driving Assistance
+ * Systems) client, which requires access to GNSS even if location settings would normally
+ * deny this, in order to enable auto safety features. This field is only respected on
+ * automotive devices, and only if the client is recognized as a legitimate ADAS
+ * application. Defaults to false.
+ *
+ * <p>Permissions enforcement occurs when resulting location request is actually used, not
+ * when this method is invoked.
+ *
+ * @hide
+ */
+ // TODO: make this system api
+ @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+ public @NonNull LastLocationRequest.Builder setAdasGnssBypass(boolean adasGnssBypass) {
+ mAdasGnssBypass = adasGnssBypass;
+ return this;
+ }
+
+ /**
* If set to true, indicates that location settings, throttling, background location limits,
* and any other possible limiting factors should be ignored in order to satisfy this
* last location request. This is only intended for use in user initiated emergency
@@ -186,6 +241,7 @@
public @NonNull LastLocationRequest build() {
return new LastLocationRequest(
mHiddenFromAppOps,
+ mAdasGnssBypass,
mLocationSettingsIgnored);
}
}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index ae44c5e..526b84e 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -315,6 +315,33 @@
public static final String EXTRA_LOCATION_ENABLED = "android.location.extra.LOCATION_ENABLED";
/**
+ * Broadcast intent action when the ADAS (Advanced Driving Assistance Systems) GNSS location
+ * enabled state changes. Includes a boolean intent extra, {@link #EXTRA_ADAS_GNSS_ENABLED},
+ * with the enabled state of ADAS GNSS location. This broadcast only has meaning on automotive
+ * devices.
+ *
+ * @see #EXTRA_ADAS_GNSS_ENABLED
+ * @see #isAdasGnssLocationEnabled()
+ *
+ * @hide
+ */
+ // TODO: @SystemApi
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_ADAS_GNSS_ENABLED_CHANGED =
+ "android.location.action.ADAS_GNSS_ENABLED_CHANGED";
+
+ /**
+ * Intent extra included with {@link #ACTION_ADAS_GNSS_ENABLED_CHANGED} broadcasts, containing
+ * the boolean enabled state of ADAS GNSS location.
+ *
+ * @see #ACTION_ADAS_GNSS_ENABLED_CHANGED
+ *
+ * @hide
+ */
+ // TODO: @SystemApi
+ public static final String EXTRA_ADAS_GNSS_ENABLED = "android.location.extra.ADAS_GNSS_ENABLED";
+
+ /**
* Broadcast intent action indicating that a high power location requests
* has either started or stopped being active. The current state of
* active location requests should be read from AppOpsManager using
@@ -621,6 +648,42 @@
}
/**
+ * Returns the current enabled/disabled state of ADAS (Advanced Driving Assistance Systems)
+ * GNSS location access for the given user. This controls safety critical automotive access to
+ * GNSS location. This only has meaning on automotive devices.
+ *
+ * @return true if ADAS location is enabled and false if ADAS location is disabled.
+ *
+ * @hide
+ */
+ //TODO: @SystemApi
+ public boolean isAdasGnssLocationEnabled() {
+ try {
+ return mService.isAdasGnssLocationEnabledForUser(mContext.getUser().getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Enables or disables ADAS (Advanced Driving Assistance Systems) GNSS location access for the
+ * given user. This only has meaning on automotive devices.
+ *
+ * @param enabled true to enable ADAS location and false to disable ADAS location.
+ *
+ * @hide
+ */
+ // TODO: @SystemApi
+ @RequiresPermission(WRITE_SECURE_SETTINGS)
+ public void setAdasGnssLocationEnabled(boolean enabled) {
+ try {
+ mService.setAdasGnssLocationEnabledForUser(enabled, mContext.getUser().getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Returns the current enabled/disabled status of the given provider. To listen for changes, see
* {@link #PROVIDERS_CHANGED_ACTION}.
*
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index a3842a1..b48e596 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -194,6 +194,7 @@
private float mMinUpdateDistanceMeters;
private final long mMaxUpdateDelayMillis;
private boolean mHideFromAppOps;
+ private final boolean mAdasGnssBypass;
private boolean mLocationSettingsIgnored;
private boolean mLowPower;
private @Nullable WorkSource mWorkSource;
@@ -236,7 +237,7 @@
if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
quality = POWER_NONE;
} else if (LocationManager.GPS_PROVIDER.equals(provider)) {
- quality = ACCURACY_FINE;
+ quality = QUALITY_HIGH_ACCURACY;
} else {
quality = POWER_LOW;
}
@@ -289,6 +290,7 @@
float minUpdateDistanceMeters,
long maxUpdateDelayMillis,
boolean hiddenFromAppOps,
+ boolean adasGnssBypass,
boolean locationSettingsIgnored,
boolean lowPower,
WorkSource workSource) {
@@ -302,8 +304,9 @@
mMinUpdateDistanceMeters = minUpdateDistanceMeters;
mMaxUpdateDelayMillis = maxUpdateDelayMillis;
mHideFromAppOps = hiddenFromAppOps;
- mLowPower = lowPower;
+ mAdasGnssBypass = adasGnssBypass;
mLocationSettingsIgnored = locationSettingsIgnored;
+ mLowPower = lowPower;
mWorkSource = Objects.requireNonNull(workSource);
}
@@ -339,15 +342,15 @@
switch (quality) {
case POWER_HIGH:
// fall through
- case ACCURACY_FINE:
+ case QUALITY_HIGH_ACCURACY:
mQuality = QUALITY_HIGH_ACCURACY;
break;
- case ACCURACY_BLOCK:
+ case QUALITY_BALANCED_POWER_ACCURACY:
mQuality = QUALITY_BALANCED_POWER_ACCURACY;
break;
case POWER_LOW:
// fall through
- case ACCURACY_CITY:
+ case QUALITY_LOW_POWER:
mQuality = QUALITY_LOW_POWER;
break;
case POWER_NONE:
@@ -648,6 +651,21 @@
}
/**
+ * Returns true if this request may access GNSS even if location settings would normally deny
+ * this, in order to enable automotive safety features. This field is only respected on
+ * automotive devices, and only if the client is recognized as a legitimate ADAS (Advanced
+ * Driving Assistance Systems) application.
+ *
+ * @return true if all limiting factors will be ignored to satisfy GNSS request
+ *
+ * @hide
+ */
+ // TODO: @SystemApi
+ public boolean isAdasGnssBypass() {
+ return mAdasGnssBypass;
+ }
+
+ /**
* @hide
* @deprecated LocationRequests should be treated as immutable.
*/
@@ -673,6 +691,15 @@
}
/**
+ * Returns true if any bypass flag is set on this request. For internal use only.
+ *
+ * @hide
+ */
+ public boolean isBypass() {
+ return mAdasGnssBypass || mLocationSettingsIgnored;
+ }
+
+ /**
* @hide
* @deprecated LocationRequests should be treated as immutable.
*/
@@ -749,6 +776,7 @@
/* minUpdateDistanceMeters= */ in.readFloat(),
/* maxUpdateDelayMillis= */ in.readLong(),
/* hiddenFromAppOps= */ in.readBoolean(),
+ /* adasGnssBypass= */ in.readBoolean(),
/* locationSettingsIgnored= */ in.readBoolean(),
/* lowPower= */ in.readBoolean(),
/* workSource= */ in.readTypedObject(WorkSource.CREATOR));
@@ -777,6 +805,7 @@
parcel.writeFloat(mMinUpdateDistanceMeters);
parcel.writeLong(mMaxUpdateDelayMillis);
parcel.writeBoolean(mHideFromAppOps);
+ parcel.writeBoolean(mAdasGnssBypass);
parcel.writeBoolean(mLocationSettingsIgnored);
parcel.writeBoolean(mLowPower);
parcel.writeTypedObject(mWorkSource, 0);
@@ -801,6 +830,7 @@
&& Float.compare(that.mMinUpdateDistanceMeters, mMinUpdateDistanceMeters) == 0
&& mMaxUpdateDelayMillis == that.mMaxUpdateDelayMillis
&& mHideFromAppOps == that.mHideFromAppOps
+ && mAdasGnssBypass == that.mAdasGnssBypass
&& mLocationSettingsIgnored == that.mLocationSettingsIgnored
&& mLowPower == that.mLowPower
&& Objects.equals(mProvider, that.mProvider)
@@ -866,8 +896,11 @@
if (mHideFromAppOps) {
s.append(", hiddenFromAppOps");
}
+ if (mAdasGnssBypass) {
+ s.append(", adasGnssBypass");
+ }
if (mLocationSettingsIgnored) {
- s.append(", locationSettingsIgnored");
+ s.append(", settingsBypass");
}
if (mWorkSource != null && !mWorkSource.isEmpty()) {
s.append(", ").append(mWorkSource);
@@ -889,6 +922,7 @@
private float mMinUpdateDistanceMeters;
private long mMaxUpdateDelayMillis;
private boolean mHiddenFromAppOps;
+ private boolean mAdasGnssBypass;
private boolean mLocationSettingsIgnored;
private boolean mLowPower;
@Nullable private WorkSource mWorkSource;
@@ -908,6 +942,7 @@
mMinUpdateDistanceMeters = 0;
mMaxUpdateDelayMillis = 0;
mHiddenFromAppOps = false;
+ mAdasGnssBypass = false;
mLocationSettingsIgnored = false;
mLowPower = false;
mWorkSource = null;
@@ -925,6 +960,7 @@
mMinUpdateDistanceMeters = locationRequest.mMinUpdateDistanceMeters;
mMaxUpdateDelayMillis = locationRequest.mMaxUpdateDelayMillis;
mHiddenFromAppOps = locationRequest.mHideFromAppOps;
+ mAdasGnssBypass = locationRequest.mAdasGnssBypass;
mLocationSettingsIgnored = locationRequest.mLocationSettingsIgnored;
mLowPower = locationRequest.mLowPower;
mWorkSource = locationRequest.mWorkSource;
@@ -977,10 +1013,10 @@
public @NonNull Builder setQuality(@NonNull Criteria criteria) {
switch (criteria.getAccuracy()) {
case Criteria.ACCURACY_COARSE:
- mQuality = ACCURACY_BLOCK;
+ mQuality = QUALITY_BALANCED_POWER_ACCURACY;
break;
case Criteria.ACCURACY_FINE:
- mQuality = ACCURACY_FINE;
+ mQuality = QUALITY_HIGH_ACCURACY;
break;
default: {
if (criteria.getPowerRequirement() == Criteria.POWER_HIGH) {
@@ -1092,6 +1128,25 @@
}
/**
+ * If set to true, indicates that the client is an ADAS (Advanced Driving Assistance
+ * Systems) client, which requires access to GNSS even if location settings would normally
+ * deny this, in order to enable auto safety features. This field is only respected on
+ * automotive devices, and only if the client is recognized as a legitimate ADAS
+ * application. Defaults to false.
+ *
+ * <p>Permissions enforcement occurs when resulting location request is actually used, not
+ * when this method is invoked.
+ *
+ * @hide
+ */
+ // TODO: @SystemApi
+ @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+ public @NonNull Builder setAdasGnssBypass(boolean adasGnssBypass) {
+ mAdasGnssBypass = adasGnssBypass;
+ return this;
+ }
+
+ /**
* If set to true, indicates that location settings, throttling, background location limits,
* and any other possible limiting factors should be ignored in order to satisfy this
* request. This is only intended for use in user initiated emergency situations, and
@@ -1171,6 +1226,7 @@
mMinUpdateDistanceMeters,
mMaxUpdateDelayMillis,
mHiddenFromAppOps,
+ mAdasGnssBypass,
mLocationSettingsIgnored,
mLowPower,
new WorkSource(mWorkSource));
diff --git a/location/java/android/location/provider/ProviderRequest.java b/location/java/android/location/provider/ProviderRequest.java
index b72d365..4f33a52 100644
--- a/location/java/android/location/provider/ProviderRequest.java
+++ b/location/java/android/location/provider/ProviderRequest.java
@@ -44,12 +44,19 @@
public static final long INTERVAL_DISABLED = Long.MAX_VALUE;
public static final @NonNull ProviderRequest EMPTY_REQUEST = new ProviderRequest(
- INTERVAL_DISABLED, QUALITY_BALANCED_POWER_ACCURACY, 0, false, false, new WorkSource());
+ INTERVAL_DISABLED,
+ QUALITY_BALANCED_POWER_ACCURACY,
+ 0,
+ false,
+ false,
+ false,
+ new WorkSource());
private final long mIntervalMillis;
private final @Quality int mQuality;
private final long mMaxUpdateDelayMillis;
private final boolean mLowPower;
+ private final boolean mAdasGnssBypass;
private final boolean mLocationSettingsIgnored;
private final WorkSource mWorkSource;
@@ -72,12 +79,14 @@
@Quality int quality,
long maxUpdateDelayMillis,
boolean lowPower,
+ boolean adasGnssBypass,
boolean locationSettingsIgnored,
@NonNull WorkSource workSource) {
mIntervalMillis = intervalMillis;
mQuality = quality;
mMaxUpdateDelayMillis = maxUpdateDelayMillis;
mLowPower = lowPower;
+ mAdasGnssBypass = adasGnssBypass;
mLocationSettingsIgnored = locationSettingsIgnored;
mWorkSource = Objects.requireNonNull(workSource);
}
@@ -126,6 +135,18 @@
}
/**
+ * Returns true if this request may access GNSS even if location settings would normally deny
+ * this, in order to enable automotive safety features. This field is only respected on
+ * automotive devices, and only if the client is recognized as a legitimate ADAS (Advanced
+ * Driving Assistance Systems) application.
+ *
+ * @hide
+ */
+ public boolean isAdasGnssBypass() {
+ return mAdasGnssBypass;
+ }
+
+ /**
* Whether the provider should ignore all location settings, user consents, power restrictions
* or any other restricting factors and always satisfy this request to the best of their
* ability. This should only be used in case of a user initiated emergency.
@@ -135,6 +156,15 @@
}
/**
+ * Returns true if any bypass flag is set on this request.
+ *
+ * @hide
+ */
+ public boolean isBypass() {
+ return mAdasGnssBypass || mLocationSettingsIgnored;
+ }
+
+ /**
* The power blame for this provider request.
*/
public @NonNull WorkSource getWorkSource() {
@@ -153,6 +183,7 @@
/* quality= */ in.readInt(),
/* maxUpdateDelayMillis= */ in.readLong(),
/* lowPower= */ in.readBoolean(),
+ /* adasGnssBypass= */ in.readBoolean(),
/* locationSettingsIgnored= */ in.readBoolean(),
/* workSource= */ in.readTypedObject(WorkSource.CREATOR));
}
@@ -176,6 +207,7 @@
parcel.writeInt(mQuality);
parcel.writeLong(mMaxUpdateDelayMillis);
parcel.writeBoolean(mLowPower);
+ parcel.writeBoolean(mAdasGnssBypass);
parcel.writeBoolean(mLocationSettingsIgnored);
parcel.writeTypedObject(mWorkSource, flags);
}
@@ -198,6 +230,7 @@
&& mQuality == that.mQuality
&& mMaxUpdateDelayMillis == that.mMaxUpdateDelayMillis
&& mLowPower == that.mLowPower
+ && mAdasGnssBypass == that.mAdasGnssBypass
&& mLocationSettingsIgnored == that.mLocationSettingsIgnored
&& mWorkSource.equals(that.mWorkSource);
}
@@ -229,8 +262,11 @@
if (mLowPower) {
s.append(", lowPower");
}
+ if (mAdasGnssBypass) {
+ s.append(", adasGnssBypass");
+ }
if (mLocationSettingsIgnored) {
- s.append(", locationSettingsIgnored");
+ s.append(", settingsBypass");
}
if (!mWorkSource.isEmpty()) {
s.append(", ").append(mWorkSource);
@@ -246,10 +282,12 @@
* A Builder for {@link ProviderRequest}s.
*/
public static final class Builder {
+
private long mIntervalMillis = INTERVAL_DISABLED;
private int mQuality = QUALITY_BALANCED_POWER_ACCURACY;
private long mMaxUpdateDelayMillis = 0;
private boolean mLowPower;
+ private boolean mAdasGnssBypass;
private boolean mLocationSettingsIgnored;
private WorkSource mWorkSource = new WorkSource();
@@ -299,6 +337,16 @@
}
/**
+ * Sets whether this ADAS request should bypass GNSS settings. False by default.
+ *
+ * @hide
+ */
+ public @NonNull Builder setAdasGnssBypass(boolean adasGnssBypass) {
+ this.mAdasGnssBypass = adasGnssBypass;
+ return this;
+ }
+
+ /**
* Sets whether location settings should be ignored. False by default.
*/
public @NonNull Builder setLocationSettingsIgnored(boolean locationSettingsIgnored) {
@@ -326,6 +374,7 @@
mQuality,
mMaxUpdateDelayMillis,
mLowPower,
+ mAdasGnssBypass,
mLocationSettingsIgnored,
mWorkSource);
}
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 860d88a..d8f48c2 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -101,6 +101,8 @@
private int mBatteryLevel;
private int mBatteryScale;
private int mDeviceType;
+ private String mHostType;
+ private boolean mSkipThumbForHost = false;
private MtpServer mServer;
private MtpStorageManager mManager;
@@ -192,6 +194,7 @@
MtpConstants.DEVICE_PROPERTY_IMAGE_SIZE,
MtpConstants.DEVICE_PROPERTY_BATTERY_LEVEL,
MtpConstants.DEVICE_PROPERTY_PERCEIVED_DEVICE_TYPE,
+ MtpConstants.DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO,
};
@VisibleForNative
@@ -408,6 +411,8 @@
}
context.deleteDatabase(devicePropertiesName);
}
+ mHostType = "";
+ mSkipThumbForHost = false;
}
@VisibleForNative
@@ -672,12 +677,24 @@
@VisibleForNative
private int getDeviceProperty(int property, long[] outIntValue, char[] outStringValue) {
+ int length;
+ String value;
+
switch (property) {
case MtpConstants.DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER:
case MtpConstants.DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
// writable string properties kept in shared preferences
- String value = mDeviceProperties.getString(Integer.toString(property), "");
- int length = value.length();
+ value = mDeviceProperties.getString(Integer.toString(property), "");
+ length = value.length();
+ if (length > 255) {
+ length = 255;
+ }
+ value.getChars(0, length, outStringValue, 0);
+ outStringValue[length] = 0;
+ return MtpConstants.RESPONSE_OK;
+ case MtpConstants.DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO:
+ value = mHostType;
+ length = value.length();
if (length > 255) {
length = 255;
}
@@ -717,6 +734,14 @@
e.putString(Integer.toString(property), stringValue);
return (e.commit() ? MtpConstants.RESPONSE_OK
: MtpConstants.RESPONSE_GENERAL_ERROR);
+ case MtpConstants.DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO:
+ mHostType = stringValue;
+ if (stringValue.startsWith("Android/")) {
+ Log.d(TAG, "setDeviceProperty." + Integer.toHexString(property)
+ + "=" + stringValue);
+ mSkipThumbForHost = true;
+ }
+ return MtpConstants.RESPONSE_OK;
}
return MtpConstants.RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
@@ -838,6 +863,10 @@
outLongs[0] = thumbOffsetAndSize != null ? thumbOffsetAndSize[1] : 0;
outLongs[1] = exif.getAttributeInt(ExifInterface.TAG_PIXEL_X_DIMENSION, 0);
outLongs[2] = exif.getAttributeInt(ExifInterface.TAG_PIXEL_Y_DIMENSION, 0);
+ if (mSkipThumbForHost) {
+ Log.d(TAG, "getThumbnailInfo: Skip runtime thumbnail.");
+ return true;
+ }
if (exif.getThumbnailRange() != null) {
if ((outLongs[0] == 0) || (outLongs[1] == 0) || (outLongs[2] == 0)) {
Log.d(TAG, "getThumbnailInfo: check thumb info:"
@@ -880,6 +909,10 @@
try {
ExifInterface exif = new ExifInterface(path);
+ if (mSkipThumbForHost) {
+ Log.d(TAG, "getThumbnailData: Skip runtime thumbnail.");
+ return exif.getThumbnail();
+ }
if (exif.getThumbnailRange() != null)
return exif.getThumbnail();
} catch (IOException e) {
diff --git a/media/java/android/mtp/MtpDevice.java b/media/java/android/mtp/MtpDevice.java
index e8b04ed..ec92591 100644
--- a/media/java/android/mtp/MtpDevice.java
+++ b/media/java/android/mtp/MtpDevice.java
@@ -170,6 +170,18 @@
}
/**
+ * Set device property SESSION_INITIATOR_VERSION_INFO
+ *
+ * @param propertyStr string value for device property SESSION_INITIATOR_VERSION_INFO
+ * @return -1 for error, 0 for success
+ *
+ * {@hide}
+ */
+ public int setDevicePropertyInitVersion(@NonNull String propertyStr) {
+ return native_set_device_property_init_version(propertyStr);
+ }
+
+ /**
* Returns the list of IDs for all storage units on this device
* Information about each storage unit can be accessed via {@link #getStorageInfo}.
*
@@ -421,6 +433,7 @@
private native boolean native_open(String deviceName, int fd);
private native void native_close();
private native MtpDeviceInfo native_get_device_info();
+ private native int native_set_device_property_init_version(String propertyStr);
private native int[] native_get_storage_ids();
private native MtpStorageInfo native_get_storage_info(int storageId);
private native int[] native_get_object_handles(int storageId, int format, int objectHandle);
diff --git a/media/java/android/mtp/MtpDeviceInfo.java b/media/java/android/mtp/MtpDeviceInfo.java
index 0304ee3..8851451 100644
--- a/media/java/android/mtp/MtpDeviceInfo.java
+++ b/media/java/android/mtp/MtpDeviceInfo.java
@@ -31,6 +31,7 @@
private String mSerialNumber;
private int[] mOperationsSupported;
private int[] mEventsSupported;
+ private int[] mDevicePropertySupported;
// only instantiated via JNI
private MtpDeviceInfo() {
@@ -144,6 +145,21 @@
}
/**
+ * Returns Device property code supported by the device.
+ *
+ * @return supported Device property code. Can be null if device does not provide the property.
+ *
+ * @see MtpConstants#DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER
+ * @see MtpConstants#DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME
+ * @see MtpConstants#DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO
+ *
+ * {@hide}
+ */
+ public final @NonNull int[] getDevicePropertySupported() {
+ return mDevicePropertySupported;
+ }
+
+ /**
* Returns if the given operation is supported by the device or not.
* @param code Operation code.
* @return If the given operation is supported by the device or not.
@@ -162,6 +178,17 @@
}
/**
+ * Returns if the given Device property is supported by the device or not.
+ * @param code Device property code.
+ * @return If the given Device property is supported by the device or not.
+ *
+ * {@hide}
+ */
+ public boolean isDevicePropertySupported(int code) {
+ return isSupported(mDevicePropertySupported, code);
+ }
+
+ /**
* Returns if the code set contains code.
* @hide
*/
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index ffed474..a77bc9f 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -1131,6 +1131,7 @@
{ MTP_DEVICE_PROPERTY_IMAGE_SIZE, MTP_TYPE_STR },
{ MTP_DEVICE_PROPERTY_BATTERY_LEVEL, MTP_TYPE_UINT8 },
{ MTP_DEVICE_PROPERTY_PERCEIVED_DEVICE_TYPE, MTP_TYPE_UINT32 },
+ { MTP_DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO, MTP_TYPE_STR },
};
bool MtpDatabase::getObjectPropertyInfo(MtpObjectProperty property, int& type) {
@@ -1289,6 +1290,7 @@
switch (property) {
case MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER:
case MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
+ case MTP_DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO:
writable = true;
// fall through
FALLTHROUGH_INTENDED;
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index 3d2b00fe..ac89fecd 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -72,6 +72,7 @@
static jfieldID field_deviceInfo_serialNumber;
static jfieldID field_deviceInfo_operationsSupported;
static jfieldID field_deviceInfo_eventsSupported;
+static jfieldID field_deviceInfo_devicePropertySupported;
// MtpStorageInfo fields
static jfieldID field_storageInfo_storageId;
@@ -129,6 +130,8 @@
GetFieldIDOrDie(env, clazz_deviceInfo, "mOperationsSupported", "[I");
field_deviceInfo_eventsSupported =
GetFieldIDOrDie(env, clazz_deviceInfo, "mEventsSupported", "[I");
+ field_deviceInfo_devicePropertySupported =
+ GetFieldIDOrDie(env, clazz_deviceInfo, "mDevicePropertySupported", "[I");
clazz_storageInfo =
(jclass)env->NewGlobalRef(FindClassOrDie(env, "android/mtp/MtpStorageInfo"));
@@ -377,9 +380,65 @@
}
}
+ assert(deviceInfo->mDeviceProperties);
+ {
+ const size_t size = deviceInfo->mDeviceProperties->size();
+ ScopedLocalRef<jintArray> events(env, static_cast<jintArray>(env->NewIntArray(size)));
+ {
+ ScopedIntArrayRW elements(env, events.get());
+ if (elements.get() == NULL) {
+ ALOGE("Could not create devicePropertySupported element.");
+ return NULL;
+ }
+ for (size_t i = 0; i < size; ++i) {
+ elements[i] = static_cast<int>(deviceInfo->mDeviceProperties->at(i));
+ }
+ env->SetObjectField(info, field_deviceInfo_devicePropertySupported, events.get());
+ }
+ }
+
return info;
}
+static jint
+android_mtp_MtpDevice_set_device_property_init_version(JNIEnv *env, jobject thiz,
+ jstring property_str) {
+ MtpDevice* const device = get_device_from_object(env, thiz);
+
+ if (!device) {
+ ALOGD("%s device is null\n", __func__);
+ env->ThrowNew(clazz_io_exception, "Failed to obtain MtpDevice.");
+ return -1;
+ }
+
+ const char *propertyStr = env->GetStringUTFChars(property_str, NULL);
+ if (propertyStr == NULL) {
+ return -1;
+ }
+
+ MtpProperty* property = new MtpProperty(MTP_DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO,
+ MTP_TYPE_STR, true);
+ if (!property) {
+ env->ThrowNew(clazz_io_exception, "Failed to obtain property.");
+ return -1;
+ }
+
+ if (property->getDataType() != MTP_TYPE_STR) {
+ env->ThrowNew(clazz_io_exception, "Unexpected property data type.");
+ return -1;
+ }
+
+ property->setCurrentValue(propertyStr);
+ if (!device->setDevicePropValueStr(property)) {
+ env->ThrowNew(clazz_io_exception, "Failed to obtain property value.");
+ return -1;
+ }
+
+ env->ReleaseStringUTFChars(property_str, propertyStr);
+
+ return 0;
+}
+
static jintArray
android_mtp_MtpDevice_get_storage_ids(JNIEnv *env, jobject thiz)
{
@@ -847,6 +906,8 @@
{"native_close", "()V", (void *)android_mtp_MtpDevice_close},
{"native_get_device_info", "()Landroid/mtp/MtpDeviceInfo;",
(void *)android_mtp_MtpDevice_get_device_info},
+ {"native_set_device_property_init_version", "(Ljava/lang/String;)I",
+ (void *)android_mtp_MtpDevice_set_device_property_init_version},
{"native_get_storage_ids", "()[I", (void *)android_mtp_MtpDevice_get_storage_ids},
{"native_get_storage_info", "(I)Landroid/mtp/MtpStorageInfo;",
(void *)android_mtp_MtpDevice_get_storage_info},
diff --git a/packages/CompanionDeviceManager/OWNERS b/packages/CompanionDeviceManager/OWNERS
index da723b3..734d8b6 100644
--- a/packages/CompanionDeviceManager/OWNERS
+++ b/packages/CompanionDeviceManager/OWNERS
@@ -1 +1 @@
-eugenesusla@google.com
\ No newline at end of file
+include /core/java/android/companion/OWNERS
\ No newline at end of file
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-gu/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-gu/strings.xml
new file mode 100644
index 0000000..1fe4c5c
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-gu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"છોડી દો"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-te/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-te/strings.xml
new file mode 100644
index 0000000..22a6f59
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-te/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"విస్మరించు"</string>
+</resources>
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml
index 7d9b4d7..6acd9ff 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml
@@ -33,7 +33,7 @@
android:background="?android:attr/colorPrimary"
android:theme="@style/Theme.CollapsingToolbar.Settings">
- <com.android.settingslib.collapsingtoolbar.AdjustableToolbarLayout
+ <com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_one_line_height"
@@ -59,7 +59,7 @@
android:transitionName="shared_element_view"
app:layout_collapseMode="pin"/>
- </com.android.settingslib.collapsingtoolbar.AdjustableToolbarLayout>
+ </com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<FrameLayout
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/styles.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/styles.xml
index 2a72a1a..63d397c 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/styles.xml
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/styles.xml
@@ -17,6 +17,7 @@
<resources>
<style name="CollapsingToolbarTitle.Collapsed" parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title">
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ <item name="android:textSize">20dp</item>
</style>
<style name="CollapsingToolbarTitle.Expanded" parent="CollapsingToolbarTitle.Collapsed">
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/AdjustableToolbarLayout.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/AdjustableToolbarLayout.java
deleted file mode 100644
index 0e7e595..0000000
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/AdjustableToolbarLayout.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.collapsingtoolbar;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.google.android.material.appbar.CollapsingToolbarLayout;
-
-/**
- * A customized version of CollapsingToolbarLayout that can apply different font size based on the
- * line count of its title.
- */
-public class AdjustableToolbarLayout extends CollapsingToolbarLayout {
-
- private static final int TOOLBAR_MAX_LINE_NUMBER = 2;
-
- public AdjustableToolbarLayout(@NonNull Context context) {
- this(context, null);
-
- }
-
- public AdjustableToolbarLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public AdjustableToolbarLayout(@NonNull Context context, @Nullable AttributeSet attrs,
- int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- initCollapsingToolbar();
- }
-
- @SuppressWarnings("RestrictTo")
- private void initCollapsingToolbar() {
- this.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right, int bottom,
- int oldLeft, int oldTop, int oldRight, int oldBottom) {
- v.removeOnLayoutChangeListener(this);
- final int count = getLineCount();
- if (count > TOOLBAR_MAX_LINE_NUMBER) {
- final ViewGroup.LayoutParams lp = getLayoutParams();
- lp.height = getResources()
- .getDimensionPixelSize(R.dimen.toolbar_three_lines_height);
- setScrimVisibleHeightTrigger(
- getResources().getDimensionPixelSize(
- R.dimen.scrim_visible_height_trigger_three_lines));
- setLayoutParams(lp);
- } else if (count == TOOLBAR_MAX_LINE_NUMBER) {
- final ViewGroup.LayoutParams lp = getLayoutParams();
- lp.height = getResources()
- .getDimensionPixelSize(R.dimen.toolbar_two_lines_height);
- setScrimVisibleHeightTrigger(
- getResources().getDimensionPixelSize(
- R.dimen.scrim_visible_height_trigger_two_lines));
- setLayoutParams(lp);
- }
- }
- });
- }
-}
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
index 4ae120a..dbcecf1 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
@@ -35,10 +35,18 @@
* A base Activity that has a collapsing toolbar layout is used for the activities intending to
* enable the collapsing toolbar function.
*/
-public class CollapsingToolbarBaseActivity extends SettingsTransitionActivity {
+public class CollapsingToolbarBaseActivity extends SettingsTransitionActivity implements
+ AppBarLayout.OnOffsetChangedListener {
+ private static final int TOOLBAR_MAX_LINE_NUMBER = 2;
+ private static final int FULLY_EXPANDED_OFFSET = 0;
+ private static final String KEY_IS_TOOLBAR_COLLAPSED = "is_toolbar_collapsed";
+
+ @Nullable
private CollapsingToolbarLayout mCollapsingToolbarLayout;
+ @Nullable
private AppBarLayout mAppBarLayout;
+ private boolean mIsToolbarCollapsed;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -48,6 +56,12 @@
super.setContentView(R.layout.collapsing_toolbar_base_layout);
mCollapsingToolbarLayout = findViewById(R.id.collapsing_toolbar);
mAppBarLayout = findViewById(R.id.app_bar);
+ mAppBarLayout.addOnOffsetChangedListener(this);
+ if (savedInstanceState != null) {
+ mIsToolbarCollapsed = savedInstanceState.getBoolean(KEY_IS_TOOLBAR_COLLAPSED);
+ }
+
+ initCollapsingToolbar();
disableCollapsingToolbarLayoutScrollingBehavior();
final Toolbar toolbar = findViewById(R.id.action_bar);
@@ -107,14 +121,43 @@
return true;
}
+ @Override
+ public void onOffsetChanged(AppBarLayout appBarLayout, int offset) {
+ if (offset == FULLY_EXPANDED_OFFSET) {
+ mIsToolbarCollapsed = false;
+ } else {
+ mIsToolbarCollapsed = true;
+ }
+ }
+
+ @Override
+ protected void onSaveInstanceState(@NonNull Bundle outState) {
+ super.onSaveInstanceState(outState);
+ if (isChangingConfigurations()) {
+ outState.putBoolean(KEY_IS_TOOLBAR_COLLAPSED, mIsToolbarCollapsed);
+ }
+ }
+
/**
* Returns an instance of collapsing toolbar.
*/
+ @Nullable
public CollapsingToolbarLayout getCollapsingToolbarLayout() {
return mCollapsingToolbarLayout;
}
+ /**
+ * Return an instance of app bar.
+ */
+ @Nullable
+ public AppBarLayout getAppBarLayout() {
+ return mAppBarLayout;
+ }
+
private void disableCollapsingToolbarLayoutScrollingBehavior() {
+ if (mAppBarLayout == null) {
+ return;
+ }
final CoordinatorLayout.LayoutParams params =
(CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();
final AppBarLayout.Behavior behavior = new AppBarLayout.Behavior();
@@ -127,4 +170,39 @@
});
params.setBehavior(behavior);
}
+
+ @SuppressWarnings("RestrictTo")
+ private void initCollapsingToolbar() {
+ if (mCollapsingToolbarLayout == null || mAppBarLayout == null) {
+ return;
+ }
+ mCollapsingToolbarLayout.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ v.removeOnLayoutChangeListener(this);
+ if (mIsToolbarCollapsed) {
+ return;
+ }
+ final int count = mCollapsingToolbarLayout.getLineCount();
+ if (count > TOOLBAR_MAX_LINE_NUMBER) {
+ final ViewGroup.LayoutParams lp = mCollapsingToolbarLayout.getLayoutParams();
+ lp.height = getResources()
+ .getDimensionPixelSize(R.dimen.toolbar_three_lines_height);
+ mCollapsingToolbarLayout.setScrimVisibleHeightTrigger(
+ getResources().getDimensionPixelSize(
+ R.dimen.scrim_visible_height_trigger_three_lines));
+ mCollapsingToolbarLayout.setLayoutParams(lp);
+ } else if (count == TOOLBAR_MAX_LINE_NUMBER) {
+ final ViewGroup.LayoutParams lp = mCollapsingToolbarLayout.getLayoutParams();
+ lp.height = getResources()
+ .getDimensionPixelSize(R.dimen.toolbar_two_lines_height);
+ mCollapsingToolbarLayout.setScrimVisibleHeightTrigger(
+ getResources().getDimensionPixelSize(
+ R.dimen.scrim_visible_height_trigger_two_lines));
+ mCollapsingToolbarLayout.setLayoutParams(lp);
+ }
+ }
+ });
+ }
}
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseFragment.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseFragment.java
index c4c74ff..faa73ff 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseFragment.java
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseFragment.java
@@ -25,21 +25,31 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.fragment.app.Fragment;
+import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.CollapsingToolbarLayout;
/**
* A base fragment that has a collapsing toolbar layout for enabling the collapsing toolbar design.
*/
-public abstract class CollapsingToolbarBaseFragment extends Fragment {
+public abstract class CollapsingToolbarBaseFragment extends Fragment implements
+ AppBarLayout.OnOffsetChangedListener {
+
+ private static final int TOOLBAR_MAX_LINE_NUMBER = 2;
+ private static final int FULLY_EXPANDED_OFFSET = 0;
+ private static final String KEY_IS_TOOLBAR_COLLAPSED = "is_toolbar_collapsed";
@Nullable
private CollapsingToolbarLayout mCollapsingToolbarLayout;
+ @Nullable
+ private AppBarLayout mAppBarLayout;
@NonNull
private Toolbar mToolbar;
@NonNull
private FrameLayout mContentFrameLayout;
+ private boolean mIsToolbarCollapsed;
@Nullable
@Override
@@ -48,6 +58,13 @@
final View view = inflater.inflate(R.layout.collapsing_toolbar_base_layout, container,
false);
mCollapsingToolbarLayout = view.findViewById(R.id.collapsing_toolbar);
+ mAppBarLayout = view.findViewById(R.id.app_bar);
+ mAppBarLayout.addOnOffsetChangedListener(this);
+ if (savedInstanceState != null) {
+ mIsToolbarCollapsed = savedInstanceState.getBoolean(KEY_IS_TOOLBAR_COLLAPSED);
+ }
+ initCollapsingToolbar();
+ disableCollapsingToolbarLayoutScrollingBehavior();
mToolbar = view.findViewById(R.id.action_bar);
mContentFrameLayout = view.findViewById(R.id.content_frame);
return view;
@@ -60,6 +77,31 @@
requireActivity().setActionBar(mToolbar);
}
+ @Override
+ public void onSaveInstanceState(@NonNull Bundle outState) {
+ super.onSaveInstanceState(outState);
+ if (getActivity().isChangingConfigurations()) {
+ outState.putBoolean(KEY_IS_TOOLBAR_COLLAPSED, mIsToolbarCollapsed);
+ }
+ }
+
+ @Override
+ public void onOffsetChanged(AppBarLayout appBarLayout, int offset) {
+ if (offset == FULLY_EXPANDED_OFFSET) {
+ mIsToolbarCollapsed = false;
+ } else {
+ mIsToolbarCollapsed = true;
+ }
+ }
+
+ /**
+ * Return an instance of app bar.
+ */
+ @Nullable
+ public AppBarLayout getAppBarLayout() {
+ return mAppBarLayout;
+ }
+
/**
* Return the collapsing toolbar layout.
*/
@@ -75,4 +117,56 @@
public FrameLayout getContentFrameLayout() {
return mContentFrameLayout;
}
+
+ private void disableCollapsingToolbarLayoutScrollingBehavior() {
+ if (mAppBarLayout == null) {
+ return;
+ }
+ final CoordinatorLayout.LayoutParams params =
+ (CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();
+ final AppBarLayout.Behavior behavior = new AppBarLayout.Behavior();
+ behavior.setDragCallback(
+ new AppBarLayout.Behavior.DragCallback() {
+ @Override
+ public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
+ return false;
+ }
+ });
+ params.setBehavior(behavior);
+ }
+
+ @SuppressWarnings("RestrictTo")
+ private void initCollapsingToolbar() {
+ if (mCollapsingToolbarLayout == null || mAppBarLayout == null) {
+ return;
+ }
+ mCollapsingToolbarLayout.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ v.removeOnLayoutChangeListener(this);
+ if (mIsToolbarCollapsed) {
+ return;
+ }
+ final int count = mCollapsingToolbarLayout.getLineCount();
+ if (count > TOOLBAR_MAX_LINE_NUMBER) {
+ final ViewGroup.LayoutParams lp = mCollapsingToolbarLayout.getLayoutParams();
+ lp.height = getResources()
+ .getDimensionPixelSize(R.dimen.toolbar_three_lines_height);
+ mCollapsingToolbarLayout.setScrimVisibleHeightTrigger(
+ getResources().getDimensionPixelSize(
+ R.dimen.scrim_visible_height_trigger_three_lines));
+ mCollapsingToolbarLayout.setLayoutParams(lp);
+ } else if (count == TOOLBAR_MAX_LINE_NUMBER) {
+ final ViewGroup.LayoutParams lp = mCollapsingToolbarLayout.getLayoutParams();
+ lp.height = getResources()
+ .getDimensionPixelSize(R.dimen.toolbar_two_lines_height);
+ mCollapsingToolbarLayout.setScrimVisibleHeightTrigger(
+ getResources().getDimensionPixelSize(
+ R.dimen.scrim_visible_height_trigger_two_lines));
+ mCollapsingToolbarLayout.setLayoutParams(lp);
+ }
+ }
+ });
+ }
}
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
index 9610c94..46f1e03 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
@@ -25,6 +25,7 @@
<style name="Switch.SettingsLib" parent="@android:style/Widget.Material.CompoundButton.Switch">
<item name="android:switchMinWidth">52dp</item>
+ <item name="android:minHeight">@dimen/settingslib_preferred_minimum_touch_target</item>
<item name="android:track">@drawable/settingslib_switch_track</item>
<item name="android:thumb">@drawable/settingslib_switch_thumb</item>
</style>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 89bb9e8..fa3f34c 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Bynaam"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Voeg gas by"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Verwyder gas"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Stel gassessie terug"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gas"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Neem \'n foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Kies \'n prent"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index bc1bd16..7b4c832 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"ቅጽል ስም"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"እንግዳን አክል"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"እንግዳን አስወግድ"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"እንግዳን ዳግም አስጀምር"</string>
<string name="guest_nickname" msgid="6332276931583337261">"እንግዳ"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ፎቶ አንሳ"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ምስል ይምረጡ"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index f04aaac..611f2c4 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"উপনাম"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"অতিথি যোগ কৰক"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"অতিথি আঁতৰাওক"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"অতিথিৰ ছেশ্বন ৰিছেট কৰক"</string>
<string name="guest_nickname" msgid="6332276931583337261">"অতিথি"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"এখন ফট’ তোলক"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"এখন প্ৰতিচ্ছবি বাছনি কৰক"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index b7cf11a..c50a22d 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Ləqəb"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Qonaq əlavə edin"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Qonağı silin"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Qonaq sessiyasını sıfırlayın"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Qonaq"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Foto çəkin"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Şəkil seçin"</string>
@@ -576,7 +575,7 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Deaktiv"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiv"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Bu dəyişikliyin tətbiq edilməsi üçün cihaz yenidən başladılmalıdır. İndi yenidən başladın və ya ləğv edin."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Simli qulaqlıq"</string>
+ <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Naqilli qulaqlıq"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktiv"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Deaktiv"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Operator şəbəkəsinin dəyişilməsi"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 97c281a..e26d065 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -567,8 +567,7 @@
<string name="user_nickname" msgid="262624187455825083">"Nadimak"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ukloni gosta"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Resetuj sesiju gosta"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gost"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Slikaj"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Odaberi sliku"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 09e5843..7899fa6 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Псевдоним"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Добавяне на гост"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Премахване на госта"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Нулиране на сесията като гост"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Гост"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Правене на снимка"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Избиране на изображение"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 88abe33..9eb20f9 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -567,8 +567,7 @@
<string name="user_nickname" msgid="262624187455825083">"Nadimak"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ukloni gosta"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Poništi sesiju gosta"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gost"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Snimite fotografiju"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Odaberite sliku"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index f499ab6..d3590bf 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Àlies"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Afegeix un convidat"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Suprimeix el convidat"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Restableix el convidat"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Convidat"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Fes una foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Tria una imatge"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 4d07eff..5c664b9 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -568,8 +568,7 @@
<string name="user_nickname" msgid="262624187455825083">"Přezdívka"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Přidat hosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Odstranit hosta"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Resetovat hosta"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Host"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Pořídit fotku"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Vybrat obrázek"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 98f5301..59bfab8 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Ψευδώνυμο"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Προσθήκη επισκέπτη"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Κατάργηση επισκέπτη"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Επαναφορά περιόδου επισκέπτη"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Επισκέπτης"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Λήψη φωτογραφίας"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Επιλογή εικόνας"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 6ff4854..26c7b2c 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Apodo"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Añadir invitado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Quitar invitado"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Restablecer invitado"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Invitado"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Hacer foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Seleccionar una imagen"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index ef7b7db..194aeaf 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Hüüdnimi"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Lisa külaline"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Eemalda külaline"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Lähtesta külastajaseanss"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Külaline"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Pildistage"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Valige pilt"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 9350610..33e2314 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -528,7 +528,7 @@
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Audio-gailu kableduna"</string>
<string name="help_label" msgid="3528360748637781274">"Laguntza eta iritziak"</string>
<string name="storage_category" msgid="2287342585424631813">"Biltegiratzea"</string>
- <string name="shared_data_title" msgid="1017034836800864953">"Partekatutako datuak"</string>
+ <string name="shared_data_title" msgid="1017034836800864953">"Datu partekatuak"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Ikusi eta aldatu partekatutako datuak"</string>
<string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Ez dago erabiltzaile honen datu partekaturik."</string>
<string name="shared_data_query_failure_text" msgid="3489828881998773687">"Errore bat gertatu da datu partekatuak eskuratzean. Saiatu berriro."</string>
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Goitizena"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Gehitu gonbidatua"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Kendu gonbidatua"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Berrezarri gonbidatuentzako saioa"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gonbidatua"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Atera argazki bat"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Aukeratu irudi bat"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 964162b..a11a00a 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Lempinimi"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Lisää vieras"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Poista vieras"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Nollaa vieras"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Vieras"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Ota kuva"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Valitse kuva"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 73f98ec..dba912e 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Alcume"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Engadir convidado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Quitar convidado"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Restablecer sesión de convidado"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Tirar foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Escoller imaxe"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 5620d94..bc74092 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"प्रचलित नाम"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"मेहमान जोड़ें"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"मेहमान हटाएं"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"मेहमान के तौर पर ब्राउज़ करने का सेशन रीसेट करें"</string>
<string name="guest_nickname" msgid="6332276931583337261">"मेहमान"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"फ़ोटो खींचें"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"कोई इमेज चुनें"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 0ff35f8..d18d34c 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -567,8 +567,7 @@
<string name="user_nickname" msgid="262624187455825083">"Nadimak"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodavanje gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Uklanjanje gosta"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Poništi gostujuću sesiju"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gost"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Fotografiraj"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Odaberi sliku"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 9bd4d12..3ad3590 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Becenév"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Vendég hozzáadása"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Vendég munkamenet eltávolítása"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Vendég munkamenet visszaállítása"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Vendég"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Fotó készítése"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Kép kiválasztása"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 662a673..da92e7d 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Gælunafn"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Bæta gesti við"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Fjarlægja gest"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Endurstilla gestastillingu"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gestur"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Taka mynd"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Velja mynd"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 2c2d11f..6f7565e 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Aggiungi ospite"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Rimuovi ospite"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Reimposta sessione Ospite"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Ospite"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Scatta una foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Scegli un\'immagine"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index ddae3c7..70dd9e7 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Лақап ат"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Қонақ қосу"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Қонақты жою"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Қонақ сеансын әдепкі күйге қайтару"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Қонақ"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Фотосуретке түсіру"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Сурет таңдау"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index d970e95..26595f5 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"ឈ្មោះហៅក្រៅ"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"បញ្ចូលភ្ញៀវ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ដកភ្ញៀវចេញ"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"កំណត់ភ្ញៀវឡើងវិញ"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ភ្ញៀវ"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ថតរូប"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ជ្រើសរើសរូបភាព"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 8bad320..b36ef8d 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"ಅಡ್ಡ ಹೆಸರು"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ಅತಿಥಿಯನ್ನು ಸೇರಿಸಿ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ಅತಿಥಿಯನ್ನು ತೆಗೆದುಹಾಕಿ"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"ಅತಿಥಿಯನ್ನು ಮರುಹೊಂದಿಸಿ"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ಅತಿಥಿ"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ಫೋಟೋ ತೆಗೆದುಕೊಳ್ಳಿ"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ಚಿತ್ರವನ್ನು ಆರಿಸಿ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 3383602..ad0ad1fb 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -568,8 +568,7 @@
<string name="user_nickname" msgid="262624187455825083">"Slapyvardis"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Pridėti svečią"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Pašalinti svečią"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Iš naujo nustatyti svečią"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Svečias"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Fotografuoti"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Pasirinkti vaizdą"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index d655afc..586de6fc 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -567,8 +567,7 @@
<string name="user_nickname" msgid="262624187455825083">"Segvārds"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Pievienot viesi"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Noņemt viesi"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Atiestatīt viesa sesiju"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Viesis"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Uzņemt fotoattēlu"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Izvēlēties attēlu"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index bd7f074..0d0f345 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Прекар"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Додајте гостин"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Отстрани гостин"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Ресетирајте го гостинот"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Гостин"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Фотографирајте"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Одберете слика"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 1e80ccd..655be1a7 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"വിളിപ്പേര്"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"അതിഥിയെ ചേർക്കുക"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"അതിഥിയെ നീക്കം ചെയ്യുക"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"അതിഥിയെ റീസെറ്റ് ചെയ്യുക"</string>
<string name="guest_nickname" msgid="6332276931583337261">"അതിഥി"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ഒരു ഫോട്ടോ എടുക്കുക"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ഒരു ചിത്രം തിരഞ്ഞെടുക്കുക"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 40b65ef..07ed369 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Хоч"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Зочин нэмэх"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Зочин хасах"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Зочныг шинэчлэх"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Зочин"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Зураг авах"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Зураг сонгох"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 6a46ede..fe8e837 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"टोपणनाव"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"अतिथी जोडा"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"अतिथी काढून टाका"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"अतिथी सेशन रीसेट करा"</string>
<string name="guest_nickname" msgid="6332276931583337261">"अतिथी"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"फोटो काढा"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"इमेज निवडा"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 7156a8e..b383ad8 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"နာမည်ပြောင်"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ဧည့်သည့် ထည့်ရန်"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ဧည့်သည်ကို ဖယ်ထုတ်ရန်"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"ဧည့်သည်ကို ပြင်ဆင်သတ်မှတ်ရန်"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ဧည့်သည်"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ဓာတ်ပုံရိုက်ရန်"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ပုံရွေးရန်"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index bb93a29..84c231f 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Kallenavn"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Legg til en gjest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Fjern gjesten"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Tilbakestill gjest"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gjest"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Ta et bilde"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Velg et bilde"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index a33bbf3..1837eab 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Bijnaam"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Gast toevoegen"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Gast verwijderen"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Gastsessie resetten"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gast"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Foto maken"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Afbeelding kiezen"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 5f410a8..bd77d88 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -568,8 +568,7 @@
<string name="user_nickname" msgid="262624187455825083">"Pseudonim"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gościa"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Usuń gościa"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Resetuj sesję gościa"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gość"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Zrób zdjęcie"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Wybierz obraz"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 3c8d928..e39b58b 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Apelido"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Adicionar convidado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remover convidado"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Redefinir sessão de visitante"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Tirar uma foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Escolher uma imagem"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index fc98aa7..a5c0d1d 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Alcunha"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Adicionar convidado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remover convidado"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Repor convidado"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Tirar uma foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Escolher uma imagem"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 3c8d928..e39b58b 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Apelido"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Adicionar convidado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remover convidado"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Redefinir sessão de visitante"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Tirar uma foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Escolher uma imagem"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 4db2f31..e1b0390 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -567,8 +567,7 @@
<string name="user_nickname" msgid="262624187455825083">"Pseudonim"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Adăugați un invitat"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ștergeți invitatul"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Resetați sesiunea pentru invitați"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Invitat"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Faceți o fotografie"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Alegeți o imagine"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 0bcdc23..1e5fce5 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -568,8 +568,7 @@
<string name="user_nickname" msgid="262624187455825083">"Псевдоним"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Добавить гостя"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Удалить аккаунт гостя"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Сбросить гостевой сеанс"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Гость"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Сделать снимок"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Выбрать фото"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index ef12ad3..09c0bf9 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -568,8 +568,7 @@
<string name="user_nickname" msgid="262624187455825083">"Prezývka"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Pridať hosťa"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Odobrať hosťa"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Obnoviť reláciu hosťa"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Hosť"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Odfotiť"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Vybrať obrázok"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index cbdfefc..b698c19 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -568,8 +568,7 @@
<string name="user_nickname" msgid="262624187455825083">"Vzdevek"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodajanje gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Odstranitev gosta"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Ponastavi gosta"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gost"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Fotografiranje"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Izberi sliko"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 3859be9..b3c23b6 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -567,8 +567,7 @@
<string name="user_nickname" msgid="262624187455825083">"Надимак"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Додај госта"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Уклони госта"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Ресетуј сесију госта"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Гост"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Сликај"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Одабери слику"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 7dcca0d..124c063 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Smeknamn"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Lägg till gäst"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ta bort gäst"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Återställ gästsession"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gäst"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Ta ett foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Välj en bild"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index b7aff72..7f67b88 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -452,7 +452,7 @@
<string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="7703677921000858479">"แท็บเล็ตอาจปิดเครื่องในไม่ช้า (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
<string name="power_remaining_duration_shutdown_imminent" product="device" msgid="4374784375644214578">"อุปกรณ์อาจปิดเครื่องในไม่ช้า (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
- <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"อีก <xliff:g id="TIME">%1$s</xliff:g> จึงจะเต็ม"</string>
+ <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"อีก <xliff:g id="TIME">%1$s</xliff:g>จึงจะเต็ม"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - อีก <xliff:g id="TIME">%2$s</xliff:g> จึงจะเต็ม"</string>
<string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - จำกัดการชาร์จชั่วคราว"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"ไม่ทราบ"</string>
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"ชื่อเล่น"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"เพิ่มผู้ใช้ชั่วคราว"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"นำผู้ใช้ชั่วคราวออก"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"รีเซ็ตผู้เข้าร่วม"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ผู้ใช้ชั่วคราว"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ถ่ายรูป"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"เลือกรูปภาพ"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 6d1f6ab..cc7db29 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Magdagdag ng bisita"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Alisin ang bisita"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"I-reset ang bisita"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Bisita"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Kumuha ng larawan"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Pumili ng larawan"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 82e481b..2cb1076 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -568,8 +568,7 @@
<string name="user_nickname" msgid="262624187455825083">"Псевдонім"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Додати гостя"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Видалити гостя"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Скинути сеанс у режимі \"Гість\""</string>
<string name="guest_nickname" msgid="6332276931583337261">"Гість"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Зробити фотографію"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Вибрати зображення"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 7f4e30a..3e11124 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Nik"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Mehmon kiritish"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Mehmonni olib tashlash"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Mehmon seansini tiklash"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Mehmon"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Suratga olish"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Rasm tanlash"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 2fe791a..0fa97e2 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Isiteketiso"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Engeza isivakashi"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Susa isihambeli"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Setha kabusha isivakashi"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Isihambeli"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Thatha isithombe"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Khetha isithombe"</string>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 8c092ae..604310a 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -454,6 +454,14 @@
android:finishOnCloseSystemDialogs="true">
</activity>
+ <!-- started from SensoryPrivacyService -->
+ <activity android:name=".sensorprivacy.television.TvUnblockSensorActivity"
+ android:exported="true"
+ android:permission="android.permission.MANAGE_SENSOR_PRIVACY"
+ android:theme="@style/BottomSheet"
+ android:finishOnCloseSystemDialogs="true">
+ </activity>
+
<!-- started from UsbDeviceSettingsManager -->
<activity android:name=".usb.UsbAccessoryUriActivity"
diff --git a/packages/SystemUI/res-keyguard/values-fa/strings.xml b/packages/SystemUI/res-keyguard/values-fa/strings.xml
index 149b313..0a036c8 100644
--- a/packages/SystemUI/res-keyguard/values-fa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fa/strings.xml
@@ -85,7 +85,7 @@
<string name="kg_login_too_many_attempts" msgid="4519957179182578690">"تلاشهای زیادی برای کشیدن الگو صورت گرفته است"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"پین خود را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه تایپ کردید. \n\nپس از <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"گذرواژه خود را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه تایپ کردید. \n\nپس از <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"الگوی باز کردن قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدید. \n\nلطفاً پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"الگوی بازگشایی قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدهاید. \n\nلطفاً پساز <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"کد پین سیمکارت اشتباه است، اکنون برای باز کردن قفل دستگاهتان باید با شرکت مخابراتی تماس بگیرید."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
<item quantity="one">کد پین سیمکارت اشتباه است، <xliff:g id="NUMBER_1">%d</xliff:g> بار دیگر میتوانید تلاش کنید.</item>
diff --git a/packages/SystemUI/res-keyguard/values-gu/strings.xml b/packages/SystemUI/res-keyguard/values-gu/strings.xml
index af43cf7..a41cce7 100644
--- a/packages/SystemUI/res-keyguard/values-gu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gu/strings.xml
@@ -38,7 +38,7 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ચાર્જિંગ"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ઝડપથી ચાર્જિંગ"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ધીમેથી ચાર્જિંગ"</string>
- <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ચાર્જિંગ હંગામી રૂપે પ્રતિબંધિત કરવામાં આવ્યું છે"</string>
+ <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ચાર્જિંગ હંગામીરૂપે પ્રતિબંધિત કરવામાં આવ્યું છે"</string>
<string name="keyguard_low_battery" msgid="1868012396800230904">"તમારું ચાર્જર કનેક્ટ કરો."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"અનલૉક કરવા માટે મેનૂ દબાવો."</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"નેટવર્ક લૉક થયું"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml
index b307544f..0692aef 100644
--- a/packages/SystemUI/res-keyguard/values-ne/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml
@@ -36,7 +36,7 @@
<string name="keyguard_charged" msgid="5478247181205188995">"चार्ज भयो"</string>
<string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • तारविनै चार्ज गर्दै"</string>
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • चार्ज गरिँदै"</string>
- <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • द्रुत गतिमा चार्ज गरिँदै"</string>
+ <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • द्रुत गतिमा चार्ज गरिँदै छ"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • मन्द गतिमा चार्ज गरिँदै"</string>
<string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • चार्जिङ केही समयका लागि सीमित पारिएको छ"</string>
<string name="keyguard_low_battery" msgid="1868012396800230904">"तपाईंको चार्जर जोड्नुहोस्।"</string>
diff --git a/packages/SystemUI/res-product/values-fa/strings.xml b/packages/SystemUI/res-product/values-fa/strings.xml
index 52fa2d8..cd98ef6 100644
--- a/packages/SystemUI/res-product/values-fa/strings.xml
+++ b/packages/SystemUI/res-product/values-fa/strings.xml
@@ -38,8 +38,8 @@
<string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="3280816298678433681">"<xliff:g id="NUMBER_0">%1$d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشتهاید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر، نمایه کاری پاک میشود که با آن همه دادههای نمایه حذف میشود."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4417100487251371559">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل رایانه لوحی داشتهاید. نمایه کاری پاک میشود که با آن همه دادههای نمایه حذف میشود."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشتهاید. نمایه کاری پاک میشود که با آن همه دادههای نمایه حذف میشود."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"شما الگوی باز کردن قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدهاید. بعد از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته میشود که با استفاده از یک حساب ایمیل قفل رایانه لوحی خود را باز کنید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"شما الگوی باز کردن قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدهاید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته میشود که با استفاده از یک حساب ایمیل قفل تلفن را باز کنید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"الگوی بازگشایی قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدهاید. بعداز <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته میشود که بااستفاده از یک حساب ایمیل قفل رایانه لوحیتان را باز کنید.\n\n لطفاً پساز <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"الگوی بازگشایی قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدهاید. پساز <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته میشود که بااستفاده از یک حساب ایمیل قفل تلفن را باز کنید.\n\n لطفاً پساز <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"برای گزینههای بیشتر، قفل تلفن را باز کنید"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"برای گزینههای بیشتر، قفل رایانه لوحی را باز کنید"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"برای گزینههای بیشتر، قفل دستگاه را باز کنید"</string>
diff --git a/packages/SystemUI/res/anim/tv_bottom_sheet_button_state_list_animator.xml b/packages/SystemUI/res/anim/tv_bottom_sheet_button_state_list_animator.xml
new file mode 100644
index 0000000..fc3b4ed
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_bottom_sheet_button_state_list_animator.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<selector
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_focused="true">
+ <set>
+ <objectAnimator
+ android:duration="200"
+ android:propertyName="scaleX"
+ android:valueFrom="1.0"
+ android:valueTo="@dimen/bottom_sheet_button_selection_scaled"
+ android:valueType="floatType"/>
+ <objectAnimator
+ android:duration="200"
+ android:propertyName="scaleY"
+ android:valueFrom="1.0"
+ android:valueTo="@dimen/bottom_sheet_button_selection_scaled"
+ android:valueType="floatType"/>
+ </set>
+ </item>
+ <item android:state_focused="false">
+ <set>
+ <objectAnimator
+ android:duration="200"
+ android:propertyName="scaleX"
+ android:valueFrom="@dimen/bottom_sheet_button_selection_scaled"
+ android:valueTo="1.0"
+ android:valueType="floatType"/>
+ <objectAnimator
+ android:duration="200"
+ android:propertyName="scaleY"
+ android:valueFrom="@dimen/bottom_sheet_button_selection_scaled"
+ android:valueTo="1.0"
+ android:valueType="floatType"/>
+ </set>
+ </item>
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml b/packages/SystemUI/res/anim/tv_bottom_sheet_enter.xml
similarity index 61%
copy from packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml
copy to packages/SystemUI/res/anim/tv_bottom_sheet_enter.xml
index 93f8724..cace36d 100644
--- a/packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml
+++ b/packages/SystemUI/res/anim/tv_bottom_sheet_enter.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2019 The Android Open Source Project
+ ~ Copyright (C) 2021 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -15,11 +15,9 @@
~ limitations under the License.
-->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
-
- <corners android:radius="20dp"/>
- <solid android:color="@color/tv_audio_recording_indicator_icon_background"/>
- <stroke android:width="1dp" android:color="@color/tv_audio_recording_indicator_stroke"/>
-
-</shape>
\ No newline at end of file
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@android:interpolator/decelerate_quint">
+ <translate android:fromYDelta="100%"
+ android:toYDelta="0"
+ android:duration="900"/>
+</set>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml b/packages/SystemUI/res/anim/tv_bottom_sheet_exit.xml
similarity index 61%
copy from packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml
copy to packages/SystemUI/res/anim/tv_bottom_sheet_exit.xml
index 93f8724..f7efe7cd 100644
--- a/packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml
+++ b/packages/SystemUI/res/anim/tv_bottom_sheet_exit.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2019 The Android Open Source Project
+ ~ Copyright (C) 2021 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -15,11 +15,9 @@
~ limitations under the License.
-->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
-
- <corners android:radius="20dp"/>
- <solid android:color="@color/tv_audio_recording_indicator_icon_background"/>
- <stroke android:width="1dp" android:color="@color/tv_audio_recording_indicator_stroke"/>
-
-</shape>
\ No newline at end of file
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@android:interpolator/decelerate_quint">
+ <translate android:fromYDelta="0"
+ android:toYDelta="100%"
+ android:duration="500"/>
+</set>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/tv_privacy_chip_collapse.xml b/packages/SystemUI/res/anim/tv_privacy_chip_collapse.xml
new file mode 100644
index 0000000..e6ceeb9
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_privacy_chip_collapse.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:ordering="together"
+ android:interpolator="@interpolator/tv_privacy_chip_collapse_interpolator"
+ android:duration="@integer/privacy_chip_animation_millis">
+ <objectAnimator
+ android:propertyName="height"
+ android:valueTo="@dimen/privacy_chip_dot_size"
+ android:valueType="floatType"/>
+ <objectAnimator
+ android:propertyName="marginEnd"
+ android:valueTo="@dimen/privacy_chip_dot_margin_horizontal"
+ android:valueType="floatType"/>
+ <objectAnimator
+ android:propertyName="radius"
+ android:valueTo="@dimen/privacy_chip_dot_radius"
+ android:valueType="floatType"/>
+ <objectAnimator
+ android:propertyName="dotAlpha"
+ android:valueTo="255"
+ android:valueType="intType"/>
+ <objectAnimator
+ android:propertyName="bgAlpha"
+ android:valueTo="255"
+ android:valueType="intType"/>
+</set>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/tv_privacy_chip_expand.xml b/packages/SystemUI/res/anim/tv_privacy_chip_expand.xml
new file mode 100644
index 0000000..4a510ae
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_privacy_chip_expand.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:ordering="together"
+ android:interpolator="@interpolator/tv_privacy_chip_expand_interpolator"
+ android:duration="@integer/privacy_chip_animation_millis">
+ <objectAnimator
+ android:propertyName="height"
+ android:valueTo="@dimen/privacy_chip_height"
+ android:valueType="floatType"/>
+ <objectAnimator
+ android:propertyName="marginEnd"
+ android:valueTo="0"
+ android:valueType="floatType"/>
+ <objectAnimator
+ android:propertyName="radius"
+ android:valueTo="@dimen/privacy_chip_radius"
+ android:valueType="floatType"/>
+ <objectAnimator
+ android:propertyName="dotAlpha"
+ android:valueTo="255"
+ android:valueType="intType"/>
+ <objectAnimator
+ android:propertyName="bgAlpha"
+ android:valueTo="0"
+ android:valueType="intType"/>
+</set>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/tv_privacy_chip_fade_in.xml b/packages/SystemUI/res/anim/tv_privacy_chip_fade_in.xml
new file mode 100644
index 0000000..701489a
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_privacy_chip_fade_in.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:ordering="together"
+ android:interpolator="@interpolator/tv_privacy_chip_collapse_interpolator"
+ android:duration="@integer/privacy_chip_animation_millis">
+ <objectAnimator
+ android:propertyName="dotAlpha"
+ android:valueTo="255"
+ android:valueType="intType"/>
+</set>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/tv_privacy_chip_fade_out.xml b/packages/SystemUI/res/anim/tv_privacy_chip_fade_out.xml
new file mode 100644
index 0000000..fa13471
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_privacy_chip_fade_out.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:ordering="together"
+ android:interpolator="@interpolator/tv_privacy_chip_collapse_interpolator"
+ android:duration="@integer/privacy_chip_animation_millis">
+ <objectAnimator
+ android:propertyName="dotAlpha"
+ android:valueTo="0"
+ android:valueType="intType"/>
+ <objectAnimator
+ android:propertyName="bgAlpha"
+ android:valueTo="0"
+ android:valueType="intType"/>
+</set>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml b/packages/SystemUI/res/color/bottom_sheet_button_background_color.xml
similarity index 61%
copy from packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml
copy to packages/SystemUI/res/color/bottom_sheet_button_background_color.xml
index 93f8724..9b0bae0 100644
--- a/packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml
+++ b/packages/SystemUI/res/color/bottom_sheet_button_background_color.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2019 The Android Open Source Project
+ ~ Copyright (C) 2021 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -14,12 +14,8 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
-
- <corners android:radius="20dp"/>
- <solid android:color="@color/tv_audio_recording_indicator_icon_background"/>
- <stroke android:width="1dp" android:color="@color/tv_audio_recording_indicator_stroke"/>
-
-</shape>
\ No newline at end of file
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_focused="true"
+ android:color="@color/bottom_sheet_button_background_color_focused"/>
+ <item android:color="@color/bottom_sheet_button_background_color_unfocused"/>
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml b/packages/SystemUI/res/color/bottom_sheet_button_text_color.xml
similarity index 61%
copy from packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml
copy to packages/SystemUI/res/color/bottom_sheet_button_text_color.xml
index 93f8724..05248f1 100644
--- a/packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml
+++ b/packages/SystemUI/res/color/bottom_sheet_button_text_color.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2019 The Android Open Source Project
+ ~ Copyright (C) 2021 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -14,12 +14,8 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
-
- <corners android:radius="20dp"/>
- <solid android:color="@color/tv_audio_recording_indicator_icon_background"/>
- <stroke android:width="1dp" android:color="@color/tv_audio_recording_indicator_stroke"/>
-
-</shape>
\ No newline at end of file
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_focused="true"
+ android:color="@color/bottom_sheet_button_text_color_focused"/>
+ <item android:color="@color/bottom_sheet_button_text_color_unfocused"/>
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml b/packages/SystemUI/res/drawable/bottom_sheet_background.xml
similarity index 69%
rename from packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml
rename to packages/SystemUI/res/drawable/bottom_sheet_background.xml
index 93f8724..87850a0 100644
--- a/packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml
+++ b/packages/SystemUI/res/drawable/bottom_sheet_background.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2019 The Android Open Source Project
+ ~ Copyright (C) 2021 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -14,12 +14,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
-
- <corners android:radius="20dp"/>
- <solid android:color="@color/tv_audio_recording_indicator_icon_background"/>
- <stroke android:width="1dp" android:color="@color/tv_audio_recording_indicator_stroke"/>
-
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
+ <solid android:color="@color/bottom_sheet_background_color"/>
+ <corners android:radius="@dimen/bottom_sheet_corner_radius"/>
</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml b/packages/SystemUI/res/drawable/bottom_sheet_background_with_blur.xml
similarity index 69%
copy from packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml
copy to packages/SystemUI/res/drawable/bottom_sheet_background_with_blur.xml
index 93f8724..cd2aa9c 100644
--- a/packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml
+++ b/packages/SystemUI/res/drawable/bottom_sheet_background_with_blur.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2019 The Android Open Source Project
+ ~ Copyright (C) 2021 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -14,12 +14,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
-
- <corners android:radius="20dp"/>
- <solid android:color="@color/tv_audio_recording_indicator_icon_background"/>
- <stroke android:width="1dp" android:color="@color/tv_audio_recording_indicator_stroke"/>
-
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
+ <solid android:color="@color/bottom_sheet_background_color_with_blur"/>
+ <corners android:radius="@dimen/bottom_sheet_corner_radius"/>
</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml b/packages/SystemUI/res/drawable/bottom_sheet_button_background.xml
similarity index 69%
copy from packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml
copy to packages/SystemUI/res/drawable/bottom_sheet_button_background.xml
index 93f8724..585a6bc 100644
--- a/packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml
+++ b/packages/SystemUI/res/drawable/bottom_sheet_button_background.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2019 The Android Open Source Project
+ ~ Copyright (C) 2021 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -14,12 +14,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
-
- <corners android:radius="20dp"/>
- <solid android:color="@color/tv_audio_recording_indicator_icon_background"/>
- <stroke android:width="1dp" android:color="@color/tv_audio_recording_indicator_stroke"/>
-
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
+ <solid android:color="@color/bottom_sheet_button_background_color"/>
+ <corners android:radius="@dimen/bottom_sheet_button_corner_radius"/>
</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml b/packages/SystemUI/res/interpolator/tv_privacy_chip_collapse_interpolator.xml
similarity index 61%
copy from packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml
copy to packages/SystemUI/res/interpolator/tv_privacy_chip_collapse_interpolator.xml
index 93f8724..4298124 100644
--- a/packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml
+++ b/packages/SystemUI/res/interpolator/tv_privacy_chip_collapse_interpolator.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2019 The Android Open Source Project
+ ~ Copyright (C) 2021 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -15,11 +15,8 @@
~ limitations under the License.
-->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
-
- <corners android:radius="20dp"/>
- <solid android:color="@color/tv_audio_recording_indicator_icon_background"/>
- <stroke android:width="1dp" android:color="@color/tv_audio_recording_indicator_stroke"/>
-
-</shape>
\ No newline at end of file
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:controlX1="0.4"
+ android:controlY1="1.00"
+ android:controlX2="0.12"
+ android:controlY2="1.00"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml b/packages/SystemUI/res/interpolator/tv_privacy_chip_expand_interpolator.xml
similarity index 61%
copy from packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml
copy to packages/SystemUI/res/interpolator/tv_privacy_chip_expand_interpolator.xml
index 93f8724..ed44715 100644
--- a/packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml
+++ b/packages/SystemUI/res/interpolator/tv_privacy_chip_expand_interpolator.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2019 The Android Open Source Project
+ ~ Copyright (C) 2021 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -15,11 +15,8 @@
~ limitations under the License.
-->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
-
- <corners android:radius="20dp"/>
- <solid android:color="@color/tv_audio_recording_indicator_icon_background"/>
- <stroke android:width="1dp" android:color="@color/tv_audio_recording_indicator_stroke"/>
-
-</shape>
\ No newline at end of file
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:controlX1="0.12"
+ android:controlY1="1.00"
+ android:controlX2="0.4"
+ android:controlY2="1.00"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/media_output_list_item.xml b/packages/SystemUI/res/layout/media_output_list_item.xml
index b563633..16c03e1 100644
--- a/packages/SystemUI/res/layout/media_output_list_item.xml
+++ b/packages/SystemUI/res/layout/media_output_list_item.xml
@@ -81,6 +81,7 @@
android:visibility="gone"/>
<SeekBar
android:id="@+id/volume_seekbar"
+ style="@*android:style/Widget.DeviceDefault.SeekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"/>
diff --git a/packages/SystemUI/res/layout/people_tile_with_suppression_detail_content_horizontal.xml b/packages/SystemUI/res/layout/people_tile_with_suppression_detail_content_horizontal.xml
new file mode 100644
index 0000000..b53c88b
--- /dev/null
+++ b/packages/SystemUI/res/layout/people_tile_with_suppression_detail_content_horizontal.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+~ Copyright (C) 2021 The Android Open Source Project
+~
+~ Licensed under the Apache License, Version 2.0 (the "License");
+~ you may not use this file except in compliance with the License.
+~ You may obtain a copy of the License at
+~
+~ http://www.apache.org/licenses/LICENSE-2.0
+~
+~ Unless required by applicable law or agreed to in writing, software
+~ distributed under the License is distributed on an "AS IS" BASIS,
+~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~ See the License for the specific language governing permissions and
+~ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:id="@+id/item"
+ android:background="@drawable/people_tile_suppressed_background"
+ android:clipToOutline="true"
+ android:padding="8dp"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@+id/person_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+
+ <TextView
+ android:gravity="start"
+ android:id="@+id/text_content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dp"
+ android:ellipsize="end"
+ android:maxLines="2"
+ android:singleLine="false"
+ android:text="@string/empty_status"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="@dimen/content_text_size_for_medium" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/people_tile_with_suppression_detail_content_vertical.xml b/packages/SystemUI/res/layout/people_tile_with_suppression_detail_content_vertical.xml
new file mode 100644
index 0000000..c79cdad
--- /dev/null
+++ b/packages/SystemUI/res/layout/people_tile_with_suppression_detail_content_vertical.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+~ Copyright (C) 2021 The Android Open Source Project
+~
+~ Licensed under the Apache License, Version 2.0 (the "License");
+~ you may not use this file except in compliance with the License.
+~ You may obtain a copy of the License at
+~
+~ http://www.apache.org/licenses/LICENSE-2.0
+~
+~ Unless required by applicable law or agreed to in writing, software
+~ distributed under the License is distributed on an "AS IS" BASIS,
+~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~ See the License for the specific language governing permissions and
+~ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:id="@+id/item"
+ android:background="@drawable/people_tile_suppressed_background"
+ android:clipToOutline="true"
+ android:padding="8dp"
+ android:orientation="vertical">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+
+ <ImageView
+ android:id="@+id/person_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+
+ <TextView
+ android:gravity="center"
+ android:id="@+id/text_content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:maxLines="2"
+ android:singleLine="false"
+ android:text="@string/empty_status"
+ android:layout_marginTop="@dimen/padding_between_suppressed_layout_items"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="@dimen/content_text_size_for_large" />
+
+ <ImageView
+ android:id="@+id/predefined_icon"
+ android:tint="?android:attr/textColorSecondary"
+ android:layout_marginTop="@dimen/padding_between_suppressed_layout_items"
+ android:layout_width="@dimen/regular_predefined_icon"
+ android:layout_height="@dimen/regular_predefined_icon"
+ tools:ignore="UseAppTint" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/tv_bottom_sheet.xml b/packages/SystemUI/res/layout/tv_bottom_sheet.xml
new file mode 100644
index 0000000..b69cdc7
--- /dev/null
+++ b/packages/SystemUI/res/layout/tv_bottom_sheet.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/bottom_sheet"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
+ android:minHeight="@dimen/bottom_sheet_min_height"
+ android:paddingHorizontal="@dimen/bottom_sheet_padding_horizontal"
+ android:paddingVertical="@dimen/bottom_sheet_padding_vertical">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minWidth="80dp"
+ android:gravity="center"
+ android:orientation="horizontal">
+ <ImageView
+ android:id="@+id/bottom_sheet_icon"
+ android:layout_width="@dimen/bottom_sheet_icon_size"
+ android:layout_height="@dimen/bottom_sheet_icon_size"
+ android:layout_gravity="center_vertical"
+ android:tint="@color/bottom_sheet_icon_color"/>
+ <ImageView
+ android:id="@+id/bottom_sheet_second_icon"
+ android:layout_width="@dimen/bottom_sheet_icon_size"
+ android:layout_height="@dimen/bottom_sheet_icon_size"
+ android:layout_marginStart="@dimen/bottom_sheet_icon_margin"
+ android:layout_gravity="center_vertical"
+ android:tint="@color/bottom_sheet_icon_color"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/bottom_sheet_padding_horizontal"
+ android:layout_weight="1"
+ android:orientation="vertical">
+ <TextView
+ android:id="@+id/bottom_sheet_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/bottom_sheet_title_margin_bottom"
+ android:textAppearance="@style/BottomSheet.TitleText"/>
+
+ <TextView
+ android:id="@+id/bottom_sheet_body"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/bottom_sheet_details_margin_bottom"
+ android:textAppearance="@style/BottomSheet.BodyText" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="@dimen/bottom_sheet_actions_width"
+ android:layout_height="match_parent"
+ android:gravity="center">
+ <Button
+ android:id="@+id/bottom_sheet_positive_button"
+ style="@style/BottomSheet.ActionItem" />
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="@dimen/bottom_sheet_actions_spacing" />
+ <Button
+ android:id="@+id/bottom_sheet_negative_button"
+ style="@style/BottomSheet.ActionItem" />
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/tv_ongoing_privacy_chip.xml b/packages/SystemUI/res/layout/tv_ongoing_privacy_chip.xml
index dff148b..6218a5e 100644
--- a/packages/SystemUI/res/layout/tv_ongoing_privacy_chip.xml
+++ b/packages/SystemUI/res/layout/tv_ongoing_privacy_chip.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2019 The Android Open Source Project
+ ~ Copyright (C) 2021 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -20,16 +20,25 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:padding="12dp"
- android:layout_gravity="center">
+ android:gravity="center"
+ android:animateLayoutChanges="false"
+ android:padding="@dimen/privacy_chip_margin">
+
+ <ImageView
+ android:id="@+id/chip_drawable"
+ android:layout_width="51dp"
+ android:layout_height="@dimen/privacy_chip_height"
+ android:minWidth="@dimen/privacy_chip_dot_bg_width"
+ android:minHeight="@dimen/privacy_chip_dot_bg_height"
+ android:layout_gravity="top|end" />
<LinearLayout
android:id="@+id/icons_container"
- android:background="@drawable/tv_rect_shadow_rounded"
- android:padding="@dimen/privacy_chip_icon_padding"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:orientation="horizontal"/>
-
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layout_gravity="center_vertical|end"
+ android:animateLayoutChanges="true"
+ android:paddingHorizontal="@dimen/privacy_chip_padding_horizontal" />
</FrameLayout>
diff --git a/packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml b/packages/SystemUI/res/transition/tv_privacy_chip_collapse.xml
similarity index 61%
copy from packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml
copy to packages/SystemUI/res/transition/tv_privacy_chip_collapse.xml
index 93f8724..f22e8ef 100644
--- a/packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml
+++ b/packages/SystemUI/res/transition/tv_privacy_chip_collapse.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2019 The Android Open Source Project
+ ~ Copyright (C) 2021 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -14,12 +14,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
-
- <corners android:radius="20dp"/>
- <solid android:color="@color/tv_audio_recording_indicator_icon_background"/>
- <stroke android:width="1dp" android:color="@color/tv_audio_recording_indicator_stroke"/>
-
-</shape>
\ No newline at end of file
+<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
+ <fade android:fadingMode="fade_in" />
+ <changeBounds/>
+</transitionSet>
diff --git a/packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml b/packages/SystemUI/res/transition/tv_privacy_chip_expand.xml
similarity index 61%
copy from packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml
copy to packages/SystemUI/res/transition/tv_privacy_chip_expand.xml
index 93f8724..059ebc8 100644
--- a/packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml
+++ b/packages/SystemUI/res/transition/tv_privacy_chip_expand.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2019 The Android Open Source Project
+ ~ Copyright (C) 2021 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -14,12 +14,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
-
- <corners android:radius="20dp"/>
- <solid android:color="@color/tv_audio_recording_indicator_icon_background"/>
- <stroke android:width="1dp" android:color="@color/tv_audio_recording_indicator_stroke"/>
-
-</shape>
\ No newline at end of file
+<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
+ <changeBounds/>
+ <fade android:fadingMode="fade_out" />
+</transitionSet>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 4736adb..ae8de87 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"ተጠቃሚ አክል"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"አዲስ ተጠቃሚ"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"እንግዳ ይወገድ?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"እንግዳ ዳግም ይጀምር?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"በዚህ ክፍለ-ጊዜ ውስጥ ያሉ ሁሉም መተግበሪያዎች እና ውሂብ ይሰረዛሉ።"</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"አስወግድ"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"ዳግም አስጀምር"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"እንኳን በደህና ተመለሱ እንግዳ!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"ክፍለ-ጊዜዎን መቀጠል ይፈልጋሉ?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"እንደገና ጀምር"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index b493d89..2881a04 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -488,12 +488,10 @@
<string name="user_add_user" msgid="4336657383006913022">"إضافة مستخدم"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"مستخدم جديد"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"هل تريد إزالة جلسة الضيف؟"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"هل تريد إعادة ضبط جلسة الضيف؟"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"سيتم حذف كل التطبيقات والبيانات في هذه الجلسة."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"إزالة"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"إعادة الضبط"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"مرحبًا بك مجددًا في جلسة الضيف"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"هل تريد متابعة جلستك؟"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"البدء من جديد"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index fe89267..345dcaa 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -482,12 +482,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Dodaj korisnika"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Novi korisnik"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Želite li da uklonite gosta?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Želite li da resetujete sesiju gosta?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci u ovoj sesiji će biti izbrisani."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ukloni"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Resetuj"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Dobro došli nazad, goste!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite li da nastavite sesiju?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Počni iz početka"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 0eedd1ca1..c035553 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"ব্যবহারকারী জুড়ুন"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"নতুন ব্যবহারকারী"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"অতিথি সরাবেন?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"গেস্ট সেশন রিসেট করবেন?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"এই সেশনের সব অ্যাপ ও ডেটা মুছে ফেলা হবে।"</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"সরান"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"রিসেট করুন"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"অতিথি, আপনি ফিরে আসায় আপনাকে স্বাগত!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"আপনি কি আপনার সেশনটি চালিয়ে যেতে চান?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"আবার শুরু করুন"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 615d346..ae7ac13 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -482,7 +482,7 @@
<string name="user_add_user" msgid="4336657383006913022">"Dodaj korisnika"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Novi korisnik"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Ukloniti gosta?"</string>
- <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Poništiti gostujuću sesiju?"</string>
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Poništiti sesiju gosta?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci iz ove sesije će se izbrisati."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ukloni"</string>
<string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Poništi"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 2428d55..14d3916 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Afegeix un usuari"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Usuari nou"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Vols suprimir el convidat?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Vols restablir el convidat?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Totes les aplicacions i les dades d\'aquesta sessió se suprimiran."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Suprimeix"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Restableix"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Benvingut de nou, convidat."</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Vols continuar amb la sessió?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Torna a començar"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index d8e0a6a1..ae0f0f3 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -484,12 +484,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Přidat uživatele"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Nový uživatel"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Odstranit hosta?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Resetovat hosta?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Veškeré aplikace a data v této relaci budou vymazána."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Odstranit"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Resetovat"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Vítejte zpět v relaci hosta!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Chcete v relaci pokračovat?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Začít znovu"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index ca44f0a..78a56cd 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Tilføj bruger"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Ny bruger"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Vil du fjerne gæsten?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Vil du nulstille gæsten?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apps og data i denne session slettes."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Fjern"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Nulstil"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Velkommen tilbage, gæst!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Vil du fortsætte din session?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start forfra"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 17cb3b9..672ffd0 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Nutzer hinzufügen"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Neuer Nutzer"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Gast entfernen?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Gastsitzung zurücksetzen?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle Apps und Daten in dieser Sitzung werden gelöscht."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Entfernen"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Zurücksetzen"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Willkommen zurück im Gastmodus"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Möchtest du deine Sitzung fortsetzen?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Neu starten"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 7b135a3..3662da2 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Προσθήκη χρήστη"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Νέος χρήστης"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Κατάργηση επισκέπτη;"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Επαναφορά περιόδου επισκέπτη;"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Όλες οι εφαρμογές και τα δεδομένα αυτής της περιόδου σύνδεσης θα διαγραφούν."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Κατάργηση"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Επαναφορά"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Kαλώς ορίσατε ξανά!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Θέλετε να συνεχίσετε την περίοδο σύνδεσής σας;"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Έναρξη από την αρχή"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 0479ad0..13b7653 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Agregar usuario"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Usuario nuevo"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"¿Quitar invitado?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"¿Quieres restablecer el usuario?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Se eliminarán las aplicaciones y los datos de esta sesión."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Quitar"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Restablecer"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"¡Hola de nuevo, invitado!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"¿Quieres retomar la sesión?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Volver a empezar"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 6564815..171afee 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Añadir usuario"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Nuevo usuario"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"¿Quitar invitado?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"¿Restablecer invitado?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Se eliminarán todas las aplicaciones y datos de esta sesión."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Quitar"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Restablecer"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Hola de nuevo, invitado"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"¿Quieres continuar con la sesión?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Volver a empezar"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 6d8a8fd..40f3998 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Gehitu erabiltzaile bat"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Erabiltzaile berria"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Gonbidatua kendu nahi duzu?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Gonbidatuentzako saioa berrezarri nahi duzu?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Saioko aplikazio eta datu guztiak ezabatuko dira."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Kendu"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Berrezarri"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Ongi etorri berriro, gonbidatu hori!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Saioarekin jarraitu nahi duzu?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Hasi berriro"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index ce3e676..f17fd41 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"افزودن کاربر"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"کاربر جدید"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"مهمان حذف شود؟"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"جلسه مهمان بازنشانی شود؟"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"همه برنامهها و دادههای این جلسه حذف خواهد شد."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"حذف"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"بازنشانی"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"مهمان گرامی، بازگشتتان را خوش آمد میگوییم!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"آیا میخواهید جلسهتان را ادامه دهید؟"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"شروع مجدد"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 90f47ef..3546ea0 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Lisää käyttäjä"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Uusi käyttäjä"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Poistetaaanko vieras?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Nollataanko vieras?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Kaikki sovellukset ja tämän istunnon tiedot poistetaan."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Poista"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Nollaa"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Tervetuloa takaisin!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Haluatko jatkaa istuntoa?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Aloita alusta"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 0304280..39d564f 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Ajouter un utilisateur"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Nouvel utilisateur"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Supprimer l\'invité?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Réinitialiser la session Invité?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applications et les données de cette session seront supprimées."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Supprimer"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Réinitialiser"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Bienvenue à nouveau dans la session Invité"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Voulez-vous poursuivre la session?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recommencer"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index c402261..4f06701 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Ajouter un utilisateur"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Nouvel utilisateur"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Supprimer l\'invité ?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Réinitialiser la session Invité ?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applications et les données de cette session seront supprimées."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Supprimer"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Réinitialiser"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Bienvenue à nouveau dans la session Invité"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Voulez-vous poursuivre la dernière session ?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Non, nouvelle session"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index e7b3e92..0641cef 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Engadir usuario"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Novo usuario"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Queres quitar o convidado?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Queres restablecer a sesión de convidado?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Eliminaranse todas as aplicacións e datos desta sesión."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Quitar"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Restablecer"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Benvido de novo, convidado"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Queres continuar coa túa sesión?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Comezar de novo"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index a99558e..25caa53 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -1036,8 +1036,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"સ્ક્રીનનો કોઈ ભાગ મોટો કરો"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"સ્વિચ"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"ઍક્સેસિબિલિટી સંકેતને ઍક્સેસિબિલિટી બટન વડે બદલવામાં આવ્યા છે\n\n"<annotation id="link">"સેટિંગ જુઓ"</annotation></string>
- <!-- no translation found for accessibility_floating_button_switch_migration_tooltip (6248529129221218770) -->
- <skip />
+ <string name="accessibility_floating_button_switch_migration_tooltip" msgid="6248529129221218770">"તમે ઍક્સેસિબિલિટી સંકેત પરથી કોઈ બટન પર સ્વિચ કરી શકો છો\n\n"<annotation id="link">"સેટિંગ"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"તેને હંગામી રૂપે ખસેડવા માટે બટનને કિનારી પર ખસેડો"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ઉપર ડાબે ખસેડો"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ઉપર જમણે ખસેડો"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 4196b1f..3d65fa4 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"उपयोगकर्ता जोड़ें"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"नया उपयोगकर्ता"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"क्या आप मेहमान को हटाना चाहते हैं?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"क्या आप मेहमान के तौर पर ब्राउज़ करने का सेशन रीसेट करना चाहते हैं?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"इस सत्र के सभी ऐप्लिकेशन और डेटा को हटा दिया जाएगा."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"निकालें"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"रीसेट करें"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"मेहमान, आपका फिर से स्वागत है!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"क्या आप अपना सत्र जारी रखना चाहते हैं?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"फिर से शुरू करें"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 01bad1c..151564a 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Bæta notanda við"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Nýr notandi"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Fjarlægja gest?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Endurstilla gestastillingu?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Öllum forritum og gögnum í þessari lotu verður eytt."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Fjarlægja"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Endurstilla"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Velkominn aftur, gestur!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Viltu halda áfram með lotuna?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Byrja upp á nýtt"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 32c386d..3dedff9 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -484,12 +484,10 @@
<string name="user_add_user" msgid="4336657383006913022">"הוספת משתמש"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"משתמש חדש"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"להסיר אורח?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"לאפס את הגלישה כאורח?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"כל האפליקציות והנתונים בסשן הזה יימחקו."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"הסרה"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"איפוס"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"שמחים לראותך שוב!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"האם ברצונך להמשיך בפעילות באתר?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"סשן חדש"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 0b21c0f..7f57da1 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸಿ"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"ಹೊಸ ಬಳಕೆದಾರರು"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ಅತಿಥಿಯನ್ನು ತೆಗೆದುಹಾಕುವುದೇ?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"ಅತಿಥಿಯನ್ನು ಮರುಹೊಂದಿಸಬೇಕೆ?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ಈ ಸೆಷನ್ನಲ್ಲಿನ ಎಲ್ಲ ಅಪ್ಲಿಕೇಶನ್ಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ತೆಗೆದುಹಾಕಿ"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"ಮರುಹೊಂದಿಸಿ"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"ಮತ್ತೆ ಸುಸ್ವಾಗತ, ಅತಿಥಿ!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"ನಿಮ್ಮ ಸೆಷನ್ ಮುಂದುವರಿಸಲು ಇಚ್ಚಿಸುವಿರಾ?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ಪ್ರಾರಂಭಿಸಿ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 44dc8bb..ce64e4c 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -484,12 +484,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Pridėti naudotoją"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Naujas naudotojas"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Pašalinti svečią?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Nustatyti svečią iš naujo?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bus ištrintos visos šios sesijos programos ir duomenys."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Pašalinti"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Nustatyti iš naujo"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Sveiki sugrįžę, svety!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Ar norite tęsti sesiją?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Pradėti iš naujo"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index b846be4..518a28b 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -482,12 +482,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Lietotāja pievienošana"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Jauns lietotājs"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Vai noņemt viesi?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Vai atiestatīt viesa sesiju?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tiks dzēstas visas šīs sesijas lietotnes un dati."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Noņemt"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Atiestatīt"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Laipni lūdzam atpakaļ, viesi!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Vai vēlaties turpināt savu sesiju?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Sākt no sākuma"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 74d087c..6923fef 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"ഉപയോക്താവിനെ ചേര്ക്കുക"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"പുതിയ ഉപയോക്താവ്"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"അതിഥിയെ നീക്കംചെയ്യണോ?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"അതിഥിയെ റീസെറ്റ് ചെയ്യണോ?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ഈ സെഷനിലെ എല്ലാ ആപ്പുകളും ഡാറ്റയും ഇല്ലാതാക്കും."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"നീക്കംചെയ്യുക"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"റീസെറ്റ് ചെയ്യുക"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"അതിഥി, വീണ്ടും സ്വാഗതം!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"നിങ്ങളുടെ സെഷൻ തുടരണോ?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"പുനരാംരംഭിക്കുക"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 84b5594..f649ca4 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"वापरकर्ता जोडा"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"नवीन वापरकर्ता"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"अतिथी काढायचे?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"अतिथीला रीसेट करायचे आहे का?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"या सत्रातील सर्व अॅप्स आणि डेटा हटवला जाईल."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"काढा"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"रीसेट करा"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"अतिथी, तुमचे पुन्हा स्वागत आहे!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"तुम्ही तुमचे सत्र सुरू ठेवू इच्छिता?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"येथून सुरू करा"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index f3838c4..5034292 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Tambah pengguna"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Pengguna baharu"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Alih keluar tetamu?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Tetapkan semula tetamu?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Semua apl dan data dalam sesi ini akan dipadam."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Alih keluar"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Tetapkan semula"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Selamat kembali, tetamu!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Adakah anda ingin meneruskan sesi anda?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Mulakan semula"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 71ae672..2f07a3e 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Legg til brukere"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Ny bruker"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Vil du fjerne gjesten?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Vil du tilbakestille gjesten?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle appene og all informasjon i denne økten slettes."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Fjern"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Tilbakestill"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Velkommen tilbake, gjest!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Vil du fortsette økten?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start på nytt"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 52e6155..10311b0 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -437,7 +437,7 @@
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"एपहरू बदल्न द्रुत गतिमा दायाँतिर ड्र्याग गर्नुहोस्"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"परिदृश्य टगल गर्नुहोस्"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"चार्ज भयो"</string>
- <string name="expanded_header_battery_charging" msgid="1717522253171025549">"चार्ज हुँदै"</string>
+ <string name="expanded_header_battery_charging" msgid="1717522253171025549">"चार्ज हुँदै छ"</string>
<string name="expanded_header_battery_charging_with_time" msgid="757991461445765011">"<xliff:g id="CHARGING_TIME">%s</xliff:g> पूर्ण नभएसम्म"</string>
<string name="expanded_header_battery_not_charging" msgid="809409140358955848">"चार्ज भइरहेको छैन"</string>
<string name="ssl_ca_cert_warning" msgid="8373011375250324005">"नेटवर्क \n अनुगमनमा हुन सक्छ"</string>
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"प्रयोगकर्ता थप्नुहोस्"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"नयाँ प्रयोगकर्ता"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"अतिथि हटाउने हो?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"अतिथि सत्र रिसेट गर्ने हो?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"यो सत्रमा भएका सबै एपहरू र डेटा मेटाइने छ।"</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"हटाउनुहोस्"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"रिसेट गर्नुहोस्"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"तपाईंलाई फेरि स्वागत छ, अतिथि"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"तपाईं आफ्नो सत्र जारी गर्न चाहनुहुन्छ?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"सुरु गर्नुहोस्"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 003ce4c..8fede32 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -1036,8 +1036,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ସ୍କ୍ରିନର ଅଂଶ ମାଗ୍ନିଫାଏ କରନ୍ତୁ"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ସ୍ୱିଚ୍ କରନ୍ତୁ"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"ଆକ୍ସେସିବିଲିଟୀ ଜେଶ୍ଚରକୁ ଆକ୍ସେସିବିଲିଟୀ ବଟନରେ ପରିବର୍ତ୍ତନ କରାଯାଇଛି\n\n"<annotation id="link">"ସେଟିଂସ୍ ଦେଖନ୍ତୁ"</annotation></string>
- <!-- no translation found for accessibility_floating_button_switch_migration_tooltip (6248529129221218770) -->
- <skip />
+ <string name="accessibility_floating_button_switch_migration_tooltip" msgid="6248529129221218770">"ଆପଣ ଆକ୍ସେସିବିଲିଟୀ ଜେଶ୍ଚରରୁ ଏକ ବଟନକୁ ସ୍ୱିଚ୍ କରିପାରିବେ\n\n"<annotation id="link">"ସେଟିଂସ୍"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ବଟନକୁ ଅସ୍ଥାୟୀ ଭାବେ ଲୁଚାଇବା ପାଇଁ ଏହାକୁ ଗୋଟିଏ ଧାରକୁ ମୁଭ୍ କରନ୍ତୁ"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ଶୀର୍ଷ ବାମକୁ ମୁଭ୍ କରନ୍ତୁ"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ଶୀର୍ଷ ଡାହାଣକୁ ମୁଭ୍ କରନ୍ତୁ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 0f687a1..da10cb4 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"ਨਵਾਂ ਵਰਤੋਂਕਾਰ"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ਕੀ ਮਹਿਮਾਨ ਹਟਾਉਣਾ ਹੈ?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"ਕੀ ਗੈਸਟ ਨੂੰ ਰੀਸੈੱਟ ਕਰਨਾ ਹੈ?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ਇਸ ਸੈਸ਼ਨ ਵਿੱਚ ਸਾਰੀਆਂ ਐਪਾਂ ਅਤੇ ਡਾਟਾ ਨੂੰ ਮਿਟਾ ਦਿੱਤਾ ਜਾਏਗਾ।"</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ਹਟਾਓ"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"ਰੀਸੈੱਟ ਕਰੋ"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"ਮਹਿਮਾਨ, ਫਿਰ ਤੁਹਾਡਾ ਸੁਆਗਤ ਹੈ!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"ਕੀ ਤੁਸੀਂ ਆਪਣਾ ਸੈਸ਼ਨ ਜਾਰੀ ਰੱਖਣਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ਮੁੜ-ਸ਼ੁਰੂ ਕਰੋ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index e822d93..704d384 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -484,12 +484,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Dodaj użytkownika"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Nowy użytkownik"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Usunąć gościa?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Zresetować sesję gościa?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Wszystkie aplikacje i dane w tej sesji zostaną usunięte."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Usuń"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Resetuj"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Witaj ponownie, Gościu!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Chcesz kontynuować sesję?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Rozpocznij nową"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 3f9a576..42c8dbb 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -482,12 +482,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Adăugați un utilizator"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Utilizator nou"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Ștergeți invitatul?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Resetați invitatul?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toate aplicațiile și datele din această sesiune vor fi șterse."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ștergeți"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Resetați"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Bine ați revenit în sesiunea pentru invitați!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Vreți să continuați sesiunea?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Începeți din nou"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 67091b9..e324c35 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -484,12 +484,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Добавить пользователя"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Новый пользователь"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Удалить аккаунт гостя?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Сбросить гостевой сеанс?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Все приложения и данные этого профиля будут удалены."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Удалить"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Сбросить"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Рады видеть вас снова!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Продолжить сеанс?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Начать заново"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 19a871e..31bea13 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -484,12 +484,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Pridať používateľa"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Nový používateľ"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Odstrániť hosťa?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Chcete resetovať reláciu hosťa?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Všetky aplikácie a údaje v tejto relácii budú odstránené."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Odstrániť"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Resetovať"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Hosť, vitajte späť!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Chcete v relácii pokračovať?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Začať odznova"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index c58343a..420e8cb 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -484,12 +484,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Dodajanje uporabnika"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Nov uporabnik"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Želite odstraniti gosta?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Želite ponastaviti gosta?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Vse aplikacije in podatki v tej seji bodo izbrisani."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Odstrani"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Ponastavi"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Znova pozdravljeni, gost!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite nadaljevati sejo?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Začni znova"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 334b2ed..e4238d2 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Shto përdorues"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Përdorues i ri"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Të hiqet i ftuari?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Të rivendoset vizitori?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Të gjitha aplikacionet dhe të dhënat në këtë sesion do të fshihen."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Hiq"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Rivendos"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Mirë se erdhe, i ftuar!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Dëshiron ta vazhdosh sesionin tënd?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Fillo nga e para"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index e4a1bea..4e82fd7 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -482,12 +482,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Додај корисника"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Нови корисник"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Желите ли да уклоните госта?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Желите ли да ресетујете сесију госта?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Све апликације и подаци у овој сесији ће бити избрисани."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Уклони"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Ресетуј"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Добро дошли назад, госте!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Желите ли да наставите сесију?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Почни из почетка"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 5dc1581..7e3b412 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"பயனரைச் சேர்"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"புதியவர்"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"கெஸ்ட்டை அகற்றவா?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"விருந்தினர் அமர்வை மீட்டமைக்கவா?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"இந்த அமர்வின் எல்லா ஆப்ஸும் தரவும் நீக்கப்படும்."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"அகற்று"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"மீட்டமை"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"நல்வரவு!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"உங்கள் அமர்வைத் தொடர விருப்பமா?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"மீண்டும் தொடங்கு"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 348c37a..1f7146f 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"యూజర్ను జోడించండి"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"కొత్త వినియోగదారు"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"గెస్ట్ను తీసివేయాలా?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"గెస్ట్ సెషన్ను రీసెట్ చేయాలా?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ఈ సెషన్లోని అన్ని యాప్లు మరియు డేటా తొలగించబడతాయి."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"తీసివేయి"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"రీసెట్ చేయండి"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"గెస్ట్కు తిరిగి స్వాగతం!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"మీరు మీ సెషన్ని కొనసాగించాలనుకుంటున్నారా?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"మొదటి నుండి ప్రారంభించు"</string>
@@ -1038,8 +1036,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"స్క్రీన్లో భాగాన్ని మాగ్నిఫై చేయండి"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"స్విచ్ చేయి"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"యాక్సెసిబిలిటీ బటన్, యాక్సెసిబిలిటీ సంజ్ఞను భర్తీ చేసింది\n\n"<annotation id="link">"సెట్టింగ్లను చూడండి"</annotation></string>
- <!-- no translation found for accessibility_floating_button_switch_migration_tooltip (6248529129221218770) -->
- <skip />
+ <string name="accessibility_floating_button_switch_migration_tooltip" msgid="6248529129221218770">"మీరు యాక్సెసిబిలిటీ సంజ్ఞ నుండి బటన్ మధ్య మారవచ్చు\n\n"<annotation id="link">"సెట్టింగ్లు"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"తాత్కాలికంగా దానిని దాచడానికి బటన్ను చివరకు తరలించండి"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ఎగువ ఎడమ వైపునకు తరలించు"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ఎగువ కుడి వైపునకు తరలించు"</string>
diff --git a/packages/SystemUI/res/values-television/colors.xml b/packages/SystemUI/res/values-television/colors.xml
index e5f3b47..566f6b2 100644
--- a/packages/SystemUI/res/values-television/colors.xml
+++ b/packages/SystemUI/res/values-television/colors.xml
@@ -19,4 +19,22 @@
<resources>
<color name="volume_dialog_background_color">#E61F232B</color>
<color name="volume_dialog_background_color_above_blur">#C71F232B</color>
+
+ <color name="bottom_sheet_icon_color">#D2E3FC</color>
+
+ <color name="bottom_sheet_title_color">#E8F0FE</color>
+ <color name="bottom_sheet_body_color">#D2E3FC</color>
+
+ <color name="bottom_sheet_background_color">#1F232C</color>
+ <color name="bottom_sheet_background_color_with_blur">#AA1A2734</color>
+
+ <color name="bottom_sheet_button_background_color_focused">#E8F0FE</color>
+ <color name="bottom_sheet_button_background_color_unfocused">#0FE8EAED</color>
+
+ <color name="bottom_sheet_button_text_color_focused">#DB202124</color>
+ <color name="bottom_sheet_button_text_color_unfocused">#B5E8EAED</color>
+
+ <color name="privacy_circle">#5BB974</color> <!-- g400 -->
+ <color name="privacy_icon_tint">#30302A</color>
+ <color name="privacy_chip_dot_bg_tint">#66000000</color>
</resources>
diff --git a/packages/SystemUI/res/values-television/dimens.xml b/packages/SystemUI/res/values-television/dimens.xml
index 7626db9..c258fcc 100644
--- a/packages/SystemUI/res/values-television/dimens.xml
+++ b/packages/SystemUI/res/values-television/dimens.xml
@@ -18,7 +18,42 @@
<!-- Opacity at which the background for the shutdown UI will be drawn. -->
<item name="shutdown_scrim_behind_alpha" format="float" type="dimen">1.0</item>
- <dimen name="privacy_chip_icon_margin">3dp</dimen>
- <dimen name="privacy_chip_icon_padding">8dp</dimen>
- <dimen name="privacy_chip_icon_size">13dp</dimen>
+ <dimen name="bottom_sheet_padding_horizontal">32dp</dimen>
+ <dimen name="bottom_sheet_padding_vertical">24dp</dimen>
+
+ <dimen name="bottom_sheet_icon_size">42dp</dimen>
+ <dimen name="bottom_sheet_icon_margin">8dp</dimen>
+ <dimen name="bottom_sheet_title_margin_bottom">18dp</dimen>
+ <dimen name="bottom_sheet_details_margin_bottom">8dp</dimen>
+
+ <dimen name="bottom_sheet_actions_width">296dp</dimen>
+ <dimen name="bottom_sheet_actions_spacing">12dp</dimen>
+ <item name="bottom_sheet_button_selection_scaled" format="float" type="dimen">1.1</item>
+ <dimen name="bottom_sheet_button_width">232dp</dimen>
+ <dimen name="bottom_sheet_button_padding_horizontal">20dp</dimen>
+ <dimen name="bottom_sheet_button_padding_vertical">16dp</dimen>
+
+ <dimen name="bottom_sheet_corner_radius">24dp</dimen>
+ <dimen name="bottom_sheet_button_corner_radius">10dp</dimen>
+
+ <dimen name="bottom_sheet_min_height">208dp</dimen>
+ <dimen name="bottom_sheet_margin">24dp</dimen>
+ <dimen name="bottom_sheet_background_blur_radius">120dp</dimen>
+
+ <dimen name="privacy_chip_margin">12dp</dimen>
+ <dimen name="privacy_chip_icon_margin_in_between">9dp</dimen>
+ <dimen name="privacy_chip_padding_horizontal">9dp</dimen>
+ <dimen name="privacy_chip_icon_size">12dp</dimen>
+ <dimen name="privacy_chip_height">24dp</dimen>
+ <dimen name="privacy_chip_min_width">30dp</dimen>
+ <dimen name="privacy_chip_radius">12dp</dimen>
+
+ <dimen name="privacy_chip_dot_size">8dp</dimen>
+ <dimen name="privacy_chip_dot_radius">4dp</dimen>
+ <dimen name="privacy_chip_dot_margin_horizontal">8dp</dimen>
+
+ <dimen name="privacy_chip_dot_bg_width">24dp</dimen>
+ <dimen name="privacy_chip_dot_bg_height">18dp</dimen>
+ <dimen name="privacy_chip_dot_bg_radius">9dp</dimen>
+
</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-television/integers.xml b/packages/SystemUI/res/values-television/integers.xml
index 587497e..b265d78 100644
--- a/packages/SystemUI/res/values-television/integers.xml
+++ b/packages/SystemUI/res/values-television/integers.xml
@@ -20,4 +20,6 @@
Value 81 corresponds to BOTTOM|CENTER_HORIZONTAL.
Value 21 corresponds to RIGHT|CENTER_VERTICAL. -->
<integer name="volume_dialog_gravity">21</integer>
+
+ <integer name="privacy_chip_animation_millis">300</integer>
</resources>
diff --git a/packages/SystemUI/res/values-television/styles.xml b/packages/SystemUI/res/values-television/styles.xml
index 00217fb..0fb7898 100644
--- a/packages/SystemUI/res/values-television/styles.xml
+++ b/packages/SystemUI/res/values-television/styles.xml
@@ -28,4 +28,34 @@
<item name="android:textColorPrimaryInverse">@color/tv_volume_dialog_accent</item>
<item name="android:dialogCornerRadius">@dimen/volume_dialog_panel_width_half</item>
</style>
+
+ <style name="BottomSheet" parent="Theme.Leanback">
+ <item name="android:windowIsFloating">true</item>
+ <item name="android:windowActivityTransitions">true</item>
+ <item name="android:windowNoTitle">true</item>
+ <item name="android:windowIsTranslucent">true</item>
+ <item name="android:backgroundDimAmount">0.2</item>
+ </style>
+
+ <style name="BottomSheet.TitleText">
+ <item name="android:textSize">28sp</item>
+ <item name="android:textColor">@color/bottom_sheet_title_color</item>
+ </style>
+
+ <style name="BottomSheet.BodyText">
+ <item name="android:textSize">16sp</item>
+ <item name="android:textColor">@color/bottom_sheet_body_color</item>
+ </style>
+
+ <style name="BottomSheet.ActionItem">
+ <item name="android:layout_width">@dimen/bottom_sheet_button_width</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:gravity">left|center_vertical</item>
+ <item name="android:textSize">16sp</item>
+ <item name="android:textColor">@color/bottom_sheet_button_text_color</item>
+ <item name="android:background">@drawable/bottom_sheet_button_background</item>
+ <item name="android:paddingHorizontal">@dimen/bottom_sheet_button_padding_horizontal</item>
+ <item name="android:paddingVertical">@dimen/bottom_sheet_button_padding_vertical</item>
+ <item name="android:stateListAnimator">@anim/tv_bottom_sheet_button_state_list_animator</item>
+ </style>
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 930bb05..efece98 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"صارف کو شامل کریں"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"نیا صارف"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"مہمان کو ہٹائیں؟"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"مہمان کو ری سیٹ کریں؟"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"اس سیشن میں موجود سبھی ایپس اور ڈیٹا کو حذف کر دیا جائے گا۔"</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ہٹائیں"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"ری سیٹ کریں"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"مہمان، پھر سے خوش آمدید!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"کیا آپ اپنا سیشن جاری رکھنا چاہتے ہیں؟"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"دوبارہ شروع کریں"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 241cfb2..c337d08 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Thêm người dùng"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Người dùng mới"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Xóa phiên khách?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Đặt lại phiên khách?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tất cả ứng dụng và dữ liệu trong phiên này sẽ bị xóa."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Xóa"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Đặt lại"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Chào mừng bạn trở lại!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Bạn có muốn tiếp tục phiên của mình không?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Bắt đầu lại"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 7be08d3..b9ea4b0 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -480,7 +480,7 @@
<string name="user_add_user" msgid="4336657383006913022">"加入使用者"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"新使用者"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"移除訪客?"</string>
- <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"要重設訪客嗎?"</string>
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"要重設訪客工作階段嗎?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"這個工作階段中的所有應用程式和資料都會被刪除。"</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"移除"</string>
<string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"重設"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 5c4c3b15..7d82bf5 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"新增使用者"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"新使用者"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"移除訪客?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"要重設訪客工作階段嗎?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"這個工作階段中的所有應用程式和資料都會遭到刪除。"</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"移除"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"重設"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"訪客你好,歡迎回來!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"你要繼續這個工作階段嗎?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"重新開始"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 647102a..a44c6ff 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Engeza umsebenzisi"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Umsebenzisi omusha"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Susa isivakashi?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Setha kabusha isimenywa?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Zonke izinhlelo zokusebenza nedatha kulesi sikhathi zizosuswa."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Susa"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Setha kabusha"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Siyakwamukela futhi, sivakashi!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Ingabe ufuna ukuqhubeka ngesikhathi sakho?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Qala phansi"</string>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 7525a9b..4053ac3 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1451,7 +1451,7 @@
<dimen name="people_space_messages_count_radius">12dp</dimen>
<dimen name="people_space_widget_background_padding">6dp</dimen>
<dimen name="required_width_for_medium">136dp</dimen>
- <dimen name="required_width_for_large">138dp</dimen>
+ <dimen name="required_width_for_large">120dp</dimen>
<dimen name="required_height_for_large">168dp</dimen>
<dimen name="default_width">146dp</dimen>
<dimen name="default_height">92dp</dimen>
@@ -1470,10 +1470,12 @@
<dimen name="below_name_text_padding">16dp</dimen>
<dimen name="above_notification_text_padding">22dp</dimen>
<dimen name="regular_predefined_icon">18dp</dimen>
- <dimen name="large_predefined_icon">24dp</dimen>
+ <dimen name="larger_predefined_icon">24dp</dimen>
+ <dimen name="largest_predefined_icon">32dp</dimen>
<dimen name="availability_dot_status_padding">8dp</dimen>
<dimen name="availability_dot_notification_padding">12dp</dimen>
<dimen name="medium_content_padding_above_name">4dp</dimen>
+ <dimen name="padding_between_suppressed_layout_items">8dp</dimen>
<!-- Accessibility floating menu -->
<dimen name="accessibility_floating_menu_elevation">3dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 83dbad1..cf18b13 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2952,6 +2952,8 @@
<string name="people_tile_description">See recent messages, missed calls, and status updates</string>
<!-- Title text displayed for the Conversation widget [CHAR LIMIT=50] -->
<string name="people_tile_title">Conversation</string>
+ <!-- Text when the Conversation widget when Do Not Disturb is suppressing the notification. [CHAR LIMIT=50] -->
+ <string name="paused_by_dnd">Paused by Do Not Disturb</string>
<!-- Content description text on the Conversation widget when a person has sent a new text message [CHAR LIMIT=150] -->
<string name="new_notification_text_content_description"><xliff:g id="name" example="Anna">%1$s</xliff:g> sent a message</string>
<!-- Content description text on the Conversation widget when a person has sent a new image message [CHAR LIMIT=150] -->
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
index 7cd43ef..cff6cf1 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
@@ -19,6 +19,7 @@
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
import android.content.Context;
+import android.os.UserHandle;
import android.text.TextUtils;
import androidx.annotation.MainThread;
@@ -40,11 +41,11 @@
AccessibilityButtonModeObserver.ModeChangedListener,
AccessibilityButtonTargetsObserver.TargetsChangedListener {
- private final Context mContext;
private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
private final AccessibilityButtonTargetsObserver mAccessibilityButtonTargetsObserver;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private Context mContext;
@VisibleForTesting
IAccessibilityFloatingMenu mFloatingMenu;
private int mBtnMode;
@@ -79,6 +80,7 @@
@Override
public void onUserSwitchComplete(int userId) {
+ mContext = mContext.createContextAsUser(UserHandle.of(userId), /* flags= */ 0);
mBtnMode = mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode();
mBtnTargets =
mAccessibilityButtonTargetsObserver.getCurrentAccessibilityButtonTargets();
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java
index 5bb5522..e891e5b 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java
@@ -16,6 +16,7 @@
package com.android.systemui.accessibility.floatingmenu;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.util.MathUtils.constrain;
import static android.util.MathUtils.sq;
import static android.view.WindowInsets.Type.ime;
@@ -200,6 +201,7 @@
mListView = listView;
mWindowManager = context.getSystemService(WindowManager.class);
+ mLastConfiguration = new Configuration(getResources().getConfiguration());
mAdapter = new AccessibilityTargetAdapter(mTargets);
mUiHandler = createUiHandler();
mPosition = position;
@@ -243,7 +245,6 @@
}
});
- mLastConfiguration = new Configuration(getResources().getConfiguration());
initListView();
updateStrokeWith(getResources().getConfiguration().uiMode, mAlignment);
@@ -567,8 +568,10 @@
final int currentX = (int) event.getX();
final int currentY = (int) event.getY();
+ final int marginStartEnd = getMarginStartEndWith(mLastConfiguration);
final Rect touchDelegateBounds =
- new Rect(mMargin, mMargin, mMargin + getLayoutWidth(), mMargin + getLayoutHeight());
+ new Rect(marginStartEnd, mMargin, marginStartEnd + getLayoutWidth(),
+ mMargin + getLayoutHeight());
if (action == MotionEvent.ACTION_DOWN
&& touchDelegateBounds.contains(currentX, currentY)) {
mIsDownInEnlargedTouchArea = true;
@@ -682,15 +685,13 @@
mListView.setLayoutManager(layoutManager);
mListView.addOnItemTouchListener(this);
mListView.animate().setInterpolator(new OvershootInterpolator());
- updateListView();
+ updateListViewWith(mLastConfiguration);
addView(mListView);
}
- private void updateListView() {
- final LayoutParams layoutParams = (FrameLayout.LayoutParams) mListView.getLayoutParams();
- layoutParams.setMargins(mMargin, mMargin, mMargin, mMargin);
- mListView.setLayoutParams(layoutParams);
+ private void updateListViewWith(Configuration configuration) {
+ updateMarginWith(configuration);
final int elevation =
getResources().getDimensionPixelSize(R.dimen.accessibility_floating_menu_elevation);
@@ -719,13 +720,15 @@
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
+ mLastConfiguration.setTo(newConfig);
+
final int diff = newConfig.diff(mLastConfiguration);
if ((diff & ActivityInfo.CONFIG_LOCALE) != 0) {
updateAccessibilityTitle(mCurrentLayoutParams);
}
updateDimensions();
- updateListView();
+ updateListViewWith(newConfig);
updateItemViewWith(mSizeType);
updateColor();
updateStrokeWith(newConfig.uiMode, mAlignment);
@@ -733,8 +736,6 @@
updateRadiusWith(mSizeType, mRadiusType, mTargets.size());
updateScrollModeWith(hasExceededMaxLayoutHeight());
setSystemGestureExclusion();
-
- mLastConfiguration.setTo(newConfig);
}
@VisibleForTesting
@@ -756,11 +757,11 @@
}
private int getMinWindowX() {
- return -mMargin;
+ return -getMarginStartEndWith(mLastConfiguration);
}
private int getMaxWindowX() {
- return mScreenWidth - mMargin - getLayoutWidth();
+ return mScreenWidth - getMarginStartEndWith(mLastConfiguration) - getLayoutWidth();
}
private int getMaxWindowY() {
@@ -805,6 +806,15 @@
return layoutBottomY > imeY ? (layoutBottomY - imeY) : 0;
}
+ private void updateMarginWith(Configuration configuration) {
+ // Avoid overlapping with system bars under landscape mode, update the margins of the menu
+ // to align the edge of system bars.
+ final int marginStartEnd = getMarginStartEndWith(configuration);
+ final LayoutParams layoutParams = (FrameLayout.LayoutParams) mListView.getLayoutParams();
+ layoutParams.setMargins(marginStartEnd, mMargin, marginStartEnd, mMargin);
+ mListView.setLayoutParams(layoutParams);
+ }
+
private void updateOffsetWith(@ShapeType int shapeType, @Alignment int side) {
final float halfWidth = getLayoutWidth() / 2.0f;
final float offset = (shapeType == ShapeType.OVAL) ? 0 : halfWidth;
@@ -896,6 +906,12 @@
return (mPadding + mIconHeight) * mTargets.size() + mPadding;
}
+ private int getMarginStartEndWith(Configuration configuration) {
+ return configuration != null
+ && configuration.orientation == ORIENTATION_PORTRAIT
+ ? mMargin : 0;
+ }
+
private @DimenRes int getRadiusResId(@SizeType int sizeType, int itemCount) {
return sizeType == SizeType.SMALL
? getSmallSizeResIdWith(itemCount)
@@ -932,7 +948,7 @@
}
private int getWindowWidth() {
- return mMargin * 2 + getLayoutWidth();
+ return getMarginStartEndWith(mLastConfiguration) * 2 + getLayoutWidth();
}
private int getWindowHeight() {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index ec930b0..11412f4 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -67,6 +67,7 @@
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -111,6 +112,7 @@
@NonNull private final FalsingManager mFalsingManager;
@NonNull private final PowerManager mPowerManager;
@NonNull private final AccessibilityManager mAccessibilityManager;
+ @NonNull private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
@Nullable private final UdfpsHbmProvider mHbmProvider;
// Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
// sensors, this, in addition to a lot of the code here, will be updated.
@@ -507,6 +509,7 @@
@NonNull FalsingManager falsingManager,
@NonNull PowerManager powerManager,
@NonNull AccessibilityManager accessibilityManager,
+ @NonNull LockscreenShadeTransitionController lockscreenShadeTransitionController,
@NonNull ScreenLifecycle screenLifecycle,
@Nullable Vibrator vibrator,
@NonNull Optional<UdfpsHbmProvider> hbmProvider) {
@@ -529,6 +532,7 @@
mFalsingManager = falsingManager;
mPowerManager = powerManager;
mAccessibilityManager = accessibilityManager;
+ mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
mHbmProvider = hbmProvider.orElse(null);
screenLifecycle.addObserver(mScreenObserver);
mScreenOn = screenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_ON;
@@ -716,6 +720,7 @@
mFgExecutor,
mDumpManager,
mKeyguardViewMediator,
+ mLockscreenShadeTransitionController,
this
);
case IUdfpsOverlayController.REASON_AUTH_BP:
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
index 00888df..35ca470 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -31,6 +31,7 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -54,6 +55,7 @@
@NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@NonNull private final DelayableExecutor mExecutor;
@NonNull private final KeyguardViewMediator mKeyguardViewMediator;
+ @NonNull private final LockscreenShadeTransitionController mLockScreenShadeTransitionController;
@NonNull private final UdfpsController mUdfpsController;
@Nullable private Runnable mCancelDelayedHintRunnable;
@@ -63,6 +65,7 @@
private boolean mFaceDetectRunning;
private boolean mHintShown;
private int mStatusBarState;
+ private float mTransitionToFullShadeProgress;
/**
* hidden amount of pin/pattern/password bouncer
@@ -81,12 +84,14 @@
@NonNull DelayableExecutor mainDelayableExecutor,
@NonNull DumpManager dumpManager,
@NonNull KeyguardViewMediator keyguardViewMediator,
+ @NonNull LockscreenShadeTransitionController transitionController,
@NonNull UdfpsController udfpsController) {
super(view, statusBarStateController, statusBar, dumpManager);
mKeyguardViewManager = statusBarKeyguardViewManager;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mExecutor = mainDelayableExecutor;
mKeyguardViewMediator = keyguardViewMediator;
+ mLockScreenShadeTransitionController = transitionController;
mUdfpsController = udfpsController;
}
@@ -116,6 +121,7 @@
updatePauseAuth();
mKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor);
+ mLockScreenShadeTransitionController.setUdfpsKeyguardViewController(this);
}
@Override
@@ -127,6 +133,9 @@
mStatusBarStateController.removeCallback(mStateListener);
mKeyguardViewManager.removeAlternateAuthInterceptor(mAlternateAuthInterceptor);
mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false);
+ if (mLockScreenShadeTransitionController.getUdfpsKeyguardViewController() == this) {
+ mLockScreenShadeTransitionController.setUdfpsKeyguardViewController(null);
+ }
if (mCancelDelayedHintRunnable != null) {
mCancelDelayedHintRunnable.run();
@@ -256,11 +265,21 @@
}
}
+ /**
+ * Set the progress we're currently transitioning to the full shade. 0.0f means we're not
+ * transitioning yet, while 1.0f means we've fully dragged down.
+ */
+ public void setTransitionToFullShadeProgress(float progress) {
+ mTransitionToFullShadeProgress = progress;
+ updateAlpha();
+ }
+
private void updateAlpha() {
// fade icon on transition to showing bouncer
int alpha = mShowingUdfpsBouncer ? 255
: Math.abs((int) MathUtils.constrainedMap(0f, 255f, .4f, .7f,
mInputBouncerHiddenAmount));
+ alpha *= (1.0f - mTransitionToFullShadeProgress);
mView.setUnpausedAlpha(alpha);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
index 2dbf30f..de8ed70 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
@@ -25,6 +25,7 @@
import com.android.systemui.screenrecord.ScreenRecordDialog;
import com.android.systemui.screenshot.LongScreenshotActivity;
import com.android.systemui.sensorprivacy.SensorUseStartedActivity;
+import com.android.systemui.sensorprivacy.television.TvUnblockSensorActivity;
import com.android.systemui.settings.brightness.BrightnessDialog;
import com.android.systemui.statusbar.tv.notifications.TvNotificationPanelActivity;
import com.android.systemui.tuner.TunerActivity;
@@ -120,4 +121,10 @@
@IntoMap
@ClassKey(SensorUseStartedActivity.class)
public abstract Activity bindSensorUseStartedActivity(SensorUseStartedActivity activity);
+
+ /** Inject into TvUnblockSensorActivity. */
+ @Binds
+ @IntoMap
+ @ClassKey(TvUnblockSensorActivity.class)
+ public abstract Activity bindTvUnblockSensorActivity(TvUnblockSensorActivity activity);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 746621d..d85c9a7 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -231,7 +231,8 @@
@Main Handler mainHandler,
UiEventLogger uiEventLogger,
NavigationBarOverlayController navBarOverlayController,
- ConfigurationController configurationController) {
+ ConfigurationController configurationController,
+ UserTracker userTracker) {
return new NavigationBarController(context,
windowManager,
assistManagerLazy,
@@ -256,7 +257,8 @@
mainHandler,
uiEventLogger,
navBarOverlayController,
- configurationController);
+ configurationController,
+ userTracker);
}
/** */
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index 053d75d..954ba79 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -63,6 +63,7 @@
import android.telecom.TelecomManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.view.CrossWindowBlurListeners;
import android.view.IWindowManager;
import android.view.ViewConfiguration;
import android.view.WindowManager;
@@ -139,6 +140,12 @@
}
@Provides
+ @Singleton
+ static CrossWindowBlurListeners provideCrossWindowBlurListeners() {
+ return CrossWindowBlurListeners.getInstance();
+ }
+
+ @Provides
@DisplayId
static int provideDisplayId(Context context) {
return context.getDisplayId();
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index 0d5faff..1d6d1f2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -46,7 +46,7 @@
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private ViewGroup mConnectedItem;
- private boolean mInclueDynamicGroup;
+ private boolean mIncludeDynamicGroup;
public MediaOutputAdapter(MediaOutputController controller) {
super(controller);
@@ -56,7 +56,6 @@
public MediaDeviceBaseViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup,
int viewType) {
super.onCreateViewHolder(viewGroup, viewType);
-
return new MediaDeviceViewHolder(mHolderView);
}
@@ -66,7 +65,7 @@
if (position == size && mController.isZeroMode()) {
viewHolder.onBind(CUSTOMIZED_ITEM_PAIR_NEW, false /* topMargin */,
true /* bottomMargin */);
- } else if (mInclueDynamicGroup) {
+ } else if (mIncludeDynamicGroup) {
if (position == 0) {
viewHolder.onBind(CUSTOMIZED_ITEM_DYNAMIC_GROUP, true /* topMargin */,
false /* bottomMargin */);
@@ -76,11 +75,12 @@
// from "position - 1".
viewHolder.onBind(((List<MediaDevice>) (mController.getMediaDevices()))
.get(position - 1),
- false /* topMargin */, position == size /* bottomMargin */);
+ false /* topMargin */, position == size /* bottomMargin */, position);
}
} else if (position < size) {
viewHolder.onBind(((List<MediaDevice>) (mController.getMediaDevices())).get(position),
- position == 0 /* topMargin */, position == (size - 1) /* bottomMargin */);
+ position == 0 /* topMargin */, position == (size - 1) /* bottomMargin */,
+ position);
} else if (DEBUG) {
Log.d(TAG, "Incorrect position: " + position);
}
@@ -88,8 +88,8 @@
@Override
public int getItemCount() {
- mInclueDynamicGroup = mController.getSelectedMediaDevice().size() > 1;
- if (mController.isZeroMode() || mInclueDynamicGroup) {
+ mIncludeDynamicGroup = mController.getSelectedMediaDevice().size() > 1;
+ if (mController.isZeroMode() || mIncludeDynamicGroup) {
// Add extra one for "pair new" or dynamic group
return mController.getMediaDevices().size() + 1;
}
@@ -120,15 +120,17 @@
}
@Override
- void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin) {
- super.onBind(device, topMargin, bottomMargin);
- final boolean currentlyConnected = !mInclueDynamicGroup && isCurrentlyConnected(device);
+ void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin, int position) {
+ super.onBind(device, topMargin, bottomMargin, position);
+ final boolean currentlyConnected = !mIncludeDynamicGroup
+ && isCurrentlyConnected(device);
if (currentlyConnected) {
mConnectedItem = mContainerLayout;
}
mBottomDivider.setVisibility(View.GONE);
mCheckBox.setVisibility(View.GONE);
- if (currentlyConnected && mController.isActiveRemoteDevice(device)) {
+ if (currentlyConnected && mController.isActiveRemoteDevice(device)
+ && mController.getSelectableMediaDevice().size() > 0) {
// Init active device layout
mDivider.setVisibility(View.VISIBLE);
mDivider.setTransitionAlpha(1);
@@ -160,6 +162,7 @@
setTwoLineLayout(device, true /* bFocused */, true /* showSeekBar */,
false /* showProgressBar */, false /* showSubtitle */);
initSeekbar(device);
+ mCurrentActivePosition = position;
} else {
setSingleLineLayout(getItemTitle(device), false /* bFocused */);
mContainerLayout.setOnClickListener(v -> onItemClick(v, device));
@@ -186,11 +189,16 @@
mConnectedItem = mContainerLayout;
mBottomDivider.setVisibility(View.GONE);
mCheckBox.setVisibility(View.GONE);
- mDivider.setVisibility(View.VISIBLE);
- mDivider.setTransitionAlpha(1);
- mAddIcon.setVisibility(View.VISIBLE);
- mAddIcon.setTransitionAlpha(1);
- mAddIcon.setOnClickListener(v -> onEndItemClick());
+ if (mController.getSelectableMediaDevice().size() > 0) {
+ mDivider.setVisibility(View.VISIBLE);
+ mDivider.setTransitionAlpha(1);
+ mAddIcon.setVisibility(View.VISIBLE);
+ mAddIcon.setTransitionAlpha(1);
+ mAddIcon.setOnClickListener(v -> onEndItemClick());
+ } else {
+ mDivider.setVisibility(View.GONE);
+ mAddIcon.setVisibility(View.GONE);
+ }
mTitleIcon.setImageDrawable(getSpeakerDrawable());
final CharSequence sessionName = mController.getSessionName();
final CharSequence title = TextUtils.isEmpty(sessionName)
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
index bcef43c..0890841 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -64,10 +64,12 @@
Context mContext;
View mHolderView;
boolean mIsDragging;
+ int mCurrentActivePosition;
public MediaOutputBaseAdapter(MediaOutputController controller) {
mController = controller;
mIsDragging = false;
+ mCurrentActivePosition = -1;
}
@Override
@@ -99,6 +101,10 @@
return mIsAnimating;
}
+ int getCurrentActivePosition() {
+ return mCurrentActivePosition;
+ }
+
/**
* ViewHolder for binding device view.
*/
@@ -136,7 +142,7 @@
mCheckBox = view.requireViewById(R.id.check_box);
}
- void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin) {
+ void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin, int position) {
mDeviceId = device.getId();
ThreadUtils.postOnBackgroundThread(() -> {
Icon icon = mController.getDeviceIconCompat(device).toIcon(mContext);
@@ -214,6 +220,9 @@
}
void initSeekbar(MediaDevice device) {
+ if (!mController.isVolumeControlEnabled(device)) {
+ disableSeekBar();
+ }
mSeekBar.setMax(device.getMaxVolume());
mSeekBar.setMin(0);
final int currentVolume = device.getCurrentVolume();
@@ -242,6 +251,7 @@
}
void initSessionSeekbar() {
+ disableSeekBar();
mSeekBar.setMax(mController.getSessionVolumeMax());
mSeekBar.setMin(0);
final int currentVolume = mController.getSessionVolume();
@@ -330,5 +340,10 @@
PorterDuff.Mode.SRC_IN));
return BluetoothUtils.buildAdvancedDrawable(mContext, drawable);
}
+
+ private void disableSeekBar() {
+ mSeekBar.setEnabled(false);
+ mSeekBar.setOnTouchListener((v, event) -> true);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index 8a9a6e6..cdcdf9a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -174,7 +174,12 @@
mHeaderTitle.setGravity(Gravity.NO_GRAVITY);
}
if (!mAdapter.isDragging() && !mAdapter.isAnimating()) {
- mAdapter.notifyDataSetChanged();
+ int currentActivePosition = mAdapter.getCurrentActivePosition();
+ if (currentActivePosition >= 0) {
+ mAdapter.notifyItemChanged(currentActivePosition);
+ } else {
+ mAdapter.notifyDataSetChanged();
+ }
}
// Show when remote media session is available
mStopButton.setVisibility(getStopButtonVisibility());
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 8fee925..5293c88 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -465,6 +465,10 @@
|| features.contains(MediaRoute2Info.FEATURE_REMOTE_GROUP_PLAYBACK));
}
+ boolean isVolumeControlEnabled(@NonNull MediaDevice device) {
+ return !device.getFeatures().contains(MediaRoute2Info.FEATURE_REMOTE_GROUP_PLAYBACK);
+ }
+
private final MediaController.Callback mCb = new MediaController.Callback() {
@Override
public void onMetadataChanged(MediaMetadata metadata) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java
index 24e076b..968c350 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java
@@ -68,7 +68,7 @@
final int size = mGroupMediaDevices.size();
if (newPosition < size) {
viewHolder.onBind(mGroupMediaDevices.get(newPosition), false /* topMargin */,
- newPosition == (size - 1) /* bottomMargin */);
+ newPosition == (size - 1) /* bottomMargin */, position);
return;
}
if (DEBUG) {
@@ -94,8 +94,8 @@
}
@Override
- void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin) {
- super.onBind(device, topMargin, bottomMargin);
+ void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin, int position) {
+ super.onBind(device, topMargin, bottomMargin, position);
mDivider.setVisibility(View.GONE);
mAddIcon.setVisibility(View.GONE);
mBottomDivider.setVisibility(View.GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index da09793..711bb56 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -129,6 +129,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.AutoHideUiElement;
@@ -199,6 +200,7 @@
private final Handler mHandler;
private final NavigationBarOverlayController mNavbarOverlayController;
private final UiEventLogger mUiEventLogger;
+ private final UserTracker mUserTracker;
private Bundle mSavedState;
private NavigationBarView mNavigationBarView;
@@ -232,7 +234,6 @@
private boolean mTransientShown;
private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
- private int mA11yBtnMode;
private LightBarController mLightBarController;
private AutoHideController mAutoHideController;
@@ -459,7 +460,8 @@
SystemActions systemActions,
@Main Handler mainHandler,
NavigationBarOverlayController navbarOverlayController,
- UiEventLogger uiEventLogger) {
+ UiEventLogger uiEventLogger,
+ UserTracker userTracker) {
mContext = context;
mWindowManager = windowManager;
mAccessibilityManager = accessibilityManager;
@@ -484,10 +486,10 @@
mHandler = mainHandler;
mNavbarOverlayController = navbarOverlayController;
mUiEventLogger = uiEventLogger;
+ mUserTracker = userTracker;
mNavBarMode = mNavigationModeController.addListener(this);
mAccessibilityButtonModeObserver.addListener(this);
- mA11yBtnMode = mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode();
}
public NavigationBarView getView() {
@@ -1375,8 +1377,9 @@
private void setAccessibilityFloatingMenuModeIfNeeded() {
if (QuickStepContract.isGesturalMode(mNavBarMode)) {
- Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
- ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU);
+ Settings.Secure.putIntForUser(mContentResolver,
+ Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
+ ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU, UserHandle.USER_CURRENT);
}
}
@@ -1437,7 +1440,8 @@
// If accessibility button is floating menu mode, click and long click state should be
// disabled.
- if (mA11yBtnMode == ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU) {
+ if (mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode()
+ == ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU) {
return 0;
}
@@ -1450,12 +1454,14 @@
.getAssistInfoForUser(UserHandle.USER_CURRENT) != null;
boolean longPressDefault = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_assistLongPressHomeEnabledDefault);
- mLongPressHomeEnabled = Settings.Secure.getInt(mContentResolver,
- Settings.Secure.ASSIST_LONG_PRESS_HOME_ENABLED, longPressDefault ? 1 : 0) != 0;
+ mLongPressHomeEnabled = Settings.Secure.getIntForUser(mContentResolver,
+ Settings.Secure.ASSIST_LONG_PRESS_HOME_ENABLED, longPressDefault ? 1 : 0,
+ mUserTracker.getUserId()) != 0;
boolean gestureDefault = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_assistTouchGestureEnabledDefault);
- mAssistantTouchGestureEnabled = Settings.Secure.getInt(mContentResolver,
- Settings.Secure.ASSIST_TOUCH_GESTURE_ENABLED, gestureDefault ? 1 : 0) != 0;
+ mAssistantTouchGestureEnabled = Settings.Secure.getIntForUser(mContentResolver,
+ Settings.Secure.ASSIST_TOUCH_GESTURE_ENABLED, gestureDefault ? 1 : 0,
+ mUserTracker.getUserId()) != 0;
if (mOverviewProxyService.getProxy() != null) {
try {
mOverviewProxyService.getProxy().onAssistantAvailable(mAssistantAvailable
@@ -1546,7 +1552,6 @@
@Override
public void onAccessibilityButtonModeChanged(int mode) {
- mA11yBtnMode = mode;
updateAccessibilityServicesState(mAccessibilityManager);
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index 8b5a537..5359210 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -57,6 +57,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CommandQueue.Callbacks;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -116,6 +117,7 @@
private final TaskbarDelegate mTaskbarDelegate;
private int mNavMode;
private boolean mIsTablet;
+ private final UserTracker mUserTracker;
/** A displayId - nav bar maps. */
@VisibleForTesting
@@ -151,7 +153,8 @@
@Main Handler mainHandler,
UiEventLogger uiEventLogger,
NavigationBarOverlayController navBarOverlayController,
- ConfigurationController configurationController) {
+ ConfigurationController configurationController,
+ UserTracker userTracker) {
mContext = context;
mWindowManager = windowManager;
mAssistManagerLazy = assistManagerLazy;
@@ -184,6 +187,7 @@
mNavigationModeController.addListener(this);
mTaskbarDelegate = new TaskbarDelegate(mOverviewProxyService);
mIsTablet = isTablet(mContext.getResources().getConfiguration());
+ mUserTracker = userTracker;
}
@Override
@@ -361,7 +365,8 @@
mSystemActions,
mHandler,
mNavBarOverlayController,
- mUiEventLogger);
+ mUiEventLogger,
+ mUserTracker);
mNavigationBars.put(displayId, navBar);
View navigationBarView = navBar.createView(savedState);
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleStoryIconFactory.java b/packages/SystemUI/src/com/android/systemui/people/PeopleStoryIconFactory.java
index 96aeb60..4ee951f 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleStoryIconFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleStoryIconFactory.java
@@ -211,7 +211,8 @@
@Override
public void setColorFilter(ColorFilter colorFilter) {
- // unimplemented
+ if (mAvatar != null) mAvatar.setColorFilter(colorFilter);
+ if (mBadgeIcon != null) mBadgeIcon.setColorFilter(colorFilter);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
index 0e17c8b..4a8775f 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
@@ -29,6 +29,8 @@
import static android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH;
import static android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT;
import static android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH;
+import static android.util.TypedValue.COMPLEX_UNIT_DIP;
+import static android.util.TypedValue.COMPLEX_UNIT_PX;
import static com.android.systemui.people.PeopleSpaceUtils.STARRED_CONTACT;
import static com.android.systemui.people.PeopleSpaceUtils.VALID_CONTACT;
@@ -43,11 +45,16 @@
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
+import android.graphics.text.LineBreaker;
import android.net.Uri;
import android.os.Bundle;
import android.os.UserHandle;
+import android.text.StaticLayout;
+import android.text.TextPaint;
import android.text.TextUtils;
import android.util.IconDrawableFactory;
import android.util.Log;
@@ -58,8 +65,11 @@
import android.widget.RemoteViews;
import android.widget.TextView;
+import androidx.annotation.DimenRes;
+import androidx.annotation.Px;
import androidx.core.graphics.drawable.RoundedBitmapDrawable;
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
+import androidx.core.math.MathUtils;
import com.android.internal.annotations.VisibleForTesting;
import com.android.launcher3.icons.FastBitmapDrawable;
@@ -197,12 +207,16 @@
*/
private RemoteViews getViewForTile() {
if (DEBUG) Log.d(TAG, "Creating view for tile key: " + mKey.toString());
- if (mTile == null || mTile.isPackageSuspended() || mTile.isUserQuieted()
- || isDndBlockingTileData(mTile)) {
+ if (mTile == null || mTile.isPackageSuspended() || mTile.isUserQuieted()) {
if (DEBUG) Log.d(TAG, "Create suppressed view: " + mTile);
return createSuppressedView();
}
+ if (isDndBlockingTileData(mTile)) {
+ if (DEBUG) Log.d(TAG, "Create dnd view");
+ return createDndRemoteViews().mRemoteViews;
+ }
+
if (Objects.equals(mTile.getNotificationCategory(), CATEGORY_MISSED_CALL)) {
if (DEBUG) Log.d(TAG, "Create missed call view");
return createMissedCallRemoteViews();
@@ -236,7 +250,9 @@
return createLastInteractionRemoteViews();
}
- private boolean isDndBlockingTileData(PeopleSpaceTile tile) {
+ private static boolean isDndBlockingTileData(@Nullable PeopleSpaceTile tile) {
+ if (tile == null) return false;
+
int notificationPolicyState = tile.getNotificationPolicyState();
if ((notificationPolicyState & PeopleSpaceTile.SHOW_CONVERSATIONS) != 0) {
// Not in DND, or all conversations
@@ -413,6 +429,11 @@
int avatarWidthSpace = mWidth - (14 + 14);
avatarSize = Math.min(avatarHeightSpace, avatarWidthSpace);
}
+
+ if (isDndBlockingTileData(mTile)) {
+ avatarSize = createDndRemoteViews().mAvatarSize;
+ }
+
return Math.min(avatarSize,
getSizeInDp(R.dimen.max_people_avatar_size));
}
@@ -473,6 +494,87 @@
return views;
}
+ private RemoteViewsAndSizes createDndRemoteViews() {
+ boolean isHorizontal = mLayoutSize == LAYOUT_MEDIUM;
+ int layoutId = isHorizontal
+ ? R.layout.people_tile_with_suppression_detail_content_horizontal
+ : R.layout.people_tile_with_suppression_detail_content_vertical;
+ RemoteViews views = new RemoteViews(mContext.getPackageName(), layoutId);
+
+ int outerPadding = mLayoutSize == LAYOUT_LARGE ? 16 : 8;
+ int outerPaddingPx = dpToPx(outerPadding);
+ views.setViewPadding(
+ R.id.item,
+ outerPaddingPx,
+ outerPaddingPx,
+ outerPaddingPx,
+ outerPaddingPx);
+
+ int mediumAvatarSize = getSizeInDp(R.dimen.avatar_size_for_medium);
+ int maxAvatarSize = getSizeInDp(R.dimen.max_people_avatar_size);
+
+ String text = mContext.getString(R.string.paused_by_dnd);
+ views.setTextViewText(R.id.text_content, text);
+
+ int textSizeResId =
+ mLayoutSize == LAYOUT_LARGE
+ ? R.dimen.content_text_size_for_large
+ : R.dimen.content_text_size_for_medium;
+ float textSizePx = mContext.getResources().getDimension(textSizeResId);
+ views.setTextViewTextSize(R.id.text_content, COMPLEX_UNIT_PX, textSizePx);
+ int lineHeight = getLineHeightFromResource(textSizeResId);
+
+ int avatarSize;
+ if (isHorizontal) {
+ int maxTextHeight = mHeight - outerPadding;
+ views.setInt(R.id.text_content, "setMaxLines", maxTextHeight / lineHeight);
+ avatarSize = mediumAvatarSize;
+ } else {
+ int iconSize =
+ getSizeInDp(
+ mLayoutSize == LAYOUT_SMALL
+ ? R.dimen.regular_predefined_icon
+ : R.dimen.largest_predefined_icon);
+ int heightWithoutIcon = mHeight - 2 * outerPadding - iconSize;
+ int paddingBetweenElements =
+ getSizeInDp(R.dimen.padding_between_suppressed_layout_items);
+ int maxTextWidth = mWidth - outerPadding * 2;
+ int maxTextHeight = heightWithoutIcon - mediumAvatarSize - paddingBetweenElements * 2;
+
+ int availableAvatarHeight;
+ int textHeight = estimateTextHeight(text, textSizeResId, maxTextWidth);
+ if (textHeight <= maxTextHeight) {
+ // If the text will fit, then display it and deduct its height from the space we
+ // have for the avatar.
+ availableAvatarHeight = heightWithoutIcon - textHeight - paddingBetweenElements * 2;
+ views.setViewVisibility(R.id.text_content, View.VISIBLE);
+ views.setInt(R.id.text_content, "setMaxLines", maxTextHeight / lineHeight);
+ views.setContentDescription(R.id.predefined_icon, null);
+ } else {
+ // If the height doesn't fit, then hide it. The dnd icon will still show.
+ availableAvatarHeight = heightWithoutIcon - paddingBetweenElements;
+ views.setViewVisibility(R.id.text_content, View.GONE);
+ // If we don't show the dnd text, set it as the content description on the icon
+ // for a11y.
+ views.setContentDescription(R.id.predefined_icon, text);
+ }
+
+ int availableAvatarWidth = mWidth - outerPadding * 2;
+ avatarSize =
+ MathUtils.clamp(
+ /* value= */ Math.min(availableAvatarWidth, availableAvatarHeight),
+ /* min= */ dpToPx(10),
+ /* max= */ maxAvatarSize);
+
+ views.setViewLayoutWidth(R.id.predefined_icon, iconSize, COMPLEX_UNIT_DIP);
+ views.setViewLayoutHeight(R.id.predefined_icon, iconSize, COMPLEX_UNIT_DIP);
+ views.setImageViewResource(R.id.predefined_icon, R.drawable.ic_qs_dnd_on);
+ }
+
+ return new RemoteViewsAndSizes(views, avatarSize);
+ }
+
+
private RemoteViews createMissedCallRemoteViews() {
RemoteViews views = setViewForContentLayout(new RemoteViews(mContext.getPackageName(),
getLayoutForContent()));
@@ -486,8 +588,8 @@
views.setImageViewResource(R.id.predefined_icon, R.drawable.ic_phone_missed);
if (mLayoutSize == LAYOUT_LARGE) {
views.setInt(R.id.content, "setGravity", Gravity.BOTTOM);
- views.setViewLayoutHeightDimen(R.id.predefined_icon, R.dimen.large_predefined_icon);
- views.setViewLayoutWidthDimen(R.id.predefined_icon, R.dimen.large_predefined_icon);
+ views.setViewLayoutHeightDimen(R.id.predefined_icon, R.dimen.larger_predefined_icon);
+ views.setViewLayoutWidthDimen(R.id.predefined_icon, R.dimen.larger_predefined_icon);
}
setAvailabilityDotPadding(views, R.dimen.availability_dot_notification_padding);
return views;
@@ -932,6 +1034,14 @@
Drawable personDrawable = storyIcon.getPeopleTileDrawable(roundedDrawable,
tile.getPackageName(), getUserId(tile), tile.isImportantConversation(),
hasNewStory);
+
+ if (isDndBlockingTileData(tile)) {
+ // If DND is blocking the conversation, then display the icon in grayscale.
+ ColorMatrix colorMatrix = new ColorMatrix();
+ colorMatrix.setSaturation(0);
+ personDrawable.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
+ }
+
return convertDrawableToBitmap(personDrawable);
}
@@ -960,4 +1070,69 @@
return context.getString(R.string.over_two_weeks_timestamp);
}
}
+
+ /**
+ * Estimates the height (in dp) which the text will have given the text size and the available
+ * width. Returns Integer.MAX_VALUE if the estimation couldn't be obtained, as this is intended
+ * to be used an estimate of the maximum.
+ */
+ private int estimateTextHeight(
+ CharSequence text,
+ @DimenRes int textSizeResId,
+ int availableWidthDp) {
+ StaticLayout staticLayout = buildStaticLayout(text, textSizeResId, availableWidthDp);
+ if (staticLayout == null) {
+ // Return max value (rather than e.g. -1) so the value can be used with <= bound checks.
+ return Integer.MAX_VALUE;
+ }
+ return pxToDp(staticLayout.getHeight());
+ }
+
+ /**
+ * Builds a StaticLayout for the text given the text size and available width. This can be used
+ * to obtain information about how TextView will lay out the text. Returns null if any error
+ * occurred creating a TextView.
+ */
+ @Nullable
+ private StaticLayout buildStaticLayout(
+ CharSequence text,
+ @DimenRes int textSizeResId,
+ int availableWidthDp) {
+ try {
+ TextView textView = new TextView(mContext);
+ textView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
+ mContext.getResources().getDimension(textSizeResId));
+ textView.setTextAppearance(android.R.style.TextAppearance_DeviceDefault);
+ TextPaint paint = textView.getPaint();
+ return StaticLayout.Builder.obtain(
+ text, 0, text.length(), paint, dpToPx(availableWidthDp))
+ // Simple break strategy avoids hyphenation unless there's a single word longer
+ // than the line width. We use this break strategy so that we consider text to
+ // "fit" only if it fits in a nice way (i.e. without hyphenation in the middle
+ // of words).
+ .setBreakStrategy(LineBreaker.BREAK_STRATEGY_SIMPLE)
+ .build();
+ } catch (Exception e) {
+ Log.e(TAG, "Could not create static layout: " + e);
+ return null;
+ }
+ }
+
+ private int dpToPx(float dp) {
+ return (int) (dp * mDensity);
+ }
+
+ private int pxToDp(@Px float px) {
+ return (int) (px / mDensity);
+ }
+
+ private static final class RemoteViewsAndSizes {
+ final RemoteViews mRemoteViews;
+ final int mAvatarSize;
+
+ RemoteViewsAndSizes(RemoteViews remoteViews, int avatarSize) {
+ mRemoteViews = remoteViews;
+ mAvatarSize = avatarSize;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/television/PrivacyChipDrawable.java b/packages/SystemUI/src/com/android/systemui/privacy/television/PrivacyChipDrawable.java
new file mode 100644
index 0000000..e5479ba
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/privacy/television/PrivacyChipDrawable.java
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.privacy.television;
+
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.util.Log;
+
+import androidx.annotation.Keep;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.systemui.R;
+
+/**
+ * Drawable that can go from being the background of the privacy icons to a small dot.
+ * The icons are not included.
+ */
+public class PrivacyChipDrawable extends Drawable {
+
+ private static final String TAG = PrivacyChipDrawable.class.getSimpleName();
+ private static final boolean DEBUG = false;
+
+ private float mWidth;
+ private float mHeight;
+ private float mMarginEnd;
+ private float mRadius;
+ private int mDotAlpha;
+ private int mBgAlpha;
+
+ private float mTargetWidth;
+ private final int mMinWidth;
+ private final int mIconWidth;
+ private final int mIconPadding;
+ private final int mBgWidth;
+ private final int mBgHeight;
+ private final int mBgRadius;
+ private final int mDotSize;
+
+ private final AnimatorSet mFadeIn;
+ private final AnimatorSet mFadeOut;
+ private final AnimatorSet mCollapse;
+ private final AnimatorSet mExpand;
+ private Animator mWidthAnimator;
+
+ private final Paint mChipPaint;
+ private final Paint mBgPaint;
+
+ private boolean mIsRtl;
+
+ private boolean mIsExpanded = true;
+
+ private PrivacyChipDrawableListener mListener;
+
+ interface PrivacyChipDrawableListener {
+ void onFadeOutFinished();
+ }
+
+ public PrivacyChipDrawable(Context context) {
+ mChipPaint = new Paint();
+ mChipPaint.setStyle(Paint.Style.FILL);
+ mChipPaint.setColor(context.getColor(R.color.privacy_circle));
+ mChipPaint.setAlpha(mDotAlpha);
+ mChipPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
+
+ mBgPaint = new Paint();
+ mBgPaint.setStyle(Paint.Style.FILL);
+ mBgPaint.setColor(context.getColor(R.color.privacy_chip_dot_bg_tint));
+ mBgPaint.setAlpha(mBgAlpha);
+ mBgPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
+
+ mBgWidth = context.getResources().getDimensionPixelSize(R.dimen.privacy_chip_dot_bg_width);
+ mBgHeight = context.getResources().getDimensionPixelSize(
+ R.dimen.privacy_chip_dot_bg_height);
+ mBgRadius = context.getResources().getDimensionPixelSize(
+ R.dimen.privacy_chip_dot_bg_radius);
+
+ mMinWidth = context.getResources().getDimensionPixelSize(R.dimen.privacy_chip_min_width);
+ mIconWidth = context.getResources().getDimensionPixelSize(R.dimen.privacy_chip_icon_size);
+ mIconPadding = context.getResources().getDimensionPixelSize(
+ R.dimen.privacy_chip_icon_margin_in_between);
+ mDotSize = context.getResources().getDimensionPixelSize(R.dimen.privacy_chip_dot_size);
+
+ mWidth = mMinWidth;
+ mHeight = context.getResources().getDimensionPixelSize(R.dimen.privacy_chip_height);
+ mRadius = context.getResources().getDimensionPixelSize(R.dimen.privacy_chip_radius);
+
+ mExpand = (AnimatorSet) AnimatorInflater.loadAnimator(context,
+ R.anim.tv_privacy_chip_expand);
+ mExpand.setTarget(this);
+
+ mCollapse = (AnimatorSet) AnimatorInflater.loadAnimator(context,
+ R.anim.tv_privacy_chip_collapse);
+ mCollapse.setTarget(this);
+
+ mFadeIn = (AnimatorSet) AnimatorInflater.loadAnimator(context,
+ R.anim.tv_privacy_chip_fade_in);
+ mFadeIn.setTarget(this);
+
+ mFadeOut = (AnimatorSet) AnimatorInflater.loadAnimator(context,
+ R.anim.tv_privacy_chip_fade_out);
+ mFadeOut.setTarget(this);
+ mFadeOut.addListener(new Animator.AnimatorListener() {
+ private boolean mCancelled;
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mCancelled = false;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (!mCancelled && mListener != null) {
+ if (DEBUG) Log.d(TAG, "Fade-out complete");
+ mListener.onFadeOutFinished();
+ }
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCancelled = true;
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ // no-op
+ }
+ });
+ }
+
+ /**
+ * Pass null to remove listener.
+ */
+ public void setListener(@Nullable PrivacyChipDrawableListener listener) {
+ this.mListener = listener;
+ }
+
+ /**
+ * Call once the view that is showing the drawable is visible to start fading the chip in.
+ */
+ public void startInitialFadeIn() {
+ if (DEBUG) Log.d(TAG, "initial fade-in");
+ mFadeIn.start();
+ }
+
+ @Override
+ public void draw(@NonNull Canvas canvas) {
+ Rect bounds = getBounds();
+
+ int centerVertical = (bounds.bottom - bounds.top) / 2;
+ // Dot background
+ RectF bgBounds = new RectF(
+ mIsRtl ? bounds.left : bounds.right - mBgWidth,
+ centerVertical - mBgHeight / 2f,
+ mIsRtl ? bounds.left + mBgWidth : bounds.right,
+ centerVertical + mBgHeight / 2f);
+ if (DEBUG) Log.v(TAG, "bg: " + bgBounds.toShortString());
+ canvas.drawRoundRect(bgBounds, mBgRadius, mBgRadius, mBgPaint);
+
+ // Icon background / dot
+ RectF greenBounds = new RectF(
+ mIsRtl ? bounds.left + mMarginEnd : bounds.right - mWidth - mMarginEnd,
+ centerVertical - mHeight / 2,
+ mIsRtl ? bounds.left + mWidth + mMarginEnd : bounds.right - mMarginEnd,
+ centerVertical + mHeight / 2);
+ if (DEBUG) Log.v(TAG, "green: " + greenBounds.toShortString());
+ canvas.drawRoundRect(greenBounds, mRadius, mRadius, mChipPaint);
+ }
+
+ private void animateToNewTargetWidth(float width) {
+ if (DEBUG) Log.d(TAG, "new target width: " + width);
+ if (width != mTargetWidth) {
+ mTargetWidth = width;
+ Animator newWidthAnimator = ObjectAnimator.ofFloat(this, "width", mTargetWidth);
+ newWidthAnimator.start();
+ if (mWidthAnimator != null) {
+ mWidthAnimator.cancel();
+ }
+ mWidthAnimator = newWidthAnimator;
+ }
+ }
+
+ private void expand() {
+ if (DEBUG) Log.d(TAG, "expanding");
+ if (mIsExpanded) {
+ return;
+ }
+ mIsExpanded = true;
+
+ mExpand.start();
+ mCollapse.cancel();
+ }
+
+ /**
+ * Starts the animation to a dot.
+ */
+ public void collapse() {
+ if (DEBUG) Log.d(TAG, "collapsing");
+ if (!mIsExpanded) {
+ return;
+ }
+ mIsExpanded = false;
+
+ animateToNewTargetWidth(mDotSize);
+ mCollapse.start();
+ mExpand.cancel();
+ }
+
+ /**
+ * Fades out the view if 0 icons are to be shown, expands the chip if it has been collapsed and
+ * makes the width of the chip adjust to the amount of icons to be shown.
+ * Should not be called when only the order of the icons was changed as the chip will expand
+ * again without there being any real update.
+ *
+ * @param iconCount Can be 0 to fade out the chip.
+ */
+ public void updateIcons(int iconCount) {
+ if (DEBUG) Log.d(TAG, "updating icons: " + iconCount);
+
+ // calculate chip size and use it for end value of animation that is specified in code,
+ // not xml
+ if (iconCount == 0) {
+ // fade out if there are no icons
+ mFadeOut.start();
+
+ mWidthAnimator.cancel();
+ mFadeIn.cancel();
+ mExpand.cancel();
+ mCollapse.cancel();
+ return;
+ }
+
+ mFadeOut.cancel();
+ expand();
+ animateToNewTargetWidth(mMinWidth + (iconCount - 1) * (mIconWidth + mIconPadding));
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ setDotAlpha(alpha);
+ setBgAlpha(alpha);
+ }
+
+ @Override
+ public int getAlpha() {
+ return mDotAlpha;
+ }
+
+ /**
+ * Set alpha value the green part of the chip.
+ */
+ @Keep
+ public void setDotAlpha(int alpha) {
+ if (DEBUG) Log.v(TAG, "dot alpha updated to: " + alpha);
+ mDotAlpha = alpha;
+ mChipPaint.setAlpha(alpha);
+ }
+
+ @Keep
+ public int getDotAlpha() {
+ return mDotAlpha;
+ }
+
+ /**
+ * Set alpha value of the background of the chip.
+ */
+ @Keep
+ public void setBgAlpha(int alpha) {
+ if (DEBUG) Log.v(TAG, "bg alpha updated to: " + alpha);
+ mBgAlpha = alpha;
+ mBgPaint.setAlpha(alpha);
+ }
+
+ @Keep
+ public int getBgAlpha() {
+ return mBgAlpha;
+ }
+
+ @Override
+ public void setColorFilter(@Nullable ColorFilter colorFilter) {
+ // no-op
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ /**
+ * The radius of the green part of the chip, not the background.
+ */
+ @Keep
+ public void setRadius(float radius) {
+ mRadius = radius;
+ invalidateSelf();
+ }
+
+ /**
+ * @return The radius of the green part of the chip, not the background.
+ */
+ @Keep
+ public float getRadius() {
+ return mRadius;
+ }
+
+ /**
+ * Height of the green part of the chip, not including the background.
+ */
+ @Keep
+ public void setHeight(float height) {
+ mHeight = height;
+ invalidateSelf();
+ }
+
+ /**
+ * @return Height of the green part of the chip, not including the background.
+ */
+ @Keep
+ public float getHeight() {
+ return mHeight;
+ }
+
+ /**
+ * Width of the green part of the chip, not including the background.
+ */
+ @Keep
+ public void setWidth(float width) {
+ mWidth = width;
+ invalidateSelf();
+ }
+
+ /**
+ * @return Width of the green part of the chip, not including the background.
+ */
+ @Keep
+ public float getWidth() {
+ return mWidth;
+ }
+
+ /**
+ * Margin at the end of the green part of the chip, so that it will be placed in the middle of
+ * the rounded rectangle in the background.
+ */
+ @Keep
+ public void setMarginEnd(float marginEnd) {
+ mMarginEnd = marginEnd;
+ invalidateSelf();
+ }
+
+ /**
+ * @return Margin at the end of the green part of the chip, so that it will be placed in the
+ * middle of the rounded rectangle in the background.
+ */
+ @Keep
+ public float getMarginEnd() {
+ return mMarginEnd;
+ }
+
+ /**
+ * Sets the layout direction.
+ */
+ public void setRtl(boolean isRtl) {
+ mIsRtl = isRtl;
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/television/TvOngoingPrivacyChip.java b/packages/SystemUI/src/com/android/systemui/privacy/television/TvOngoingPrivacyChip.java
index 5ab7bd8..e4f5cde 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/television/TvOngoingPrivacyChip.java
+++ b/packages/SystemUI/src/com/android/systemui/privacy/television/TvOngoingPrivacyChip.java
@@ -25,9 +25,10 @@
import android.annotation.UiThread;
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Looper;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
@@ -38,15 +39,20 @@
import android.widget.ImageView;
import android.widget.LinearLayout;
+import androidx.annotation.NonNull;
+
import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.privacy.PrivacyChipBuilder;
import com.android.systemui.privacy.PrivacyItem;
import com.android.systemui.privacy.PrivacyItemController;
+import com.android.systemui.privacy.PrivacyType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import javax.inject.Inject;
@@ -56,9 +62,10 @@
* recording audio, accessing the camera or accessing the location.
*/
@SysUISingleton
-public class TvOngoingPrivacyChip extends SystemUI implements PrivacyItemController.Callback {
+public class TvOngoingPrivacyChip extends SystemUI implements PrivacyItemController.Callback,
+ PrivacyChipDrawable.PrivacyChipDrawableListener {
private static final String TAG = "TvOngoingPrivacyChip";
- static final boolean DEBUG = false;
+ private static final boolean DEBUG = false;
// This title is used in CameraMicIndicatorsPermissionTest and
// RecognitionServiceMicIndicatorTest.
@@ -68,7 +75,8 @@
@IntDef(prefix = {"STATE_"}, value = {
STATE_NOT_SHOWN,
STATE_APPEARING,
- STATE_SHOWN,
+ STATE_EXPANDED,
+ STATE_COLLAPSED,
STATE_DISAPPEARING
})
public @interface State {
@@ -76,46 +84,58 @@
private static final int STATE_NOT_SHOWN = 0;
private static final int STATE_APPEARING = 1;
- private static final int STATE_SHOWN = 2;
- private static final int STATE_DISAPPEARING = 3;
+ private static final int STATE_EXPANDED = 2;
+ private static final int STATE_COLLAPSED = 3;
+ private static final int STATE_DISAPPEARING = 4;
- private static final int ANIMATION_DURATION_MS = 200;
+ private static final int EXPANDED_DURATION_MS = 4000;
+ public final int mAnimationDurationMs;
private final Context mContext;
private final PrivacyItemController mPrivacyItemController;
- private View mIndicatorView;
+ private ViewGroup mIndicatorView;
private boolean mViewAndWindowAdded;
private ObjectAnimator mAnimator;
private boolean mMicCameraIndicatorFlagEnabled;
- private boolean mLocationIndicatorEnabled;
- private List<PrivacyItem> mPrivacyItems;
+ private boolean mAllIndicatorsEnabled;
+
+ @NonNull
+ private List<PrivacyItem> mPrivacyItems = Collections.emptyList();
private LinearLayout mIconsContainer;
private final int mIconSize;
private final int mIconMarginStart;
+ private PrivacyChipDrawable mChipDrawable;
+
+ private final Handler mUiThreadHandler = new Handler(Looper.getMainLooper());
+ private final Runnable mCollapseRunnable = this::collapseChip;
+
@State
private int mState = STATE_NOT_SHOWN;
@Inject
public TvOngoingPrivacyChip(Context context, PrivacyItemController privacyItemController) {
super(context);
- Log.d(TAG, "Privacy chip running without id");
+ if (DEBUG) Log.d(TAG, "Privacy chip running");
mContext = context;
mPrivacyItemController = privacyItemController;
Resources res = mContext.getResources();
- mIconMarginStart = Math.round(res.getDimension(R.dimen.privacy_chip_icon_margin));
+ mIconMarginStart = Math.round(
+ res.getDimension(R.dimen.privacy_chip_icon_margin_in_between));
mIconSize = res.getDimensionPixelSize(R.dimen.privacy_chip_icon_size);
+ mAnimationDurationMs = res.getInteger(R.integer.privacy_chip_animation_millis);
+
mMicCameraIndicatorFlagEnabled = privacyItemController.getMicCameraAvailable();
- mLocationIndicatorEnabled = privacyItemController.getLocationAvailable();
+ mAllIndicatorsEnabled = privacyItemController.getAllIndicatorsAvailable();
if (DEBUG) {
Log.d(TAG, "micCameraIndicators: " + mMicCameraIndicatorFlagEnabled);
- Log.d(TAG, "locationIndicators: " + mLocationIndicatorEnabled);
+ Log.d(TAG, "allIndicators: " + mAllIndicatorsEnabled);
}
}
@@ -125,69 +145,145 @@
}
@Override
- public void onPrivacyItemsChanged(List<PrivacyItem> privacyItems) {
+ public void onPrivacyItemsChanged(@NonNull List<PrivacyItem> privacyItems) {
if (DEBUG) Log.d(TAG, "PrivacyItemsChanged");
- mPrivacyItems = privacyItems;
- updateUI();
+
+ List<PrivacyItem> updatedPrivacyItems = new ArrayList<>(privacyItems);
+ // Never show the location indicator on tv.
+ if (updatedPrivacyItems.removeIf(
+ privacyItem -> privacyItem.getPrivacyType() == PrivacyType.TYPE_LOCATION)) {
+ if (DEBUG) Log.v(TAG, "Removed the location item");
+ }
+
+ if (isChipDisabled()) {
+ fadeOutIndicator();
+ mPrivacyItems = updatedPrivacyItems;
+ return;
+ }
+
+ // Do they have the same elements? (order doesn't matter)
+ if (updatedPrivacyItems.size() == mPrivacyItems.size()
+ && mPrivacyItems.containsAll(updatedPrivacyItems)) {
+ if (DEBUG) Log.d(TAG, "List wasn't updated");
+ return;
+ }
+
+ mPrivacyItems = updatedPrivacyItems;
+ updateChip();
+ }
+
+ private void updateChip() {
+ if (DEBUG) Log.d(TAG, mPrivacyItems.size() + " privacy items");
+
+ if (mPrivacyItems.isEmpty()) {
+ if (DEBUG) Log.d(TAG, "removing indicator (state: " + stateToString(mState) + ")");
+ fadeOutIndicator();
+ return;
+ }
+
+ if (DEBUG) Log.d(TAG, "Current state: " + stateToString(mState));
+ switch (mState) {
+ case STATE_NOT_SHOWN:
+ createAndShowIndicator();
+ break;
+ case STATE_APPEARING:
+ case STATE_EXPANDED:
+ updateIcons();
+ collapseLater();
+ break;
+ case STATE_COLLAPSED:
+ case STATE_DISAPPEARING:
+ mState = STATE_EXPANDED;
+ updateIcons();
+ animateIconAppearance();
+ break;
+ }
+ }
+
+ /**
+ * Collapse the chip EXPANDED_DURATION_MS from now.
+ */
+ private void collapseLater() {
+ mUiThreadHandler.removeCallbacks(mCollapseRunnable);
+ if (DEBUG) Log.d(TAG, "chip will collapse in " + EXPANDED_DURATION_MS + "ms");
+ mUiThreadHandler.postDelayed(mCollapseRunnable, EXPANDED_DURATION_MS);
+ }
+
+ private void collapseChip() {
+ if (DEBUG) Log.d(TAG, "collapseChip");
+
+ if (mState != STATE_EXPANDED) {
+ return;
+ }
+ mState = STATE_COLLAPSED;
+
+ if (mChipDrawable != null) {
+ mChipDrawable.collapse();
+ }
+ animateIconDisappearance();
}
@Override
public void onFlagMicCameraChanged(boolean flag) {
if (DEBUG) Log.d(TAG, "mic/camera indicators enabled: " + flag);
mMicCameraIndicatorFlagEnabled = flag;
+ updateChipOnFlagChanged();
}
@Override
- public void onFlagLocationChanged(boolean flag) {
- if (DEBUG) Log.d(TAG, "location indicators enabled: " + flag);
- mLocationIndicatorEnabled = flag;
+ public void onFlagAllChanged(boolean flag) {
+ if (DEBUG) Log.d(TAG, "all indicators enabled: " + flag);
+ mAllIndicatorsEnabled = flag;
+ updateChipOnFlagChanged();
}
- private void updateUI() {
- if (DEBUG) Log.d(TAG, mPrivacyItems.size() + " privacy items");
+ private boolean isChipDisabled() {
+ return !(mMicCameraIndicatorFlagEnabled || mAllIndicatorsEnabled);
+ }
- if ((mMicCameraIndicatorFlagEnabled || mLocationIndicatorEnabled)
- && !mPrivacyItems.isEmpty()) {
- if (mState == STATE_NOT_SHOWN || mState == STATE_DISAPPEARING) {
- showIndicator();
- } else {
- if (DEBUG) Log.d(TAG, "only updating icons");
- PrivacyChipBuilder builder = new PrivacyChipBuilder(mContext, mPrivacyItems);
- setIcons(builder.generateIcons(), mIconsContainer);
- mIconsContainer.requestLayout();
- }
+ private void updateChipOnFlagChanged() {
+ if (isChipDisabled()) {
+ fadeOutIndicator();
} else {
- hideIndicatorIfNeeded();
+ updateChip();
}
}
@UiThread
- private void hideIndicatorIfNeeded() {
+ private void fadeOutIndicator() {
if (mState == STATE_NOT_SHOWN || mState == STATE_DISAPPEARING) return;
+ mUiThreadHandler.removeCallbacks(mCollapseRunnable);
+
if (mViewAndWindowAdded) {
mState = STATE_DISAPPEARING;
- animateDisappearance();
+ animateIconDisappearance();
} else {
// Appearing animation has not started yet, as we were still waiting for the View to be
// laid out.
mState = STATE_NOT_SHOWN;
removeIndicatorView();
}
+ if (mChipDrawable != null) {
+ mChipDrawable.updateIcons(0);
+ }
}
@UiThread
- private void showIndicator() {
+ private void createAndShowIndicator() {
mState = STATE_APPEARING;
+ if (mIndicatorView != null || mViewAndWindowAdded) {
+ removeIndicatorView();
+ }
+
// Inflate the indicator view
- mIndicatorView = LayoutInflater.from(mContext).inflate(
+ mIndicatorView = (ViewGroup) LayoutInflater.from(mContext).inflate(
R.layout.tv_ongoing_privacy_chip, null);
- // 1. Set alpha to 0.
+ // 1. Set icon alpha to 0.
// 2. Wait until the window is shown and the view is laid out.
// 3. Start a "fade in" (alpha) animation.
- mIndicatorView.setAlpha(0f);
mIndicatorView
.getViewTreeObserver()
.addOnGlobalLayoutListener(
@@ -196,20 +292,35 @@
public void onGlobalLayout() {
// State could have changed to NOT_SHOWN (if all the recorders are
// already gone)
- if (mState != STATE_APPEARING) return;
+ if (mState != STATE_APPEARING) {
+ return;
+ }
mViewAndWindowAdded = true;
// Remove the observer
mIndicatorView.getViewTreeObserver().removeOnGlobalLayoutListener(
this);
- animateAppearance();
+ animateIconAppearance();
+ mChipDrawable.startInitialFadeIn();
}
});
+ final boolean isRtl = mContext.getResources().getConfiguration().getLayoutDirection()
+ == View.LAYOUT_DIRECTION_RTL;
+ if (DEBUG) Log.d(TAG, "is RTL: " + isRtl);
+
+ mChipDrawable = new PrivacyChipDrawable(mContext);
+ mChipDrawable.setListener(this);
+ mChipDrawable.setRtl(isRtl);
+ ImageView chipBackground = mIndicatorView.findViewById(R.id.chip_drawable);
+ if (chipBackground != null) {
+ chipBackground.setImageDrawable(mChipDrawable);
+ }
+
mIconsContainer = mIndicatorView.findViewById(R.id.icons_container);
- PrivacyChipBuilder builder = new PrivacyChipBuilder(mContext, mPrivacyItems);
- setIcons(builder.generateIcons(), mIconsContainer);
+ mIconsContainer.setAlpha(0f);
+ updateIcons();
final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
WRAP_CONTENT,
@@ -217,19 +328,19 @@
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
- layoutParams.gravity = Gravity.TOP | Gravity.END;
+ layoutParams.gravity = Gravity.TOP | (isRtl ? Gravity.LEFT : Gravity.RIGHT);
layoutParams.setTitle(LAYOUT_PARAMS_TITLE);
layoutParams.packageName = mContext.getPackageName();
final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
windowManager.addView(mIndicatorView, layoutParams);
-
}
- private void setIcons(List<Drawable> icons, ViewGroup iconsContainer) {
- iconsContainer.removeAllViews();
+ private void updateIcons() {
+ List<Drawable> icons = new PrivacyChipBuilder(mContext, mPrivacyItems).generateIcons();
+ mIconsContainer.removeAllViews();
for (int i = 0; i < icons.size(); i++) {
Drawable icon = icons.get(i);
- icon.mutate().setTint(Color.WHITE);
+ icon.mutate().setTint(mContext.getColor(R.color.privacy_icon_tint));
ImageView imageView = new ImageView(mContext);
imageView.setImageDrawable(icon);
imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
@@ -241,22 +352,25 @@
imageView.setLayoutParams(layoutParams);
}
}
+ if (mChipDrawable != null) {
+ mChipDrawable.updateIcons(icons.size());
+ }
}
- private void animateAppearance() {
- animateAlphaTo(1f);
+ private void animateIconAppearance() {
+ animateIconAlphaTo(1f);
}
- private void animateDisappearance() {
- animateAlphaTo(0f);
+ private void animateIconDisappearance() {
+ animateIconAlphaTo(0f);
}
- private void animateAlphaTo(final float endValue) {
+ private void animateIconAlphaTo(float endValue) {
if (mAnimator == null) {
if (DEBUG) Log.d(TAG, "set up animator");
mAnimator = new ObjectAnimator();
- mAnimator.setTarget(mIndicatorView);
+ mAnimator.setTarget(mIconsContainer);
mAnimator.setProperty(View.ALPHA);
mAnimator.addListener(new AnimatorListenerAdapter() {
boolean mCancelled;
@@ -280,7 +394,7 @@
// and then onAnimationEnd(...). We, however, only want to proceed here if the
// animation ended "naturally".
if (!mCancelled) {
- onAnimationFinished();
+ onIconAnimationFinished();
}
}
});
@@ -289,19 +403,37 @@
mAnimator.cancel();
}
- final float currentValue = mIndicatorView.getAlpha();
+ final float currentValue = mIconsContainer.getAlpha();
+ if (currentValue == endValue) {
+ if (DEBUG) Log.d(TAG, "alpha not changing");
+ return;
+ }
if (DEBUG) Log.d(TAG, "animate alpha to " + endValue + " from " + currentValue);
- mAnimator.setDuration((int) (Math.abs(currentValue - endValue) * ANIMATION_DURATION_MS));
+ mAnimator.setDuration(mAnimationDurationMs);
mAnimator.setFloatValues(endValue);
mAnimator.start();
}
- private void onAnimationFinished() {
- if (DEBUG) Log.d(TAG, "onAnimationFinished");
+ @Override
+ public void onFadeOutFinished() {
+ if (DEBUG) Log.d(TAG, "drawable fade-out finished");
+
+ if (mState == STATE_DISAPPEARING) {
+ removeIndicatorView();
+ mState = STATE_NOT_SHOWN;
+ }
+ }
+
+ private void onIconAnimationFinished() {
+ if (DEBUG) Log.d(TAG, "onAnimationFinished (icon fade)");
+
+ if (mState == STATE_APPEARING || mState == STATE_EXPANDED) {
+ collapseLater();
+ }
if (mState == STATE_APPEARING) {
- mState = STATE_SHOWN;
+ mState = STATE_EXPANDED;
} else if (mState == STATE_DISAPPEARING) {
removeIndicatorView();
mState = STATE_NOT_SHOWN;
@@ -312,14 +444,39 @@
if (DEBUG) Log.d(TAG, "removeIndicatorView");
final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
- if (windowManager != null) {
+ if (windowManager != null && mIndicatorView != null) {
windowManager.removeView(mIndicatorView);
}
mIndicatorView = null;
mAnimator = null;
+ if (mChipDrawable != null) {
+ mChipDrawable.setListener(null);
+ mChipDrawable = null;
+ }
+
mViewAndWindowAdded = false;
}
+ /**
+ * Used in debug logs.
+ */
+ private String stateToString(@State int state) {
+ switch (state) {
+ case STATE_NOT_SHOWN:
+ return "NOT_SHOWN";
+ case STATE_APPEARING:
+ return "APPEARING";
+ case STATE_EXPANDED:
+ return "EXPANDED";
+ case STATE_COLLAPSED:
+ return "COLLAPSED";
+ case STATE_DISAPPEARING:
+ return "DISAPPEARING";
+ default:
+ return "INVALID";
+ }
+ }
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index edfbed0..6660081 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -297,7 +297,7 @@
// start margin of next page).
qsPanelController.setPageMargin(mSideMargins);
} else if (view == mHeader) {
- // No content padding for the header.
+ quickStatusBarHeaderController.setContentMargins(mContentPadding, mContentPadding);
} else {
view.setPaddingRelative(
mContentPadding,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
index 2d0d87d..bcce87a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
@@ -46,6 +46,7 @@
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
public class QSDetail extends LinearLayout {
@@ -83,6 +84,8 @@
private boolean mSwitchState;
private QSFooter mFooter;
+ private NotificationsQuickSettingsContainer mContainer;
+
public QSDetail(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@@ -115,6 +118,10 @@
mClipper = new QSDetailClipper(this);
}
+ public void setContainer(NotificationsQuickSettingsContainer container) {
+ mContainer = container;
+ }
+
/** */
public void setQsPanel(QSPanelController panelController, QuickStatusBarHeader header,
QSFooter footer) {
@@ -242,6 +249,9 @@
}
sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
animateDetailVisibleDiff(x, y, visibleDiff, listener);
+ if (mContainer != null) {
+ mContainer.setDetailShowing(showingDetail);
+ }
}
protected void animateDetailVisibleDiff(int x, int y, boolean visibleDiff, AnimatorListener listener) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 7b8a6a0..c28c649 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -293,6 +293,7 @@
public void setContainer(ViewGroup container) {
if (container instanceof NotificationsQuickSettingsContainer) {
mQSCustomizerController.setContainer((NotificationsQuickSettingsContainer) container);
+ mQSDetail.setContainer((NotificationsQuickSettingsContainer) container);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 0bb0a3f..c70eaff 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -425,7 +425,7 @@
LinearLayout.LayoutParams layoutParams = (LayoutParams) hostView.getLayoutParams();
layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
layoutParams.width = horizontal ? 0 : ViewGroup.LayoutParams.MATCH_PARENT;
- layoutParams.weight = horizontal ? 1.2f : 0;
+ layoutParams.weight = horizontal ? 1f : 0;
// Add any bottom margin, such that the total spacing is correct. This is only
// necessary if the view isn't horizontal, since otherwise the padding is
// carried in the parent of this view (to ensure correct vertical alignment)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
index cbdcad5..76076f6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
@@ -177,7 +177,6 @@
mView.onAttach(mIconManager, mQSExpansionPathInterpolator);
mDemoModeController.addCallback(mDemoModeReceiver);
- mHeaderQsPanelController.setContentMargins(0, 0);
}
@Override
@@ -253,6 +252,10 @@
return mMicCameraIndicatorsEnabled || mLocationIndicatorsEnabled;
}
+ public void setContentMargins(int marginStart, int marginEnd) {
+ mHeaderQsPanelController.setContentMargins(marginStart, marginEnd);
+ }
+
private static class ClockDemoModeReceiver implements DemoMode {
private Clock mClockView;
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index c6b5eb7..5bb3413 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -291,19 +291,24 @@
? res.getString(R.string.screenrecord_ongoing_screen_only)
: res.getString(R.string.screenrecord_ongoing_screen_and_audio);
- Intent stopIntent = getNotificationIntent(this);
+ PendingIntent pendingIntent = PendingIntent.getService(
+ this,
+ REQUEST_CODE,
+ getNotificationIntent(this),
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
+ Notification.Action stopAction = new Notification.Action.Builder(
+ Icon.createWithResource(this, R.drawable.ic_android),
+ getResources().getString(R.string.screenrecord_stop_label),
+ pendingIntent).build();
Notification.Builder builder = new Notification.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_screenrecord)
.setContentTitle(notificationTitle)
- .setContentText(getResources().getString(R.string.screenrecord_stop_text))
.setUsesChronometer(true)
.setColorized(true)
.setColor(getResources().getColor(R.color.GM2_red_700))
.setOngoing(true)
.setForegroundServiceBehavior(Notification.FOREGROUND_SERVICE_IMMEDIATE)
- .setContentIntent(
- PendingIntent.getService(this, REQUEST_CODE, stopIntent,
- PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE))
+ .addAction(stopAction)
.addExtras(extras);
startForeground(NOTIFICATION_RECORDING_ID, builder.build());
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
index 4aead817f..55602a9 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
@@ -111,30 +111,21 @@
}
/**
- * Stores the given Bitmap to a temp file.
+ * Writes the given Bitmap to outputFile.
*/
- ListenableFuture<File> exportAsTempFile(Executor executor, Bitmap bitmap) {
+ ListenableFuture<File> exportToRawFile(Executor executor, Bitmap bitmap,
+ final File outputFile) {
return CallbackToFutureAdapter.getFuture(
(completer) -> {
executor.execute(() -> {
- File cachePath;
- try {
- cachePath = File.createTempFile("long_screenshot_cache_", ".tmp");
- try (FileOutputStream stream = new FileOutputStream(cachePath)) {
- bitmap.compress(mCompressFormat, mQuality, stream);
- } catch (IOException e) {
- if (cachePath.exists()) {
- //noinspection ResultOfMethodCallIgnored
- cachePath.delete();
- cachePath = null;
- }
- completer.setException(e);
- }
- if (cachePath != null) {
- completer.set(cachePath);
- }
+ try (FileOutputStream stream = new FileOutputStream(outputFile)) {
+ bitmap.compress(mCompressFormat, mQuality, stream);
+ completer.set(outputFile);
} catch (IOException e) {
- // Failed to create a new file
+ if (outputFile.exists()) {
+ //noinspection ResultOfMethodCallIgnored
+ outputFile.delete();
+ }
completer.setException(e);
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java b/packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java
index 730702e..51cc32a 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java
@@ -20,6 +20,7 @@
import android.graphics.HardwareRenderer;
import android.graphics.RecordingCanvas;
import android.graphics.Rect;
+import android.graphics.Region;
import android.graphics.RenderNode;
import android.graphics.drawable.Drawable;
import android.os.Handler;
@@ -46,7 +47,6 @@
private static final String TAG = "ImageTileSet";
- private CallbackRegistry<OnBoundsChangedListener, ImageTileSet, Rect> mOnBoundsListeners;
private CallbackRegistry<OnContentChangedListener, ImageTileSet, Rect> mContentListeners;
@Inject
@@ -54,14 +54,6 @@
mHandler = handler;
}
- interface OnBoundsChangedListener {
- /**
- * Reports an update to the bounding box that contains all active tiles. These are virtual
- * (capture) coordinates which can be either negative or positive.
- */
- void onBoundsChanged(int left, int top, int right, int bottom);
- }
-
interface OnContentChangedListener {
/**
* Mark as dirty and rebuild display list.
@@ -70,25 +62,9 @@
}
private final List<ImageTile> mTiles = new ArrayList<>();
- private final Rect mBounds = new Rect();
+ private final Region mRegion = new Region();
private final Handler mHandler;
- void addOnBoundsChangedListener(OnBoundsChangedListener listener) {
- if (mOnBoundsListeners == null) {
- mOnBoundsListeners = new CallbackRegistry<>(
- new NotifierCallback<OnBoundsChangedListener, ImageTileSet, Rect>() {
- @Override
- public void onNotifyCallback(OnBoundsChangedListener callback,
- ImageTileSet sender,
- int arg, Rect newBounds) {
- callback.onBoundsChanged(newBounds.left, newBounds.top, newBounds.right,
- newBounds.bottom);
- }
- });
- }
- mOnBoundsListeners.add(listener);
- }
-
void addOnContentChangedListener(OnContentChangedListener listener) {
if (mContentListeners == null) {
mContentListeners = new CallbackRegistry<>(
@@ -110,14 +86,8 @@
mHandler.post(() -> addTile(tile));
return;
}
- final Rect newBounds = new Rect(mBounds);
- final Rect newRect = tile.getLocation();
mTiles.add(tile);
- newBounds.union(newRect);
- if (!newBounds.equals(mBounds)) {
- mBounds.set(newBounds);
- notifyBoundsChanged(mBounds);
- }
+ mRegion.op(tile.getLocation(), mRegion, Region.Op.UNION);
notifyContentChanged();
}
@@ -127,12 +97,6 @@
}
}
- private void notifyBoundsChanged(Rect bounds) {
- if (mOnBoundsListeners != null) {
- mOnBoundsListeners.notifyCallbacks(this, 0, bounds);
- }
- }
-
/**
* Returns a drawable to paint the combined contents of the tiles. Drawable dimensions are
* zero-based and map directly to {@link #getLeft()}, {@link #getTop()}, {@link #getRight()},
@@ -153,6 +117,15 @@
return mTiles.size();
}
+ /**
+ * @return the bounding rect around any gaps in the tiles.
+ */
+ Rect getGaps() {
+ Region difference = new Region();
+ difference.op(mRegion.getBounds(), mRegion, Region.Op.DIFFERENCE);
+ return difference.getBounds();
+ }
+
ImageTile get(int i) {
return mTiles.get(i);
}
@@ -182,41 +155,40 @@
}
int getLeft() {
- return mBounds.left;
+ return mRegion.getBounds().left;
}
int getTop() {
- return mBounds.top;
+ return mRegion.getBounds().top;
}
int getRight() {
- return mBounds.right;
+ return mRegion.getBounds().right;
}
int getBottom() {
- return mBounds.bottom;
+ return mRegion.getBounds().bottom;
}
int getWidth() {
- return mBounds.width();
+ return mRegion.getBounds().width();
}
int getHeight() {
- return mBounds.height();
+ return mRegion.getBounds().height();
}
void clear() {
if (mTiles.isEmpty()) {
return;
}
- mBounds.setEmpty();
+ mRegion.setEmpty();
Iterator<ImageTile> i = mTiles.iterator();
while (i.hasNext()) {
ImageTile next = i.next();
next.close();
i.remove();
}
- notifyBoundsChanged(mBounds);
notifyContentChanged();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
index f571e41..07f6d36 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
@@ -228,8 +228,8 @@
});
// Immediately export to temp image file for saved state
- mCacheSaveFuture = mImageExporter.exportAsTempFile(mBackgroundExecutor,
- mLongScreenshot.toBitmap());
+ mCacheSaveFuture = mImageExporter.exportToRawFile(mBackgroundExecutor,
+ mLongScreenshot.toBitmap(), new File(getCacheDir(), "long_screenshot_cache.png"));
mCacheSaveFuture.addListener(() -> {
try {
// Get the temp file path to persist, used in onSavedInstanceState
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index 6690465..3c830cc 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -453,14 +453,6 @@
mCornerSizeX / (mOrientationPortrait ? bounds.width() : bounds.height());
final float currentScale = 1 / cornerScale;
- mScreenshotPreview.setScaleX(currentScale);
- mScreenshotPreview.setScaleY(currentScale);
-
- if (mAccessibilityManager.isEnabled()) {
- mDismissButton.setAlpha(0);
- mDismissButton.setVisibility(View.VISIBLE);
- }
-
AnimatorSet dropInAnimation = new AnimatorSet();
ValueAnimator flashInAnimator = ValueAnimator.ofFloat(0, 1);
flashInAnimator.setDuration(SCREENSHOT_FLASH_IN_DURATION_MS);
@@ -491,6 +483,20 @@
ValueAnimator toCorner = ValueAnimator.ofFloat(0, 1);
toCorner.setDuration(SCREENSHOT_TO_CORNER_Y_DURATION_MS);
+
+ toCorner.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mScreenshotPreview.setScaleX(currentScale);
+ mScreenshotPreview.setScaleY(currentScale);
+ mScreenshotPreview.setVisibility(View.VISIBLE);
+ if (mAccessibilityManager.isEnabled()) {
+ mDismissButton.setAlpha(0);
+ mDismissButton.setVisibility(View.VISIBLE);
+ }
+ }
+ });
+
float xPositionPct =
SCREENSHOT_TO_CORNER_X_DURATION_MS / (float) SCREENSHOT_TO_CORNER_Y_DURATION_MS;
float dismissPct =
@@ -534,13 +540,6 @@
}
});
- toCorner.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- mScreenshotPreview.setVisibility(View.VISIBLE);
- }
- });
-
mScreenshotFlash.setAlpha(0f);
mScreenshotFlash.setVisibility(View.VISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
index 94e3149..ce6e469 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
@@ -56,6 +56,7 @@
public class ScrollCaptureClient {
private static final int TILE_SIZE_PX_MAX = 4 * (1024 * 1024);
private static final int TILES_PER_PAGE = 2; // increase once b/174571735 is addressed
+ private static final int MAX_TILES = 30;
@VisibleForTesting
static final int MATCH_ANY_TASK = ActivityTaskManager.INVALID_TASK_ID;
@@ -83,11 +84,12 @@
int getMaxTiles();
/**
- * @return the maximum combined capture height for this session, in pixels.
+ * Target pixel height for acquisition this session. Session may yield more or less data
+ * than this, but acquiring this height is considered sufficient for completion.
+ *
+ * @return target height in pixels.
*/
- default int getMaxHeight() {
- return getMaxTiles() * getTileHeight();
- }
+ int getTargetHeight();
/**
* @return the height of each image tile
@@ -234,11 +236,11 @@
private final int mTileWidth;
private Rect mRequestRect;
private boolean mStarted;
+ private final int mTargetHeight;
private ICancellationSignal mCancellationSignal;
private final Rect mWindowBounds;
private final Rect mBoundsInWindow;
- private final int mMaxTiles;
private Completer<Session> mStartCompleter;
private Completer<CaptureResult> mTileRequestCompleter;
@@ -256,7 +258,7 @@
mTileWidth = mBoundsInWindow.width();
mTileHeight = pxPerTile / mBoundsInWindow.width();
- mMaxTiles = (int) Math.ceil(maxPages * TILES_PER_PAGE);
+ mTargetHeight = (int) (mBoundsInWindow.height() * maxPages);
if (DEBUG_SCROLL) {
Log.d(TAG, "boundsInWindow: " + mBoundsInWindow);
@@ -285,7 +287,7 @@
private void start(Completer<Session> completer) {
mReader = ImageReader.newInstance(mTileWidth, mTileHeight, PixelFormat.RGBA_8888,
- mMaxTiles, HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE);
+ MAX_TILES, HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE);
mStartCompleter = completer;
try {
mCancellationSignal = mConnection.startCapture(mReader.getSurface(), this);
@@ -410,8 +412,13 @@
}
@Override
+ public int getTargetHeight() {
+ return mTargetHeight;
+ }
+
+ @Override
public int getMaxTiles() {
- return mMaxTiles;
+ return MAX_TILES;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
index bbcfdbd..4c1f6a1 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
@@ -199,22 +199,20 @@
Log.d(TAG, "onCaptureResult: " + result + " scrolling " + (mScrollingUp ? "UP" : "DOWN")
+ " finish on boundary: " + mFinishOnBoundary);
boolean emptyResult = result.captured.height() == 0;
- boolean partialResult = !emptyResult
- && result.captured.height() < result.requested.height();
- boolean finish = false;
if (emptyResult) {
// Potentially reached a vertical boundary. Extend in the other direction.
if (mFinishOnBoundary) {
- Log.d(TAG, "Partial/empty: finished!");
- finish = true;
+ Log.d(TAG, "Empty: finished!");
+ finishCapture();
+ return;
} else {
// We hit a boundary, clear the tiles, capture everything in the opposite direction,
// then finish.
mImageTileSet.clear();
mFinishOnBoundary = true;
mScrollingUp = !mScrollingUp;
- Log.d(TAG, "Partial/empty: cleared, switch direction to finish");
+ Log.d(TAG, "Empty: cleared, switch direction to finish");
}
} else {
// Got a non-empty result, but may already have enough bitmap data now
@@ -223,12 +221,14 @@
Log.d(TAG, "Hit max tiles: finished");
// If we ever hit the max tiles, we've got enough bitmap data to finish
// (even if we weren't sure we'd finish on this pass).
- finish = true;
+ finishCapture();
+ return;
} else {
if (mScrollingUp && !mFinishOnBoundary) {
// During the initial scroll up, we only want to acquire the portion described
// by IDEAL_PORTION_ABOVE.
- if (expectedTiles >= mSession.getMaxTiles() * IDEAL_PORTION_ABOVE) {
+ if (mImageTileSet.getHeight() + result.captured.height()
+ >= mSession.getTargetHeight() * IDEAL_PORTION_ABOVE) {
Log.d(TAG, "Hit ideal portion above: clear and switch direction");
// We got enough above the start point, now see how far down it can go.
mImageTileSet.clear();
@@ -246,15 +246,15 @@
+ " - " + mImageTileSet.getRight() + "," + mImageTileSet.getBottom()
+ " (" + mImageTileSet.getWidth() + "x" + mImageTileSet.getHeight() + ")");
-
- // Stop when "too tall"
- if (mImageTileSet.getHeight() > MAX_HEIGHT) {
- Log.d(TAG, "Max height reached.");
- finish = true;
+ Rect gapBounds = mImageTileSet.getGaps();
+ if (!gapBounds.isEmpty()) {
+ Log.d(TAG, "Found gaps in tileset: " + gapBounds + ", requesting " + gapBounds.top);
+ requestNextTile(gapBounds.top);
+ return;
}
- if (finish) {
- Log.d(TAG, "Stop.");
+ if (mImageTileSet.getHeight() >= mSession.getTargetHeight()) {
+ Log.d(TAG, "Target height reached.");
finishCapture();
return;
}
@@ -268,8 +268,8 @@
: result.requested.bottom;
} else {
nextTop = (mScrollingUp)
- ? result.captured.top - mSession.getTileHeight()
- : result.captured.bottom;
+ ? mImageTileSet.getTop() - mSession.getTileHeight()
+ : mImageTileSet.getBottom();
}
requestNextTile(nextTop);
}
diff --git a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt
index 06c1c6f..a79316d 100644
--- a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt
@@ -32,6 +32,7 @@
import com.android.internal.app.AlertActivity
import com.android.internal.widget.DialogTitle
import com.android.systemui.R
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.statusbar.phone.KeyguardDismissUtil
import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController
import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -46,13 +47,15 @@
class SensorUseStartedActivity @Inject constructor(
private val sensorPrivacyController: IndividualSensorPrivacyController,
private val keyguardStateController: KeyguardStateController,
- private val keyguardDismissUtil: KeyguardDismissUtil
+ private val keyguardDismissUtil: KeyguardDismissUtil,
+ @Background private val bgHandler: Handler
) : AlertActivity(), DialogInterface.OnClickListener {
companion object {
private val LOG_TAG = SensorUseStartedActivity::class.java.simpleName
private const val SUPPRESS_REMINDERS_REMOVAL_DELAY_MILLIS = 2000L
+ private const val UNLOCK_DELAY_MILLIS = 200L
private const val CAMERA = SensorPrivacyManager.Sensors.CAMERA
private const val MICROPHONE = SensorPrivacyManager.Sensors.MICROPHONE
@@ -179,9 +182,12 @@
BUTTON_POSITIVE -> {
if (keyguardStateController.isMethodSecure && keyguardStateController.isShowing) {
keyguardDismissUtil.executeWhenUnlocked({
- disableSensorPrivacy()
+ bgHandler.postDelayed({
+ disableSensorPrivacy()
+ }, UNLOCK_DELAY_MILLIS)
+
false
- }, false, false)
+ }, false, true)
} else {
disableSensorPrivacy()
}
@@ -201,7 +207,7 @@
sensorPrivacyController
.suppressSensorPrivacyReminders(sensorUsePackageName, false)
} else {
- Handler(mainLooper).postDelayed({
+ bgHandler.postDelayed({
sensorPrivacyController
.suppressSensorPrivacyReminders(sensorUsePackageName, false)
}, SUPPRESS_REMINDERS_REMOVAL_DELAY_MILLIS)
@@ -218,7 +224,12 @@
}
private fun disableSensorPrivacy() {
- sensorPrivacyController.setSensorBlocked(sensor, false)
+ if (sensor == ALL_SENSORS) {
+ sensorPrivacyController.setSensorBlocked(MICROPHONE, false)
+ sensorPrivacyController.setSensorBlocked(CAMERA, false)
+ } else {
+ sensorPrivacyController.setSensorBlocked(sensor, false)
+ }
unsuppressImmediately = true
setResult(RESULT_OK)
}
diff --git a/packages/SystemUI/src/com/android/systemui/sensorprivacy/television/TvUnblockSensorActivity.java b/packages/SystemUI/src/com/android/systemui/sensorprivacy/television/TvUnblockSensorActivity.java
new file mode 100644
index 0000000..9d101ef
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/sensorprivacy/television/TvUnblockSensorActivity.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.sensorprivacy.television;
+
+import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
+import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE;
+
+import android.hardware.SensorPrivacyManager;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
+import com.android.systemui.tv.TvBottomSheetActivity;
+
+import javax.inject.Inject;
+
+/**
+ * Bottom sheet that is shown when the camera/mic sensors are blocked by the global toggle and
+ * allows the user to re-enable them.
+ */
+public class TvUnblockSensorActivity extends TvBottomSheetActivity {
+
+ private static final String TAG = TvUnblockSensorActivity.class.getSimpleName();
+
+ private static final int ALL_SENSORS = Integer.MAX_VALUE;
+ private int mSensor = -1;
+
+ private final IndividualSensorPrivacyController mSensorPrivacyController;
+ private IndividualSensorPrivacyController.Callback mSensorPrivacyCallback;
+
+ @Inject
+ public TvUnblockSensorActivity(
+ IndividualSensorPrivacyController individualSensorPrivacyController) {
+ mSensorPrivacyController = individualSensorPrivacyController;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ boolean allSensors = getIntent().getBooleanExtra(SensorPrivacyManager.EXTRA_ALL_SENSORS,
+ false);
+ if (allSensors) {
+ mSensor = ALL_SENSORS;
+ } else {
+ mSensor = getIntent().getIntExtra(SensorPrivacyManager.EXTRA_SENSOR, -1);
+ }
+
+ if (mSensor == -1) {
+ Log.v(TAG, "Invalid extras");
+ finish();
+ return;
+ }
+
+ mSensorPrivacyCallback = (sensor, blocked) -> {
+ if (mSensor == ALL_SENSORS) {
+ if (!mSensorPrivacyController.isSensorBlocked(CAMERA)
+ && !mSensorPrivacyController.isSensorBlocked(MICROPHONE)) {
+ finish();
+ }
+ } else if (this.mSensor == sensor && !blocked) {
+ finish();
+ }
+ };
+
+ initUI();
+ }
+
+ private void initUI() {
+ TextView title = findViewById(R.id.bottom_sheet_title);
+ TextView content = findViewById(R.id.bottom_sheet_body);
+ ImageView icon = findViewById(R.id.bottom_sheet_icon);
+ // mic icon if both icons are shown
+ ImageView secondIcon = findViewById(R.id.bottom_sheet_second_icon);
+ Button unblockButton = findViewById(R.id.bottom_sheet_positive_button);
+ Button cancelButton = findViewById(R.id.bottom_sheet_negative_button);
+
+ switch (mSensor) {
+ case MICROPHONE:
+ title.setText(R.string.sensor_privacy_start_use_mic_dialog_title);
+ content.setText(R.string.sensor_privacy_start_use_mic_dialog_content);
+ icon.setImageResource(com.android.internal.R.drawable.perm_group_microphone);
+ secondIcon.setVisibility(View.GONE);
+ break;
+ case CAMERA:
+ title.setText(R.string.sensor_privacy_start_use_camera_dialog_title);
+ content.setText(R.string.sensor_privacy_start_use_camera_dialog_content);
+ icon.setImageResource(com.android.internal.R.drawable.perm_group_camera);
+ secondIcon.setVisibility(View.GONE);
+ break;
+ case ALL_SENSORS:
+ default:
+ title.setText(R.string.sensor_privacy_start_use_mic_camera_dialog_title);
+ content.setText(R.string.sensor_privacy_start_use_mic_camera_dialog_content);
+ icon.setImageResource(com.android.internal.R.drawable.perm_group_camera);
+ secondIcon.setImageResource(com.android.internal.R.drawable.perm_group_microphone);
+ break;
+ }
+ unblockButton.setText(
+ com.android.internal.R.string.sensor_privacy_start_use_dialog_turn_on_button);
+ unblockButton.setOnClickListener(v -> {
+ if (mSensor == ALL_SENSORS) {
+ mSensorPrivacyController.setSensorBlocked(CAMERA, false);
+ mSensorPrivacyController.setSensorBlocked(MICROPHONE, false);
+ } else {
+ mSensorPrivacyController.setSensorBlocked(mSensor, false);
+ }
+ });
+
+ cancelButton.setText(android.R.string.cancel);
+ cancelButton.setOnClickListener(v -> finish());
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mSensorPrivacyController.addCallback(mSensorPrivacyCallback);
+ }
+
+ @Override
+ public void onPause() {
+ mSensorPrivacyController.removeCallback(mSensorPrivacyCallback);
+ super.onPause();
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
index ce796d9..89dda9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
@@ -22,6 +22,7 @@
import android.content.res.Resources
import android.util.IndentingPrintWriter
import android.util.MathUtils
+import android.view.CrossWindowBlurListeners
import android.view.SurfaceControl
import android.view.ViewRootImpl
import androidx.annotation.VisibleForTesting
@@ -37,6 +38,7 @@
@SysUISingleton
open class BlurUtils @Inject constructor(
@Main private val resources: Resources,
+ private val crossWindowBlurListeners: CrossWindowBlurListeners,
dumpManager: DumpManager
) : Dumpable {
val minBlurRadius = resources.getDimensionPixelSize(R.dimen.min_window_blur_radius)
@@ -97,7 +99,8 @@
* @return {@code true} when supported.
*/
open fun supportsBlursOnWindows(): Boolean {
- return CROSS_WINDOW_BLUR_SUPPORTED && ActivityManager.isHighEndGfx()
+ return CROSS_WINDOW_BLUR_SUPPORTED && ActivityManager.isHighEndGfx() &&
+ crossWindowBlurListeners.isCrossWindowBlurEnabled()
}
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index 4a4e990..6f4a73e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -18,6 +18,7 @@
import com.android.systemui.Gefingerpoken
import com.android.systemui.R
import com.android.systemui.animation.Interpolators
+import com.android.systemui.biometrics.UdfpsKeyguardViewController
import com.android.systemui.classifier.Classifier
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.dagger.SysUISingleton
@@ -109,6 +110,11 @@
private var nextHideKeyguardNeedsNoAnimation = false
/**
+ * The udfpsKeyguardViewController if it exists.
+ */
+ var udfpsKeyguardViewController: UdfpsKeyguardViewController? = null
+
+ /**
* The touch helper responsible for the drag down animation.
*/
val touchHelper = DragDownHelper(falsingManager, falsingCollector, this, context)
@@ -291,6 +297,7 @@
// Fade out all content only visible on the lockscreen
notificationPanelController.setKeyguardOnlyContentAlpha(1.0f - scrimProgress)
depthController.transitionToFullShadeProgress = scrimProgress
+ udfpsKeyguardViewController?.setTransitionToFullShadeProgress(scrimProgress)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index 8900551..f03a9a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -96,6 +96,15 @@
var globalActionsSpring = DepthAnimation()
var showingHomeControls: Boolean = false
+ @VisibleForTesting
+ var brightnessMirrorSpring = DepthAnimation()
+ var brightnessMirrorVisible: Boolean = false
+ set(value) {
+ field = value
+ brightnessMirrorSpring.animateTo(if (value) blurUtils.blurRadiusOfRatio(1f)
+ else 0)
+ }
+
var qsPanelExpansion = 0f
set(value) {
if (field == value) return
@@ -186,13 +195,16 @@
var blur = max(shadeRadius.toInt(), globalActionsRadius)
// Make blur be 0 if it is necessary to stop blur effect.
- if (scrimsVisible) {
+ if (scrimsVisible || !blurUtils.supportsBlursOnWindows()) {
blur = 0
}
+ val zoomOut = blurUtils.ratioOfBlurRadius(blur)
+
+ // Brightness slider removes blur, but doesn't affect zooms
+ blur = (blur * (1f - brightnessMirrorSpring.ratio)).toInt()
val opaque = scrimsVisible && !ignoreShadeBlurUntilHidden
blurUtils.applyBlur(blurRoot?.viewRootImpl ?: root.viewRootImpl, blur, opaque)
- val zoomOut = blurUtils.ratioOfBlurRadius(blur)
try {
if (root.isAttachedToWindow && root.windowToken != null) {
wallpaperManager.setWallpaperZoomOut(root.windowToken, zoomOut)
@@ -260,6 +272,7 @@
shadeSpring.finishIfRunning()
shadeAnimation.finishIfRunning()
globalActionsSpring.finishIfRunning()
+ brightnessMirrorSpring.finishIfRunning()
}
}
@@ -425,6 +438,7 @@
it.println("shadeRadius: ${shadeSpring.radius}")
it.println("shadeAnimation: ${shadeAnimation.radius}")
it.println("globalActionsRadius: ${globalActionsSpring.radius}")
+ it.println("brightnessMirrorRadius: ${brightnessMirrorSpring.radius}")
it.println("wakeAndUnlockBlur: $wakeAndUnlockBlurRadius")
it.println("ignoreShadeBlurUntilHidden: $ignoreShadeBlurUntilHidden")
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ExpandAnimationParameters.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ExpandAnimationParameters.kt
index f1479a1..f19cf5d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ExpandAnimationParameters.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ExpandAnimationParameters.kt
@@ -22,11 +22,27 @@
)
var startTranslationZ = 0f
+
+ /**
+ * The top position of the notification at the start of the animation. This is needed in order
+ * to keep the notification at its place when launching a notification that is clipped rounded.
+ */
+ var startNotificationTop = 0f
var startClipTopAmount = 0
var parentStartClipTopAmount = 0
var progress = 0f
var linearProgress = 0f
+ /**
+ * The rounded top clipping at the beginning.
+ */
+ var startRoundedTopClipping = 0
+
+ /**
+ * The rounded top clipping of the parent notification at the start.
+ */
+ var parentStartRoundedTopClipping = 0
+
override val topChange: Int
get() {
// We need this compensation to ensure that the QS moves in sync.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
index c248670..1bbef25 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
@@ -40,6 +40,11 @@
private val headsUpManager: HeadsUpManagerPhone,
private val notification: ExpandableNotificationRow
) : ActivityLaunchAnimator.Controller {
+
+ companion object {
+ const val ANIMATION_DURATION_TOP_ROUNDING = 100L
+ }
+
private val notificationEntry = notification.entry
private val notificationKey = notificationEntry.sbn.key
@@ -54,18 +59,37 @@
val height = max(0, notification.actualHeight - notification.clipBottomAmount)
val location = notification.locationOnScreen
+ val clipStartLocation = notificationListContainer.getTopClippingStartLocation()
+ val roundedTopClipping = Math.max(clipStartLocation - location[1], 0)
+ val windowTop = location[1] + roundedTopClipping
+ val topCornerRadius = if (roundedTopClipping > 0) {
+ // Because the rounded Rect clipping is complex, we start the top rounding at
+ // 0, which is pretty close to matching the real clipping.
+ // We'd have to clipOut the overlaid drawable too with the outer rounded rect in case
+ // if we'd like to have this perfect, but this is close enough.
+ 0f
+ } else {
+ notification.currentBackgroundRadiusTop
+ }
val params = ExpandAnimationParameters(
- top = location[1],
+ top = windowTop,
bottom = location[1] + height,
left = location[0],
right = location[0] + notification.width,
- topCornerRadius = notification.currentBackgroundRadiusTop,
+ topCornerRadius = topCornerRadius,
bottomCornerRadius = notification.currentBackgroundRadiusBottom
)
params.startTranslationZ = notification.translationZ
+ params.startNotificationTop = notification.translationY
+ params.startRoundedTopClipping = roundedTopClipping
params.startClipTopAmount = notification.clipTopAmount
if (notification.isChildInGroup) {
+ params.startNotificationTop += notification.notificationParent.translationY
+ val parentRoundedClip = Math.max(clipStartLocation
+ - notification.notificationParent.locationOnScreen[1], 0)
+ params.parentStartRoundedTopClipping = parentRoundedClip
+
val parentClip = notification.notificationParent.clipTopAmount
params.parentStartClipTopAmount = parentClip
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 9d56e9b..93166f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -35,6 +35,7 @@
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.graphics.Canvas;
import android.graphics.Path;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.AnimationDrawable;
@@ -85,6 +86,7 @@
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
import com.android.systemui.statusbar.notification.ExpandAnimationParameters;
+import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorController;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
@@ -133,7 +135,7 @@
private boolean mUpdateBackgroundOnUpdate;
private boolean mNotificationTranslationFinished = false;
- private ArrayList<MenuItem> mSnoozedMenuItems;
+ private boolean mIsSnoozed;
/**
* Listener for when {@link ExpandableNotificationRow} is laid out.
@@ -252,6 +254,7 @@
private OnExpandClickListener mOnExpandClickListener;
private View.OnClickListener mOnAppClickListener;
private View.OnClickListener mOnFeedbackClickListener;
+ private Path mExpandingClipPath;
// Listener will be called when receiving a long click event.
// Use #setLongPressPosition to optionally assign positional data with the long press.
@@ -836,6 +839,7 @@
public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {
if (mExpandAnimationRunning && !isChildInGroup && mNotificationParent != null) {
mNotificationParent.setChildIsExpanding(false);
+ mNotificationParent.setExpandingClipPath(null);
mNotificationParent.setExtraWidthForClipping(0.0f);
mNotificationParent.setMinimumHeightForClipping(0);
}
@@ -1105,8 +1109,7 @@
false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
false /* resetMenu */);
mNotificationGutsManager.openGuts(this, 0, 0, item);
- mSnoozedMenuItems = mMenuRow.getMenuItems(mMenuRow.getMenuView().getContext());
- mMenuRow.resetMenu();
+ mIsSnoozed = true;
};
}
@@ -1821,10 +1824,7 @@
void onGutsClosed() {
updateContentAccessibilityImportanceForGuts(true /* isEnabled */);
- if (mSnoozedMenuItems != null && mSnoozedMenuItems.size() > 0) {
- mMenuRow.setMenuItems(mSnoozedMenuItems);
- mSnoozedMenuItems = null;
- }
+ mIsSnoozed = false;
}
/**
@@ -2036,7 +2036,22 @@
setTranslationZ(translationZ);
float extraWidthForClipping = params.getWidth() - getWidth();
setExtraWidthForClipping(extraWidthForClipping);
- int top = params.getTop();
+ int top;
+ if (params.getStartRoundedTopClipping() > 0) {
+ // If we were clipping initially, let's interpolate from the start position to the
+ // top. Otherwise, we just take the top directly.
+ float expandProgress = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(
+ params.getProgress(0,
+ NotificationLaunchAnimatorController.ANIMATION_DURATION_TOP_ROUNDING));
+ float startTop = params.getStartNotificationTop();
+ top = (int) Math.min(MathUtils.lerp(startTop,
+ params.getTop(), expandProgress),
+ startTop);
+ } else {
+ top = params.getTop();
+ }
+ int actualHeight = params.getBottom() - top;
+ setActualHeight(actualHeight);
int startClipTopAmount = params.getStartClipTopAmount();
int clipTopAmount = (int) MathUtils.lerp(startClipTopAmount, 0, params.getProgress());
if (mNotificationParent != null) {
@@ -2065,13 +2080,12 @@
setClipTopAmount(clipTopAmount);
}
setTranslationY(top);
- setActualHeight(params.getHeight());
mTopRoundnessDuringExpandAnimation = params.getTopCornerRadius() / mOutlineRadius;
mBottomRoundnessDuringExpandAnimation = params.getBottomCornerRadius() / mOutlineRadius;
invalidateOutline();
- mBackgroundNormal.setExpandAnimationParams(params);
+ mBackgroundNormal.setExpandAnimationSize(params.getWidth(), actualHeight);
}
public void setExpandAnimationRunning(boolean expandAnimationRunning) {
@@ -2468,7 +2482,8 @@
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
int intrinsicBefore = getIntrinsicHeight();
super.onLayout(changed, left, top, right, bottom);
- if (intrinsicBefore != getIntrinsicHeight() && intrinsicBefore != 0) {
+ if (intrinsicBefore != getIntrinsicHeight()
+ && (intrinsicBefore != 0 || getActualHeight() > 0)) {
notifyHeightChanged(true /* needsAnimation */);
}
if (mMenuRow != null && mMenuRow.getMenuView() != null) {
@@ -2981,7 +2996,7 @@
public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfoInternal(info);
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK);
- if (canViewBeDismissed()) {
+ if (canViewBeDismissed() && !mIsSnoozed) {
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
}
boolean expandable = shouldShowPublic();
@@ -2997,7 +3012,7 @@
isExpanded = isExpanded();
}
}
- if (expandable) {
+ if (expandable && !mIsSnoozed) {
if (isExpanded) {
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE);
} else {
@@ -3085,6 +3100,26 @@
return super.childNeedsClipping(child);
}
+ /**
+ * Set a clip path to be set while expanding the notification. This is needed to nicely
+ * clip ourselves during the launch if we were clipped rounded in the beginning
+ */
+ public void setExpandingClipPath(Path path) {
+ mExpandingClipPath = path;
+ invalidate();
+ }
+
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ canvas.save();
+ if (mExpandingClipPath != null && (mExpandAnimationRunning || mChildIsExpanding)) {
+ // If we're launching a notification, let's clip if a clip rounded to the clipPath
+ canvas.clipPath(mExpandingClipPath);
+ }
+ super.dispatchDraw(canvas);
+ canvas.restore();
+ }
+
@Override
protected void applyRoundness() {
super.applyRoundness();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
index 754de58..0f615aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
@@ -240,10 +240,10 @@
invalidate();
}
- /** Set the current expand animation parameters. */
- public void setExpandAnimationParams(ExpandAnimationParameters params) {
- mActualHeight = params.getHeight();
- mActualWidth = params.getWidth();
+ /** Set the current expand animation size. */
+ public void setExpandAnimationSize(int actualWidth, int actualHeight) {
+ mActualHeight = actualHeight;
+ mActualWidth = actualWidth;
invalidate();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index 26606cd..197920f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -72,8 +72,6 @@
private boolean mUnlockHintRunning;
private boolean mQsCustomizerShowing;
private int mIntrinsicPadding;
- private int mExpandAnimationTopChange;
- private ExpandableNotificationRow mExpandingNotification;
private float mHideAmount;
private boolean mAppearing;
private float mPulseHeight = MAX_PULSE_HEIGHT;
@@ -518,22 +516,6 @@
return isDozing() && !isPulsing(row.getEntry());
}
- public void setExpandAnimationTopChange(int expandAnimationTopChange) {
- mExpandAnimationTopChange = expandAnimationTopChange;
- }
-
- public void setExpandingNotification(ExpandableNotificationRow row) {
- mExpandingNotification = row;
- }
-
- public ExpandableNotificationRow getExpandingNotification() {
- return mExpandingNotification;
- }
-
- public int getExpandAnimationTopChange() {
- return mExpandAnimationTopChange;
- }
-
/**
* @return {@code true } when shade is completely hidden: in AOD, ambient display or when
* bypassing.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
index 2a2e733f7..7a5c188 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
@@ -200,4 +200,11 @@
default void setWillExpand(boolean willExpand) {}
void setNotificationActivityStarter(NotificationActivityStarter notificationActivityStarter);
+
+ /**
+ * @return the start location where we start clipping notifications.
+ */
+ default int getTopClippingStartLocation() {
+ return 0;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 9ba04bf..4e6d376 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -77,6 +77,7 @@
import com.android.systemui.Dumpable;
import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
+import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.statusbar.CommandQueue;
@@ -90,6 +91,7 @@
import com.android.systemui.statusbar.notification.ExpandAnimationParameters;
import com.android.systemui.statusbar.notification.FakeShadowView;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
+import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorController;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.ShadeViewRefactor;
import com.android.systemui.statusbar.notification.ShadeViewRefactor.RefactorComponent;
@@ -139,6 +141,9 @@
// adb shell setprop persist.debug.nssl true && adb reboot
private static final boolean DEBUG = SystemProperties.getBoolean("persist.debug.nssl",
false /* default */);
+ // TODO(b/187291379) disable again before release
+ private static final boolean DEBUG_REMOVE_ANIMATION = SystemProperties.getBoolean(
+ "persist.debug.nssl.dismiss", true /* default */);
private static final float RUBBER_BAND_FACTOR_NORMAL = 0.35f;
private static final float RUBBER_BAND_FACTOR_AFTER_EXPAND = 0.15f;
@@ -471,6 +476,12 @@
private final Path mRoundedClipPath = new Path();
/**
+ * The clip Path used to clip the launching notification. This may be different
+ * from the normal path, as the views launch animation could start clipped.
+ */
+ private final Path mLaunchedNotificationClipPath = new Path();
+
+ /**
* Should we use rounded rect clipping right now
*/
private boolean mShouldUseRoundedRectClipping = false;
@@ -493,6 +504,26 @@
private boolean mLaunchingNotification;
/**
+ * Does the launching notification need to be clipped
+ */
+ private boolean mLaunchingNotificationNeedsToBeClipped;
+
+ /**
+ * The current launch animation params when launching a notification
+ */
+ private ExpandAnimationParameters mLaunchAnimationParams;
+
+ /**
+ * Corner radii of the launched notification if it's clipped
+ */
+ private float[] mLaunchedNotificationRadii = new float[8];
+
+ /**
+ * The notification that is being launched currently.
+ */
+ private ExpandableNotificationRow mExpandingNotificationRow;
+
+ /**
* Do notifications dismiss with normal transitioning
*/
private boolean mDismissUsingRowTranslationX = true;
@@ -2647,7 +2678,17 @@
*/
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
boolean generateRemoveAnimation(ExpandableView child) {
+ String key = "";
+ if (DEBUG_REMOVE_ANIMATION) {
+ if (child instanceof ExpandableNotificationRow) {
+ key = ((ExpandableNotificationRow) child).getEntry().getKey();
+ }
+ Log.d(TAG, "generateRemoveAnimation " + key);
+ }
if (removeRemovedChildFromHeadsUpChangeAnimations(child)) {
+ if (DEBUG_REMOVE_ANIMATION) {
+ Log.d(TAG, "removedBecauseOfHeadsUp " + key);
+ }
mAddedHeadsUpChildren.remove(child);
return false;
}
@@ -2656,8 +2697,17 @@
mClearTransientViewsWhenFinished.add(child);
return true;
}
+ if (DEBUG_REMOVE_ANIMATION) {
+ Log.d(TAG, "generateRemove " + key
+ + "\nmIsExpanded " + mIsExpanded
+ + "\nmAnimationsEnabled " + mAnimationsEnabled
+ + "\n!invisible group " + !isChildInInvisibleGroup(child));
+ }
if (mIsExpanded && mAnimationsEnabled && !isChildInInvisibleGroup(child)) {
if (!mChildrenToAddAnimated.contains(child)) {
+ if (DEBUG_REMOVE_ANIMATION) {
+ Log.d(TAG, "needsAnimation = true " + key);
+ }
// Generate Animations
mChildrenToRemoveAnimated.add(child);
mNeedsAnimation = true;
@@ -2679,7 +2729,7 @@
/**
* Remove a removed child view from the heads up animations if it was just added there
*
- * @return whether any child was removed from the list to animate
+ * @return whether any child was removed from the list to animate and the view was just added
*/
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private boolean removeRemovedChildFromHeadsUpChangeAnimations(View child) {
@@ -2698,7 +2748,7 @@
((ExpandableNotificationRow) child).setHeadsUpAnimatingAway(false);
}
mTmpList.clear();
- return hasAddEvent;
+ return hasAddEvent && mAddedHeadsUpChildren.contains(child);
}
// TODO (b/162832756): remove since this won't happen in new pipeline (we prune groups in
@@ -2749,6 +2799,9 @@
* @return the amount of scrolling needed to start clipping notifications.
*/
private int getScrollAmountToScrollBoundary() {
+ if (mShouldUseSplitNotificationShade) {
+ return mSidePaddings;
+ }
return mTopPadding - mQsScrollBoundaryPosition;
}
@@ -2892,7 +2945,16 @@
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
void setExpandingNotification(ExpandableNotificationRow row) {
- mAmbientState.setExpandingNotification(row);
+ if (mExpandingNotificationRow != null && row == null) {
+ // Let's unset the clip path being set during launch
+ mExpandingNotificationRow.setExpandingClipPath(null);
+ ExpandableNotificationRow parent = mExpandingNotificationRow.getNotificationParent();
+ if (parent != null) {
+ parent.setExpandingClipPath(null);
+ }
+ }
+ mExpandingNotificationRow = row;
+ updateLaunchedNotificationClipPath();
requestChildrenUpdate();
}
@@ -2902,10 +2964,10 @@
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void applyExpandAnimationParams(ExpandAnimationParameters params) {
- mAmbientState.setExpandAnimationTopChange(params == null ? 0 : params.getTopChange());
-
- // Disable clipping for launches
+ // Modify the clipping for launching notifications
+ mLaunchAnimationParams = params;
setLaunchingNotification(params != null);
+ updateLaunchedNotificationClipPath();
requestChildrenUpdate();
}
@@ -5353,7 +5415,15 @@
return;
}
mLaunchingNotification = launching;
- updateUseRoundedRectClipping();
+ mLaunchingNotificationNeedsToBeClipped = mLaunchAnimationParams != null
+ && (mLaunchAnimationParams.getStartRoundedTopClipping() > 0
+ || mLaunchAnimationParams.getParentStartRoundedTopClipping() > 0);
+ if (!mLaunchingNotificationNeedsToBeClipped || !mLaunchingNotification) {
+ mLaunchedNotificationClipPath.reset();
+ }
+ // When launching notifications, we're clipping the children individually instead of in
+ // dispatchDraw
+ invalidate();
}
/**
@@ -5363,22 +5433,97 @@
// We don't want to clip notifications when QS is expanded, because incoming heads up on
// the bottom would be clipped otherwise
boolean qsAllowsClipping = mQsExpansionFraction < 0.5f || mShouldUseSplitNotificationShade;
- boolean clip = !mLaunchingNotification && mIsExpanded && qsAllowsClipping;
+ boolean clip = mIsExpanded && qsAllowsClipping;
if (clip != mShouldUseRoundedRectClipping) {
mShouldUseRoundedRectClipping = clip;
invalidate();
}
}
+ /**
+ * Update the clip path for launched notifications in case they were originally clipped
+ */
+ private void updateLaunchedNotificationClipPath() {
+ if (!mLaunchingNotificationNeedsToBeClipped || !mLaunchingNotification
+ || mExpandingNotificationRow == null) {
+ return;
+ }
+ int left = Math.min(mLaunchAnimationParams.getLeft(), mRoundedRectClippingLeft);
+ int right = Math.max(mLaunchAnimationParams.getRight(), mRoundedRectClippingRight);
+ int bottom = Math.max(mLaunchAnimationParams.getBottom(), mRoundedRectClippingBottom);
+ float expandProgress = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(
+ mLaunchAnimationParams.getProgress(0,
+ NotificationLaunchAnimatorController.ANIMATION_DURATION_TOP_ROUNDING));
+ int top = (int) Math.min(MathUtils.lerp(mRoundedRectClippingTop,
+ mLaunchAnimationParams.getTop(), expandProgress),
+ mRoundedRectClippingTop);
+ float topRadius = mLaunchAnimationParams.getTopCornerRadius();
+ float bottomRadius = mLaunchAnimationParams.getBottomCornerRadius();
+ mLaunchedNotificationRadii[0] = topRadius;
+ mLaunchedNotificationRadii[1] = topRadius;
+ mLaunchedNotificationRadii[2] = topRadius;
+ mLaunchedNotificationRadii[3] = topRadius;
+ mLaunchedNotificationRadii[4] = bottomRadius;
+ mLaunchedNotificationRadii[5] = bottomRadius;
+ mLaunchedNotificationRadii[6] = bottomRadius;
+ mLaunchedNotificationRadii[7] = bottomRadius;
+ mLaunchedNotificationClipPath.reset();
+ mLaunchedNotificationClipPath.addRoundRect(left, top, right, bottom,
+ mLaunchedNotificationRadii, Path.Direction.CW);
+ // Offset into notification clip coordinates instead of parent ones.
+ // This is needed since the notification changes in translationZ, where clipping via
+ // canvas dispatching won't work.
+ ExpandableNotificationRow expandingRow = mExpandingNotificationRow;
+ if (expandingRow.getNotificationParent() != null) {
+ expandingRow = expandingRow.getNotificationParent();
+ }
+ mLaunchedNotificationClipPath.offset(
+ -expandingRow.getLeft() - expandingRow.getTranslationX(),
+ -expandingRow.getTop() - expandingRow.getTranslationY());
+ expandingRow.setExpandingClipPath(mLaunchedNotificationClipPath);
+ if (mShouldUseRoundedRectClipping) {
+ invalidate();
+ }
+ }
+
@Override
protected void dispatchDraw(Canvas canvas) {
- if (mShouldUseRoundedRectClipping) {
+ if (mShouldUseRoundedRectClipping && !mLaunchingNotification) {
+ // When launching notifications, we're clipping the children individually instead of in
+ // dispatchDraw
// Let's clip rounded.
canvas.clipPath(mRoundedClipPath);
}
super.dispatchDraw(canvas);
}
+ @Override
+ protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
+ if (mShouldUseRoundedRectClipping && mLaunchingNotification) {
+ // Let's clip children individually during notification launch
+ canvas.save();
+ ExpandableView expandableView = (ExpandableView) child;
+ Path clipPath;
+ if (expandableView.isExpandAnimationRunning()
+ || ((ExpandableView) child).hasExpandingChild()) {
+ // When launching the notification, it is not clipped by this layout, but by the
+ // view itself. This is because the view is Translating in Z, where this clipPath
+ // wouldn't apply.
+ clipPath = null;
+ } else {
+ clipPath = mRoundedClipPath;
+ }
+ if (clipPath != null) {
+ canvas.clipPath(clipPath);
+ }
+ boolean result = super.drawChild(canvas, child, drawingTime);
+ canvas.restore();
+ return result;
+ } else {
+ return super.drawChild(canvas, child, drawingTime);
+ }
+ }
+
/**
* Calculate the total translation needed when dismissing.
*/
@@ -5393,6 +5538,13 @@
}
/**
+ * @return the start location where we start clipping notifications.
+ */
+ public int getTopClippingStartLocation() {
+ return mIsExpanded ? mQsScrollBoundaryPosition : 0;
+ }
+
+ /**
* A listener that is notified when the empty space below the notifications is clicked on
*/
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 495eda7..e71f7db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -1533,6 +1533,11 @@
}
@Override
+ public int getTopClippingStartLocation() {
+ return mView.getTopClippingStartLocation();
+ }
+
+ @Override
public View getContainerChildAt(int i) {
return mView.getContainerChildAt(i);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
index 54ef623..b148eeb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
@@ -27,6 +27,7 @@
private val listeners: MutableList<ConfigurationController.ConfigurationListener> = ArrayList()
private val lastConfig = Configuration()
private var density: Int = 0
+ private var smallestScreenWidth: Int = 0
private var fontScale: Float = 0.toFloat()
private val inCarMode: Boolean
private var uiMode: Int = 0
@@ -38,6 +39,7 @@
this.context = context
fontScale = currentConfig.fontScale
density = currentConfig.densityDpi
+ smallestScreenWidth = currentConfig.smallestScreenWidthDp
inCarMode = currentConfig.uiMode and Configuration.UI_MODE_TYPE_MASK ==
Configuration.UI_MODE_TYPE_CAR
uiMode = currentConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK
@@ -72,6 +74,14 @@
this.fontScale = fontScale
}
+ val smallestScreenWidth = newConfig.smallestScreenWidthDp
+ if (smallestScreenWidth != this.smallestScreenWidth) {
+ this.smallestScreenWidth = smallestScreenWidth
+ listeners.filterForEach({ this.listeners.contains(it) }) {
+ it.onSmallestScreenWidthChanged()
+ }
+ }
+
val localeList = newConfig.locales
if (localeList != this.localeList) {
this.localeList = localeList
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 f461d94..5d31786 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -36,9 +36,11 @@
import android.app.ActivityManager;
import android.app.Fragment;
import android.app.StatusBarManager;
+import android.content.ContentResolver;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.database.ContentObserver;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
@@ -50,10 +52,12 @@
import android.graphics.drawable.Drawable;
import android.hardware.biometrics.BiometricSourceType;
import android.os.Bundle;
+import android.os.Handler;
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.UserManager;
import android.os.VibrationEffect;
+import android.provider.Settings;
import android.util.Log;
import android.util.MathUtils;
import android.view.LayoutInflater;
@@ -210,6 +214,8 @@
new MyOnHeadsUpChangedListener();
private final HeightListener mHeightListener = new HeightListener();
private final ConfigurationListener mConfigurationListener = new ConfigurationListener();
+ private final SettingsChangeObserver mSettingsChangeObserver;
+
@VisibleForTesting final StatusBarStateListener mStatusBarStateListener =
new StatusBarStateListener();
private final BiometricUnlockController mBiometricUnlockController;
@@ -594,6 +600,8 @@
private int mScreenCornerRadius;
private boolean mQSAnimatingHiddenFromCollapsed;
+ private final ContentResolver mContentResolver;
+
private final Executor mUiExecutor;
private final SecureSettings mSecureSettings;
@@ -635,6 +643,7 @@
@Inject
public NotificationPanelViewController(NotificationPanelView view,
@Main Resources resources,
+ @Main Handler handler,
LayoutInflater layoutInflater,
NotificationWakeUpCoordinator coordinator, PulseExpansionHandler pulseExpansionHandler,
DynamicPrivacyController dynamicPrivacyController,
@@ -678,6 +687,7 @@
TapAgainViewController tapAgainViewController,
NavigationModeController navigationModeController,
FragmentService fragmentService,
+ ContentResolver contentResolver,
QuickAccessWalletController quickAccessWalletController,
@Main Executor uiExecutor,
SecureSettings secureSettings,
@@ -704,15 +714,12 @@
mKeyguardStatusBarViewComponentFactory = keyguardStatusBarViewComponentFactory;
mDepthController = notificationShadeDepthController;
mFeatureFlags = featureFlags;
+ mContentResolver = contentResolver;
mKeyguardQsUserSwitchComponentFactory = keyguardQsUserSwitchComponentFactory;
mKeyguardUserSwitcherComponentFactory = keyguardUserSwitcherComponentFactory;
mQSDetailDisplayer = qsDetailDisplayer;
mFragmentService = fragmentService;
- mKeyguardUserSwitcherEnabled = mResources.getBoolean(
- com.android.internal.R.bool.config_keyguardUserSwitcher);
- mKeyguardQsUserSwitchEnabled =
- mKeyguardUserSwitcherEnabled && mResources.getBoolean(
- R.bool.config_keyguard_user_switch_opens_qs_details);
+ mSettingsChangeObserver = new SettingsChangeObserver(handler);
mShouldUseSplitNotificationShade =
Utils.shouldUseSplitNotificationShade(mFeatureFlags, mResources);
mView.setWillNotDraw(!DEBUG);
@@ -795,6 +802,7 @@
}
mMaxKeyguardNotifications = resources.getInteger(R.integer.keyguard_max_notification_count);
+ updateUserSwitcherFlags();
onFinishInflate();
}
@@ -1034,6 +1042,10 @@
view = mLayoutInflater.inflate(layoutId, mView, false);
mView.addView(view, index);
} else {
+ // Add the stub back so we can re-inflate it again if necessary
+ ViewStub stub = new ViewStub(mView.getContext(), layoutId);
+ stub.setId(stubId);
+ mView.addView(stub, index);
view = null;
}
} else if (enabled) {
@@ -1061,6 +1073,7 @@
updateResources();
// Re-inflate the keyguard user switcher group.
+ updateUserSwitcherFlags();
boolean isUserSwitcherEnabled = mUserManager.isUserSwitcherEnabled();
boolean showQsUserSwitch = mKeyguardQsUserSwitchEnabled && isUserSwitcherEnabled;
boolean showKeyguardUserSwitcher =
@@ -1443,7 +1456,6 @@
private void setQsExpansionEnabled() {
mQsExpansionEnabled = mQsExpansionEnabledPolicy && mQsExpansionEnabledAmbient;
- Log.d(TAG, "Set qsExpansionEnabled: " + mQsExpansionEnabled);
if (mQs == null) return;
mQs.setHeaderClickable(mQsExpansionEnabled);
}
@@ -3874,6 +3886,26 @@
return false;
}
+ private void updateUserSwitcherFlags() {
+ mKeyguardUserSwitcherEnabled = mResources.getBoolean(
+ com.android.internal.R.bool.config_keyguardUserSwitcher);
+ mKeyguardQsUserSwitchEnabled =
+ mKeyguardUserSwitcherEnabled && mResources.getBoolean(
+ R.bool.config_keyguard_user_switch_opens_qs_details);
+ }
+
+ private void registerSettingsChangeListener() {
+ mContentResolver.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.USER_SWITCHER_ENABLED),
+ /* notifyForDescendants */ false,
+ mSettingsChangeObserver
+ );
+ }
+
+ private void unregisterSettingsChangeListener() {
+ mContentResolver.unregisterContentObserver(mSettingsChangeObserver);
+ }
+
private class OnHeightChangedListener implements ExpandableView.OnHeightChangedListener {
@Override
public void onHeightChanged(ExpandableView view, boolean needsAnimation) {
@@ -4195,6 +4227,15 @@
}
@Override
+ public void onSmallestScreenWidthChanged() {
+ if (DEBUG) Log.d(TAG, "onSmallestScreenWidthChanged");
+
+ // Can affect multi-user switcher visibility as it depends on screen size by default:
+ // it is enabled only for devices with large screens (see config_keyguardUserSwitcher)
+ reInflateViews();
+ }
+
+ @Override
public void onOverlayChanged() {
if (DEBUG) Log.d(TAG, "onOverlayChanged");
reInflateViews();
@@ -4207,6 +4248,21 @@
}
}
+ private class SettingsChangeObserver extends ContentObserver {
+
+ SettingsChangeObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ if (DEBUG) Log.d(TAG, "onSettingsChanged");
+
+ // Can affect multi-user switcher visibility
+ reInflateViews();
+ }
+ }
+
private class StatusBarStateListener implements StateListener {
@Override
public void onStateChanged(int statusBarState) {
@@ -4322,10 +4378,12 @@
mConfigurationListener.onThemeChanged();
mFalsingManager.addTapListener(mFalsingTapListener);
mKeyguardIndicationController.init();
+ registerSettingsChangeListener();
}
@Override
public void onViewDetachedFromWindow(View v) {
+ unregisterSettingsChangeListener();
mFragmentService.getFragmentHostManager(mView)
.removeTagListener(QS.TAG, mFragmentListener);
mStatusBarStateController.removeCallback(mStatusBarStateListener);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
index 1cb0be0..ed8fb31 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -47,6 +47,8 @@
private View mKeyguardStatusBar;
private boolean mQsExpanded;
private boolean mCustomizerAnimating;
+ private boolean mCustomizing;
+ private boolean mDetailShowing;
private int mBottomPadding;
private int mStackScrollerMargin;
@@ -140,7 +142,18 @@
}
public void setCustomizerShowing(boolean isShowing) {
- if (isShowing) {
+ mCustomizing = isShowing;
+ updateBottomMargin();
+ mStackScroller.setQsCustomizerShowing(isShowing);
+ }
+
+ public void setDetailShowing(boolean isShowing) {
+ mDetailShowing = isShowing;
+ updateBottomMargin();
+ }
+
+ private void updateBottomMargin() {
+ if (mCustomizing || mDetailShowing) {
// Clear out bottom paddings/margins so the qs customization can be full height.
setPadding(0, 0, 0, 0);
setBottomMargin(mStackScroller, 0);
@@ -148,7 +161,6 @@
setPadding(0, 0, 0, mBottomPadding);
setBottomMargin(mStackScroller, mStackScrollerMargin);
}
- mStackScroller.setQsCustomizerShowing(isShowing);
}
private void setBottomMargin(View v, int bottomMargin) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
index 399c850..a0edc7c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
@@ -74,11 +74,13 @@
mBrightnessMirror.setVisibility(View.VISIBLE);
mVisibilityCallback.accept(true);
mNotificationPanel.setPanelAlpha(0, true /* animate */);
+ mDepthController.setBrightnessMirrorVisible(true);
}
public void hideMirror() {
mVisibilityCallback.accept(false);
mNotificationPanel.setPanelAlpha(255, true /* animate */);
+ mDepthController.setBrightnessMirrorVisible(false);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
index 0a6cf7b..c2bd87c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
@@ -33,6 +33,7 @@
interface ConfigurationListener {
default void onConfigChanged(Configuration newConfig) {}
default void onDensityOrFontScaleChanged() {}
+ default void onSmallestScreenWidthChanged() {}
default void onOverlayChanged() {}
default void onUiModeChanged() {}
default void onThemeChanged() {}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index ca1f55e..11ddbd0 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -241,7 +241,7 @@
@Override
public void onReceive(Context context, Intent intent) {
boolean newWorkProfile = Intent.ACTION_MANAGED_PROFILE_ADDED.equals(intent.getAction());
- boolean userStarted = Intent.ACTION_USER_STARTED.equals(intent.getAction());
+ boolean userStarted = Intent.ACTION_USER_SWITCHED.equals(intent.getAction());
boolean isManagedProfile = mUserManager.isManagedProfile(
intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
if (userStarted || newWorkProfile) {
@@ -288,7 +288,7 @@
public void start() {
if (DEBUG) Log.d(TAG, "Start");
final IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_USER_STARTED);
+ filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
filter.addAction(Intent.ACTION_WALLPAPER_CHANGED);
mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter, mMainExecutor,
diff --git a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
index c5e35a4..8b394bf 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
+++ b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
@@ -16,13 +16,18 @@
package com.android.systemui.toast;
+import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
+import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+
import android.animation.Animator;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.Application;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -53,7 +58,7 @@
final ToastPlugin.Toast mPluginToast;
private final String mPackageName;
- private final int mUserId;
+ @UserIdInt private final int mUserId;
private final LayoutInflater mLayoutInflater;
final int mDefaultX = 0;
@@ -74,7 +79,7 @@
}
SystemUIToast(LayoutInflater layoutInflater, Context context, CharSequence text,
- ToastPlugin.Toast pluginToast, String packageName, int userId,
+ ToastPlugin.Toast pluginToast, String packageName, @UserIdInt int userId,
int orientation) {
mLayoutInflater = layoutInflater;
mContext = context;
@@ -248,6 +253,15 @@
return null;
}
+ final Context userContext;
+ try {
+ userContext = context.createPackageContextAsUser("android",
+ 0, new UserHandle(userId));
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Could not create user package context");
+ return null;
+ }
+
final ApplicationsState appState =
ApplicationsState.getInstance((Application) context.getApplicationContext());
if (!appState.isUserAdded(userId)) {
@@ -255,9 +269,11 @@
+ "packageName=" + packageName);
return null;
}
+
+ final PackageManager packageManager = userContext.getPackageManager();
final AppEntry appEntry = appState.getEntry(packageName, userId);
if (appEntry == null || appEntry.info == null
- || !ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER.filterApp(appEntry)) {
+ || !showApplicationIcon(appEntry.info, packageManager)) {
return null;
}
@@ -265,7 +281,20 @@
UserHandle user = UserHandle.getUserHandleForUid(appInfo.uid);
IconFactory iconFactory = IconFactory.obtain(context);
Bitmap iconBmp = iconFactory.createBadgedIconBitmap(
- appInfo.loadUnbadgedIcon(context.getPackageManager()), user, true).icon;
+ appInfo.loadUnbadgedIcon(packageManager), user, true).icon;
return new BitmapDrawable(context.getResources(), iconBmp);
}
+
+ private static boolean showApplicationIcon(ApplicationInfo appInfo,
+ PackageManager packageManager) {
+ if (hasFlag(appInfo.flags, FLAG_UPDATED_SYSTEM_APP)) {
+ return packageManager.getLaunchIntentForPackage(appInfo.packageName)
+ != null;
+ }
+ return !hasFlag(appInfo.flags, FLAG_SYSTEM);
+ }
+
+ private static boolean hasFlag(int flags, int flag) {
+ return (flags & flag) != 0;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvBottomSheetActivity.java b/packages/SystemUI/src/com/android/systemui/tv/TvBottomSheetActivity.java
new file mode 100644
index 0000000..2b7a332
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvBottomSheetActivity.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.tv;
+
+import android.app.Activity;
+import android.graphics.PixelFormat;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.WindowManager;
+
+import com.android.systemui.R;
+
+import java.util.function.Consumer;
+
+/**
+ * Generic bottom sheet with up to two icons in the beginning and two buttons.
+ */
+public abstract class TvBottomSheetActivity extends Activity {
+
+ private static final String TAG = TvBottomSheetActivity.class.getSimpleName();
+ private Drawable mBackgroundWithBlur;
+ private Drawable mBackgroundWithoutBlur;
+
+ private final Consumer<Boolean> mBlurConsumer = this::onBlurChanged;
+
+ private void onBlurChanged(boolean enabled) {
+ Log.v(TAG, "blur enabled: " + enabled);
+ getWindow().setBackgroundDrawable(enabled ? mBackgroundWithBlur : mBackgroundWithoutBlur);
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.tv_bottom_sheet);
+
+ overridePendingTransition(R.anim.tv_bottom_sheet_enter, 0);
+
+ mBackgroundWithBlur = getResources()
+ .getDrawable(R.drawable.bottom_sheet_background_with_blur);
+ mBackgroundWithoutBlur = getResources().getDrawable(R.drawable.bottom_sheet_background);
+
+ DisplayMetrics metrics = getResources().getDisplayMetrics();
+ int screenWidth = metrics.widthPixels;
+ int screenHeight = metrics.heightPixels;
+ int marginPx = getResources().getDimensionPixelSize(R.dimen.bottom_sheet_margin);
+
+ WindowManager.LayoutParams windowParams = getWindow().getAttributes();
+ windowParams.width = screenWidth - marginPx * 2;
+ windowParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
+ windowParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
+ windowParams.horizontalMargin = 0f;
+ windowParams.verticalMargin = (float) marginPx / screenHeight;
+ windowParams.format = PixelFormat.TRANSPARENT;
+ windowParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
+ windowParams.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
+ windowParams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+ getWindow().setAttributes(windowParams);
+ getWindow().setElevation(getWindow().getElevation() + 5);
+ getWindow().setBackgroundBlurRadius(getResources().getDimensionPixelSize(
+ R.dimen.bottom_sheet_background_blur_radius));
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ getWindowManager().addCrossWindowBlurEnabledListener(mBlurConsumer);
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ getWindowManager().removeCrossWindowBlurEnabledListener(mBlurConsumer);
+ super.onDetachedFromWindow();
+ }
+
+ @Override
+ public void finish() {
+ super.finish();
+ overridePendingTransition(0, R.anim.tv_bottom_sheet_exit);
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index ab4b1f1..e570598 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -128,7 +128,7 @@
private final MediaSessions mMediaSessions;
protected C mCallbacks = new C();
private final State mState = new State();
- protected final MediaSessionsCallbacks mMediaSessionsCallbacksW = new MediaSessionsCallbacks();
+ protected final MediaSessionsCallbacks mMediaSessionsCallbacksW;
private final Optional<Vibrator> mVibrator;
private final boolean mHasVibrator;
private boolean mShowA11yStream;
@@ -179,6 +179,7 @@
mWorkerLooper = theadFactory.buildLooperOnNewThread(
VolumeDialogControllerImpl.class.getSimpleName());
mWorker = new W(mWorkerLooper);
+ mMediaSessionsCallbacksW = new MediaSessionsCallbacks(mContext);
mMediaSessions = createMediaSessions(mContext, mWorkerLooper, mMediaSessionsCallbacksW);
mAudio = audioManager;
mNoMan = notificationManager;
@@ -1148,83 +1149,98 @@
private final HashMap<Token, Integer> mRemoteStreams = new HashMap<>();
private int mNextStream = DYNAMIC_STREAM_START_INDEX;
+ private final boolean mShowRemoteSessions;
+
+ public MediaSessionsCallbacks(Context context) {
+ mShowRemoteSessions = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_volumeShowRemoteSessions);
+ }
@Override
public void onRemoteUpdate(Token token, String name, PlaybackInfo pi) {
- addStream(token, "onRemoteUpdate");
+ if (mShowRemoteSessions) {
+ addStream(token, "onRemoteUpdate");
- int stream = 0;
- synchronized (mRemoteStreams) {
- stream = mRemoteStreams.get(token);
- }
- Slog.d(TAG, "onRemoteUpdate: stream: " + stream + " volume: " + pi.getCurrentVolume());
- boolean changed = mState.states.indexOfKey(stream) < 0;
- final StreamState ss = streamStateW(stream);
- ss.dynamic = true;
- ss.levelMin = 0;
- ss.levelMax = pi.getMaxVolume();
- if (ss.level != pi.getCurrentVolume()) {
- ss.level = pi.getCurrentVolume();
- changed = true;
- }
- if (!Objects.equals(ss.remoteLabel, name)) {
- ss.name = -1;
- ss.remoteLabel = name;
- changed = true;
- }
- if (changed) {
- Log.d(TAG, "onRemoteUpdate: " + name + ": " + ss.level + " of " + ss.levelMax);
- mCallbacks.onStateChanged(mState);
+ int stream = 0;
+ synchronized (mRemoteStreams) {
+ stream = mRemoteStreams.get(token);
+ }
+ Slog.d(TAG,
+ "onRemoteUpdate: stream: " + stream + " volume: " + pi.getCurrentVolume());
+ boolean changed = mState.states.indexOfKey(stream) < 0;
+ final StreamState ss = streamStateW(stream);
+ ss.dynamic = true;
+ ss.levelMin = 0;
+ ss.levelMax = pi.getMaxVolume();
+ if (ss.level != pi.getCurrentVolume()) {
+ ss.level = pi.getCurrentVolume();
+ changed = true;
+ }
+ if (!Objects.equals(ss.remoteLabel, name)) {
+ ss.name = -1;
+ ss.remoteLabel = name;
+ changed = true;
+ }
+ if (changed) {
+ Log.d(TAG, "onRemoteUpdate: " + name + ": " + ss.level + " of " + ss.levelMax);
+ mCallbacks.onStateChanged(mState);
+ }
}
}
@Override
public void onRemoteVolumeChanged(Token token, int flags) {
- addStream(token, "onRemoteVolumeChanged");
- int stream = 0;
- synchronized (mRemoteStreams) {
- stream = mRemoteStreams.get(token);
- }
- final boolean showUI = shouldShowUI(flags);
- Slog.d(TAG, "onRemoteVolumeChanged: stream: " + stream + " showui? " + showUI);
- boolean changed = updateActiveStreamW(stream);
- if (showUI) {
- changed |= checkRoutedToBluetoothW(AudioManager.STREAM_MUSIC);
- }
- if (changed) {
- Slog.d(TAG, "onRemoteChanged: updatingState");
- mCallbacks.onStateChanged(mState);
- }
- if (showUI) {
- mCallbacks.onShowRequested(Events.SHOW_REASON_REMOTE_VOLUME_CHANGED);
+ if (mShowRemoteSessions) {
+ addStream(token, "onRemoteVolumeChanged");
+ int stream = 0;
+ synchronized (mRemoteStreams) {
+ stream = mRemoteStreams.get(token);
+ }
+ final boolean showUI = shouldShowUI(flags);
+ Slog.d(TAG, "onRemoteVolumeChanged: stream: " + stream + " showui? " + showUI);
+ boolean changed = updateActiveStreamW(stream);
+ if (showUI) {
+ changed |= checkRoutedToBluetoothW(AudioManager.STREAM_MUSIC);
+ }
+ if (changed) {
+ Slog.d(TAG, "onRemoteChanged: updatingState");
+ mCallbacks.onStateChanged(mState);
+ }
+ if (showUI) {
+ mCallbacks.onShowRequested(Events.SHOW_REASON_REMOTE_VOLUME_CHANGED);
+ }
}
}
@Override
public void onRemoteRemoved(Token token) {
- int stream = 0;
- synchronized (mRemoteStreams) {
- if (!mRemoteStreams.containsKey(token)) {
- Log.d(TAG, "onRemoteRemoved: stream doesn't exist, "
- + "aborting remote removed for token:" + token.toString());
- return;
+ if (mShowRemoteSessions) {
+ int stream = 0;
+ synchronized (mRemoteStreams) {
+ if (!mRemoteStreams.containsKey(token)) {
+ Log.d(TAG, "onRemoteRemoved: stream doesn't exist, "
+ + "aborting remote removed for token:" + token.toString());
+ return;
+ }
+ stream = mRemoteStreams.get(token);
}
- stream = mRemoteStreams.get(token);
+ mState.states.remove(stream);
+ if (mState.activeStream == stream) {
+ updateActiveStreamW(-1);
+ }
+ mCallbacks.onStateChanged(mState);
}
- mState.states.remove(stream);
- if (mState.activeStream == stream) {
- updateActiveStreamW(-1);
- }
- mCallbacks.onStateChanged(mState);
}
public void setStreamVolume(int stream, int level) {
- final Token t = findToken(stream);
- if (t == null) {
- Log.w(TAG, "setStreamVolume: No token found for stream: " + stream);
- return;
+ if (mShowRemoteSessions) {
+ final Token t = findToken(stream);
+ if (t == null) {
+ Log.w(TAG, "setStreamVolume: No token found for stream: " + stream);
+ return;
+ }
+ mMediaSessions.setVolume(t, level);
}
- mMediaSessions.setVolume(t, level);
}
private Token findToken(int stream) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
index 5b50e89..6237031 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
@@ -25,6 +25,8 @@
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import android.content.Context;
+import android.content.ContextWrapper;
import android.os.UserHandle;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
@@ -39,6 +41,7 @@
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -58,6 +61,7 @@
@Rule
public MockitoRule mockito = MockitoJUnit.rule();
+ private Context mContextWrapper;
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private AccessibilityFloatingMenuController mController;
private AccessibilityButtonTargetsObserver mTargetsObserver;
@@ -66,6 +70,16 @@
private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardCallbackCaptor;
private KeyguardUpdateMonitorCallback mKeyguardCallback;
+ @Before
+ public void setUp() throws Exception {
+ mContextWrapper = new ContextWrapper(mContext) {
+ @Override
+ public Context createContextAsUser(UserHandle user, int flags) {
+ return getBaseContext();
+ }
+ };
+ }
+
@Test
public void initController_registerListeners() {
mController = setUpController();
@@ -105,7 +119,7 @@
public void onKeyguardVisibilityChanged_showing_destroyWidget() {
enableAccessibilityFloatingMenuConfig();
mController = setUpController();
- mController.mFloatingMenu = new AccessibilityFloatingMenu(mContext);
+ mController.mFloatingMenu = new AccessibilityFloatingMenu(mContextWrapper);
captureKeyguardUpdateMonitorCallback();
mKeyguardCallback.onUserUnlocked();
@@ -131,7 +145,7 @@
final int fakeUserId = 1;
enableAccessibilityFloatingMenuConfig();
mController = setUpController();
- mController.mFloatingMenu = new AccessibilityFloatingMenu(mContext);
+ mController.mFloatingMenu = new AccessibilityFloatingMenu(mContextWrapper);
captureKeyguardUpdateMonitorCallback();
mKeyguardCallback.onUserSwitching(fakeUserId);
@@ -144,7 +158,7 @@
final int fakeUserId = 1;
enableAccessibilityFloatingMenuConfig();
mController = setUpController();
- mController.mFloatingMenu = new AccessibilityFloatingMenu(mContext);
+ mController.mFloatingMenu = new AccessibilityFloatingMenu(mContextWrapper);
captureKeyguardUpdateMonitorCallback();
mKeyguardCallback.onUserUnlocked();
mKeyguardCallback.onKeyguardVisibilityChanged(true);
@@ -172,7 +186,7 @@
@Test
public void onAccessibilityButtonModeChanged_floatingModeAndHasButtonTargets_showWidget() {
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.putStringForUser(mContextWrapper.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, TEST_A11Y_BTN_TARGETS,
UserHandle.USER_CURRENT);
mController = setUpController();
@@ -184,7 +198,7 @@
@Test
public void onAccessibilityButtonModeChanged_floatingModeAndNoButtonTargets_destroyWidget() {
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.putStringForUser(mContextWrapper.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, "", UserHandle.USER_CURRENT);
mController = setUpController();
@@ -195,7 +209,7 @@
@Test
public void onAccessibilityButtonModeChanged_navBarModeAndHasButtonTargets_destroyWidget() {
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.putStringForUser(mContextWrapper.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, TEST_A11Y_BTN_TARGETS,
UserHandle.USER_CURRENT);
mController = setUpController();
@@ -207,7 +221,7 @@
@Test
public void onAccessibilityButtonModeChanged_navBarModeAndNoButtonTargets_destroyWidget() {
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.putStringForUser(mContextWrapper.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, "", UserHandle.USER_CURRENT);
mController = setUpController();
@@ -218,7 +232,7 @@
@Test
public void onAccessibilityButtonTargetsChanged_floatingModeAndHasButtonTargets_showWidget() {
- Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.putIntForUser(mContextWrapper.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU,
UserHandle.USER_CURRENT);
mController = setUpController();
@@ -230,7 +244,7 @@
@Test
public void onAccessibilityButtonTargetsChanged_floatingModeAndNoButtonTargets_destroyWidget() {
- Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.putIntForUser(mContextWrapper.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU,
UserHandle.USER_CURRENT);
mController = setUpController();
@@ -242,7 +256,7 @@
@Test
public void onAccessibilityButtonTargetsChanged_navBarModeAndHasButtonTargets_destroyWidget() {
- Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.putIntForUser(mContextWrapper.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, UserHandle.USER_CURRENT);
mController = setUpController();
@@ -254,7 +268,7 @@
@Test
public void onAccessibilityButtonTargetsChanged_navBarModeAndNoButtonTargets_destroyWidget() {
- Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.putIntForUser(mContextWrapper.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, UserHandle.USER_CURRENT);
mController = setUpController();
@@ -269,15 +283,15 @@
mModeObserver = spy(Dependency.get(AccessibilityButtonModeObserver.class));
mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
- return new AccessibilityFloatingMenuController(mContext, mTargetsObserver,
+ return new AccessibilityFloatingMenuController(mContextWrapper, mTargetsObserver,
mModeObserver, mKeyguardUpdateMonitor);
}
private void enableAccessibilityFloatingMenuConfig() {
- Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.putIntForUser(mContextWrapper.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU,
UserHandle.USER_CURRENT);
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.putStringForUser(mContextWrapper.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, TEST_A11Y_BTN_TARGETS,
UserHandle.USER_CURRENT);
}
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 41f9877..0c750a1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -53,6 +53,7 @@
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.util.concurrency.FakeExecutor;
@@ -117,6 +118,8 @@
@Mock
private AccessibilityManager mAccessibilityManager;
@Mock
+ private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
+ @Mock
private ScreenLifecycle mScreenLifecycle;
@Mock
private Vibrator mVibrator;
@@ -176,6 +179,7 @@
mFalsingManager,
mPowerManager,
mAccessibilityManager,
+ mLockscreenShadeTransitionController,
mScreenLifecycle,
mVibrator,
Optional.of(mHbmProvider));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
index 5923de6..f62587c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
@@ -35,6 +35,7 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -65,6 +66,8 @@
@Mock
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@Mock
+ private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
+ @Mock
private DumpManager mDumpManager;
@Mock
private DelayableExecutor mExecutor;
@@ -106,6 +109,7 @@
mExecutor,
mDumpManager,
mKeyguardViewMediator,
+ mLockscreenShadeTransitionController,
mUdfpsController);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
index 6e21642..2c68661 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
@@ -135,8 +135,6 @@
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
@@ -154,8 +152,6 @@
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
@@ -176,9 +172,25 @@
assertThat(mViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mTwoLineTitleText.getText()).isEqualTo(TEST_DEVICE_NAME_1);
+ }
+
+ @Test
+ public void onBindViewHolder_bindConnectedDevice_withSelectableDevice_showAddIcon() {
+ when(mMediaOutputController.getSelectableMediaDevice()).thenReturn(mMediaDevices);
+ mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
+
assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(mViewHolder.mTwoLineTitleText.getText()).isEqualTo(TEST_DEVICE_NAME_1);
+ }
+
+ @Test
+ public void onBindViewHolder_bindConnectedDevice_withoutSelectableDevice_hideAddIcon() {
+ when(mMediaOutputController.getSelectableMediaDevice()).thenReturn(new ArrayList<>());
+ mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
+
+ assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
}
@Test
@@ -245,8 +257,6 @@
assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mTwoLineTitleText.getText()).isEqualTo(TEST_DEVICE_NAME_1);
}
@@ -263,8 +273,6 @@
assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mTitleText.getText()).isEqualTo(TEST_DEVICE_NAME_1);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
index 589ae2e..9bd07b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
@@ -155,6 +155,7 @@
@Test
public void refresh_notInDragging_verifyUpdateAdapter() {
+ when(mMediaOutputBaseAdapter.getCurrentActivePosition()).thenReturn(-1);
when(mMediaOutputBaseAdapter.isDragging()).thenReturn(false);
mMediaOutputBaseDialogImpl.refresh();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
index da63b8a..4980f74 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
@@ -52,6 +52,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -108,7 +109,8 @@
Dependency.get(Dependency.MAIN_HANDLER),
mock(UiEventLogger.class),
mock(NavigationBarOverlayController.class),
- mock(ConfigurationController.class)));
+ mock(ConfigurationController.class),
+ mock(UserTracker.class)));
initializeNavigationBars();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index 4ec45b4..b1afeec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -76,6 +76,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -276,7 +277,8 @@
mock(SystemActions.class),
mHandler,
mock(NavigationBarOverlayController.class),
- mUiEventLogger));
+ mUiEventLogger,
+ mock(UserTracker.class)));
}
private void processAllMessages() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java
index 67505c4..75ae9cb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java
@@ -35,7 +35,6 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -541,7 +540,9 @@
tileWithDndBlocking, mOptions).getViews();
View result = views.apply(mContext, null);
- assertEquals(result.getSourceLayoutResId(), R.layout.people_tile_suppressed_layout);
+ assertResourcesEqual(
+ result.getSourceLayoutResId(),
+ R.layout.people_tile_with_suppression_detail_content_horizontal);
tileWithDndBlocking = PERSON_TILE.toBuilder()
.setNotificationPolicyState(BLOCK_CONVERSATIONS)
@@ -551,7 +552,9 @@
tileWithDndBlocking, mOptions).getViews();
result = views.apply(mContext, null);
- assertNotEquals(result.getSourceLayoutResId(), R.layout.people_tile_suppressed_layout);
+ assertResourcesNotEqual(
+ result.getSourceLayoutResId(),
+ R.layout.people_tile_with_suppression_detail_content_horizontal);
tileWithDndBlocking = PERSON_TILE.toBuilder()
.setNotificationPolicyState(SHOW_IMPORTANT_CONVERSATIONS)
@@ -560,7 +563,9 @@
tileWithDndBlocking, mOptions).getViews();
result = views.apply(mContext, null);
- assertEquals(result.getSourceLayoutResId(), R.layout.people_tile_suppressed_layout);
+ assertResourcesEqual(
+ result.getSourceLayoutResId(),
+ R.layout.people_tile_with_suppression_detail_content_horizontal);
tileWithDndBlocking = PERSON_TILE.toBuilder()
.setNotificationPolicyState(SHOW_IMPORTANT_CONVERSATIONS)
@@ -570,7 +575,9 @@
tileWithDndBlocking, mOptions).getViews();
result = views.apply(mContext, null);
- assertNotEquals(result.getSourceLayoutResId(), R.layout.people_tile_suppressed_layout);
+ assertResourcesNotEqual(
+ result.getSourceLayoutResId(),
+ R.layout.people_tile_with_suppression_detail_content_horizontal);
tileWithDndBlocking = PERSON_TILE.toBuilder()
.setNotificationPolicyState(SHOW_STARRED_CONTACTS)
@@ -580,7 +587,9 @@
tileWithDndBlocking, mOptions).getViews();
result = views.apply(mContext, null);
- assertEquals(result.getSourceLayoutResId(), R.layout.people_tile_suppressed_layout);
+ assertResourcesEqual(
+ result.getSourceLayoutResId(),
+ R.layout.people_tile_with_suppression_detail_content_horizontal);
tileWithDndBlocking = PERSON_TILE.toBuilder()
.setNotificationPolicyState(SHOW_STARRED_CONTACTS)
@@ -590,7 +599,9 @@
tileWithDndBlocking, mOptions).getViews();
result = views.apply(mContext, null);
- assertNotEquals(result.getSourceLayoutResId(), R.layout.people_tile_suppressed_layout);
+ assertResourcesNotEqual(
+ result.getSourceLayoutResId(),
+ R.layout.people_tile_with_suppression_detail_content_horizontal);
tileWithDndBlocking = PERSON_TILE.toBuilder()
.setNotificationPolicyState(SHOW_CONTACTS)
@@ -600,7 +611,9 @@
tileWithDndBlocking, mOptions).getViews();
result = views.apply(mContext, null);
- assertNotEquals(result.getSourceLayoutResId(), R.layout.people_tile_suppressed_layout);
+ assertResourcesNotEqual(
+ result.getSourceLayoutResId(),
+ R.layout.people_tile_with_suppression_detail_content_horizontal);
tileWithDndBlocking = PERSON_TILE.toBuilder()
.setNotificationPolicyState(SHOW_CONTACTS)
@@ -610,7 +623,9 @@
tileWithDndBlocking, mOptions).getViews();
result = views.apply(mContext, null);
- assertNotEquals(result.getSourceLayoutResId(), R.layout.people_tile_suppressed_layout);
+ assertResourcesNotEqual(
+ result.getSourceLayoutResId(),
+ R.layout.people_tile_with_suppression_detail_content_horizontal);
tileWithDndBlocking = PERSON_TILE.toBuilder()
.setNotificationPolicyState(SHOW_CONTACTS)
@@ -619,7 +634,11 @@
tileWithDndBlocking, mOptions).getViews();
result = views.apply(mContext, null);
- assertEquals(result.getSourceLayoutResId(), R.layout.people_tile_suppressed_layout);
+ assertResourcesEqual(
+ result.getSourceLayoutResId(),
+ R.layout.people_tile_with_suppression_detail_content_horizontal);
+ assertThat(result.<TextView>findViewById(R.id.text_content).getText().toString())
+ .isEqualTo(mContext.getString(R.string.paused_by_dnd));
}
@Test
@@ -1068,4 +1087,21 @@
return new PeopleTileViewHelper(mContext, tile, 0, options,
new PeopleTileKey(tile.getId(), 0, tile.getPackageName()));
}
+
+ private void assertResourcesEqual(int expected, int actual) {
+ assertThat(getResourceName(actual)).isEqualTo(getResourceName(expected));
+ }
+
+ private void assertResourcesNotEqual(int expected, int actual) {
+ assertThat(getResourceName(actual)).isNotEqualTo(getResourceName(expected));
+ }
+
+ private String getResourceName(int resId) {
+ Resources resources = mContext.getResources();
+ try {
+ return resources.getResourceEntryName(resId);
+ } catch (Resources.NotFoundException e) {
+ return String.valueOf(resId);
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeSession.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeSession.java
index 9c68f0d..478658e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeSession.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeSession.java
@@ -57,16 +57,19 @@
private int mScrollDelta;
private int mPageHeight;
+ private int mTargetHeight;
FakeSession(int pageHeight, float maxPages, int tileHeight, int visiblePageTop,
- int visiblePageBottom, int availableTop, int availableBottom) {
+ int visiblePageBottom, int availableTop, int availableBottom,
+ int maxTiles) {
mPageHeight = pageHeight;
mTileHeight = tileHeight;
mAvailable = new Rect(0, availableTop, getPageWidth(), availableBottom);
mAvailableTop = new Rect(mAvailable);
mAvailableTop.inset(0, 0, 0, pageHeight);
mVisiblePage = new Rect(0, visiblePageTop, getPageWidth(), visiblePageBottom);
- mMaxTiles = (int) Math.ceil((pageHeight * maxPages) / mTileHeight);
+ mTargetHeight = (int) (pageHeight * maxPages);
+ mMaxTiles = maxTiles;
}
private static Image mockImage() {
@@ -158,6 +161,11 @@
}
@Override
+ public int getTargetHeight() {
+ return mTargetHeight;
+ }
+
+ @Override
public int getTileHeight() {
return mTileHeight;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeSessionTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeSessionTest.java
index 2520af9..4c8a4b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeSessionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeSessionTest.java
@@ -42,21 +42,6 @@
@RunWith(AndroidTestingRunner.class)
public class FakeSessionTest extends SysuiTestCase {
@Test
- public void testMaxTiles() {
- FakeSession session = new FakeSession(
- /* pageHeight */ 100,
- /* maxPages */ 2.25f,
- /* tileHeight */ 10,
- /* visiblePageTop */ 0,
- /* visiblePageBottom */ 100,
- /* availableTop */ -250,
- /* availableBottom */ 250);
-
- // (pageHeight * maxPages) / tileHeight
- assertEquals("getMaxTiles()", 23, session.getMaxTiles());
- }
-
- @Test
public void testNonEmptyResult_hasImage() {
FakeSession session = new FakeSession(
/* pageHeight */ 100,
@@ -65,7 +50,8 @@
/* visiblePageTop */ 0,
/* visiblePageBottom */ 100,
/* availableTop */ 0,
- /* availableBottom */ 100);
+ /* availableBottom */ 100,
+ /* max Tiles */ 30);
ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(0));
assertNotNull("result.image", result.image);
assertNotNull("result.image.getHardwareBuffer()", result.image.getHardwareBuffer());
@@ -80,7 +66,8 @@
/* visiblePageTop */ 0,
/* visiblePageBottom */ 100,
/* availableTop */ 0,
- /* availableBottom */ 100);
+ /* availableBottom */ 100,
+ /* max Tiles */ 30);
ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(-100));
assertNull("result.image", result.image);
}
@@ -94,7 +81,8 @@
/* visiblePageTop */ 0,
/* visiblePageBottom */ 100,
/* availableTop */ -250,
- /* availableBottom */ 250);
+ /* availableBottom */ 250,
+ /* max Tiles */ 30);
ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(0));
assertEquals("requested top", 0, result.requested.top);
@@ -113,7 +101,8 @@
/* visiblePageTop */ 0,
/* visiblePageBottom */ 100,
/* availableTop */ -250,
- /* availableBottom */ 250);
+ /* availableBottom */ 250,
+ /* max Tiles */ 30);
ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(90));
assertEquals("requested top", 90, result.requested.top);
@@ -132,7 +121,8 @@
/* visiblePageTop */ 0,
/* visiblePageBottom */ 100,
/* availableTop */ -250,
- /* availableBottom */ 250);
+ /* availableBottom */ 250,
+ /* max Tiles */ 30);
ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(-100));
assertEquals("requested top", -100, result.requested.top);
@@ -151,7 +141,8 @@
/* visiblePageTop */ 0,
/* visiblePageBottom */ 100,
/* availableTop */ -250,
- /* availableBottom */ 250);
+ /* availableBottom */ 250,
+ /* max Tiles */ 30);
ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(150));
assertEquals("requested top", 150, result.requested.top);
@@ -170,7 +161,8 @@
/* visiblePageTop */ 0,
/* visiblePageBottom */ 100,
/* availableTop */ -100,
- /* availableBottom */ 100);
+ /* availableBottom */ 100,
+ /* max Tiles */ 30);
ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(-125));
assertEquals("requested top", -125, result.requested.top);
@@ -189,7 +181,8 @@
/* visiblePageTop */ 0,
/* visiblePageBottom */ 100,
/* availableTop */ -100,
- /* availableBottom */ 100);
+ /* availableBottom */ 100,
+ /* max Tiles */ 30);
ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(75));
assertEquals("requested top", 75, result.requested.top);
@@ -211,7 +204,8 @@
/* visiblePageTop */ 25, // <<--
/* visiblePageBottom */ 100,
/* availableTop */ -150,
- /* availableBottom */ 150);
+ /* availableBottom */ 150,
+ /* max Tiles */ 30);
ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(-150));
assertEquals("requested top", -150, result.requested.top);
@@ -233,7 +227,8 @@
/* visiblePageTop */ 0,
/* visiblePageBottom */ 75,
/* availableTop */ -150,
- /* availableBottom */ 150);
+ /* availableBottom */ 150,
+ /* max Tiles */ 30);
ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(50));
assertEquals("requested top", 50, result.requested.top);
@@ -252,7 +247,8 @@
/* visiblePageTop */ 0,
/* visiblePageBottom */ 100,
/* availableTop */ -100,
- /* availableBottom */ 200);
+ /* availableBottom */ 200,
+ /* max Tiles */ 30);
ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(-150));
assertTrue("captured rect is empty", result.captured.isEmpty());
}
@@ -266,7 +262,8 @@
/* visiblePageTop */ 0,
/* visiblePageBottom */ 100,
/* availableTop */ -100,
- /* availableBottom */ 200);
+ /* availableBottom */ 200,
+ /* max Tiles */ 30);
ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(200));
assertTrue("captured rect is empty", result.captured.isEmpty());
}
@@ -280,7 +277,8 @@
/* visiblePageTop */ 60, // <<---
/* visiblePageBottom */ 0,
/* availableTop */ -150,
- /* availableBottom */ 150);
+ /* availableBottom */ 150,
+ /* max Tiles */ 30);
ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(0));
assertEquals("requested top", 0, result.requested.top);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureControllerTest.java
index 5bab1bc..10c878a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureControllerTest.java
@@ -92,14 +92,16 @@
// Each tile is cropped to the visible page size, which is inset 5px from the TOP
// requested result
// 0, 50 5, 50
- // -45, 5 -40, 5 <-- clear previous / top
- // 5, 55 5, 55 (not cropped, target is positioned fully within visible range)
- // 55, 105 55, 105
- // 105, 155 105, 155
- // 155, 205 155, 205 <-- bottom
+ // -45, 5 -40, 5
+ // -90, -40 -85, -40 <-- clear previous / top
+ // -40, 10 -40, 10 (not cropped, target is positioned fully within visible range)
+ // 10, 60 10, 60
+ // 60, 110 60, 110
+ // 110, 160 110, 160
+ // 160, 210 160, 210 <-- bottom
- assertEquals("top", -40, screenshot.getTop());
- assertEquals("bottom", 205, screenshot.getBottom());
+ assertEquals("top", -85, screenshot.getTop());
+ assertEquals("bottom", 210, screenshot.getBottom());
}
@Test
@@ -119,13 +121,14 @@
// requested result
// 0, 50 0, 50 // not cropped, positioned within visible range
// -50, 0 -50, 0 <-- clear previous/reverse
- // 0, 50 - 0, 45 // target now positioned at page bottom, bottom cropped
+ // 0, 50 0, 45 // target now positioned at page bottom, bottom cropped
// 45, 95, 45, 90
// 90, 140, 140, 135
- // 135, 185 185, 180 <-- bottom
+ // 135, 185 185, 180
+ // 180, 230 180, 225 <-- bottom
assertEquals("top", -50, screenshot.getTop());
- assertEquals("bottom", 180, screenshot.getBottom());
+ assertEquals("bottom", 225, screenshot.getBottom());
}
@Test
@@ -265,7 +268,8 @@
mLocalVisibleBottom = mPageHeight;
}
Session session = new FakeSession(mPageHeight, mMaxPages, mTileHeight,
- mLocalVisibleTop, mLocalVisibleBottom, mAvailableTop, mAvailableBottom);
+ mLocalVisibleTop, mLocalVisibleBottom, mAvailableTop, mAvailableBottom,
+ /* maxTiles */ 30);
ScrollCaptureClient client = mock(ScrollCaptureClient.class);
when(client.start(/* response */ any(), /* maxPages */ anyFloat()))
.thenReturn(immediateFuture(session));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt
index 7c7d2dc..2b44d8b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar
import android.content.res.Resources
+import android.view.CrossWindowBlurListeners
import android.view.SurfaceControl
import android.view.ViewRootImpl
import androidx.test.filters.SmallTest
@@ -37,11 +38,13 @@
@Mock lateinit var resources: Resources
@Mock lateinit var dumpManager: DumpManager
@Mock lateinit var transaction: SurfaceControl.Transaction
+ @Mock lateinit var corssWindowBlurListeners: CrossWindowBlurListeners
lateinit var blurUtils: BlurUtils
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
+ `when`(corssWindowBlurListeners.isCrossWindowBlurEnabled).thenReturn(true)
blurUtils = TestableBlurUtils()
}
@@ -71,7 +74,7 @@
verify(transaction).apply()
}
- inner class TestableBlurUtils() : BlurUtils(resources, dumpManager) {
+ inner class TestableBlurUtils() : BlurUtils(resources, corssWindowBlurListeners, dumpManager) {
override fun supportsBlursOnWindows(): Boolean {
return true
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index 61c3835..60b3889 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -47,6 +47,7 @@
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.doThrow
import org.mockito.Mockito.never
+import org.mockito.Mockito.reset
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
@@ -71,6 +72,7 @@
@Mock private lateinit var shadeSpring: NotificationShadeDepthController.DepthAnimation
@Mock private lateinit var shadeAnimation: NotificationShadeDepthController.DepthAnimation
@Mock private lateinit var globalActionsSpring: NotificationShadeDepthController.DepthAnimation
+ @Mock private lateinit var brightnessSpring: NotificationShadeDepthController.DepthAnimation
@Mock private lateinit var listener: NotificationShadeDepthController.DepthListener
@Mock private lateinit var dozeParameters: DozeParameters
@Captor private lateinit var scrimVisibilityCaptor: ArgumentCaptor<Consumer<Int>>
@@ -90,7 +92,11 @@
`when`(blurUtils.blurRadiusOfRatio(anyFloat())).then { answer ->
(answer.arguments[0] as Float * maxBlur).toInt()
}
- `when`(blurUtils.minBlurRadius).thenReturn(0)
+ `when`(blurUtils.ratioOfBlurRadius(anyInt())).then { answer ->
+ answer.arguments[0] as Int / maxBlur.toFloat()
+ }
+ `when`(blurUtils.supportsBlursOnWindows()).thenReturn(true)
+ `when`(blurUtils.maxBlurRadius).thenReturn(maxBlur)
`when`(blurUtils.maxBlurRadius).thenReturn(maxBlur)
notificationShadeDepthController = NotificationShadeDepthController(
@@ -99,6 +105,7 @@
notificationShadeWindowController, dozeParameters, dumpManager)
notificationShadeDepthController.shadeSpring = shadeSpring
notificationShadeDepthController.shadeAnimation = shadeAnimation
+ notificationShadeDepthController.brightnessMirrorSpring = brightnessSpring
notificationShadeDepthController.globalActionsSpring = globalActionsSpring
notificationShadeDepthController.root = root
@@ -191,6 +198,14 @@
}
@Test
+ fun setFullShadeTransition_appliesBlur_onlyIfSupported() {
+ reset(blurUtils)
+ notificationShadeDepthController.transitionToFullShadeProgress = 1f
+ notificationShadeDepthController.updateBlurCallback.doFrame(0)
+ verify(blurUtils).applyBlur(any(), eq(0), eq(false))
+ }
+
+ @Test
fun updateGlobalDialogVisibility_animatesBlur() {
notificationShadeDepthController.updateGlobalDialogVisibility(0.5f, root)
verify(globalActionsSpring).animateTo(eq(maxBlur / 2), eq(root))
@@ -267,6 +282,32 @@
}
@Test
+ fun brightnessMirrorVisible_whenVisible() {
+ notificationShadeDepthController.brightnessMirrorVisible = true
+ verify(brightnessSpring).animateTo(eq(maxBlur), any())
+ }
+
+ @Test
+ fun brightnessMirrorVisible_whenHidden() {
+ notificationShadeDepthController.brightnessMirrorVisible = false
+ verify(brightnessSpring).animateTo(eq(0), any())
+ }
+
+ @Test
+ fun brightnessMirror_hidesShadeBlur() {
+ // Brightness mirror is fully visible
+ `when`(brightnessSpring.ratio).thenReturn(1f)
+ // And shade is blurred
+ `when`(shadeSpring.radius).thenReturn(maxBlur)
+ `when`(shadeAnimation.radius).thenReturn(maxBlur)
+
+ notificationShadeDepthController.updateBlurCallback.doFrame(0)
+ verify(notificationShadeWindowController).setBackgroundBlurRadius(eq(0))
+ verify(wallpaperManager).setWallpaperZoomOut(any(), eq(1f))
+ verify(blurUtils).applyBlur(eq(viewRootImpl), eq(0), eq(false))
+ }
+
+ @Test
fun ignoreShadeBlurUntilHidden_whennNull_ignoresIfShadeHasNoBlur() {
`when`(shadeSpring.radius).thenReturn(0)
`when`(shadeAnimation.radius).thenReturn(0)
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 2d51683..2693b94 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
@@ -26,9 +26,12 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -37,9 +40,13 @@
import android.annotation.IdRes;
import android.app.ActivityManager;
+import android.content.ContentResolver;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.database.ContentObserver;
import android.hardware.biometrics.BiometricSourceType;
+import android.os.Handler;
+import android.os.Looper;
import android.os.PowerManager;
import android.os.UserManager;
import android.testing.AndroidTestingRunner;
@@ -50,6 +57,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
+import android.view.ViewStub;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -60,6 +68,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.testing.UiEventLoggerFake;
+import com.android.internal.util.CollectionUtils;
import com.android.internal.util.LatencyTracker;
import com.android.keyguard.KeyguardClockSwitch;
import com.android.keyguard.KeyguardClockSwitchController;
@@ -140,6 +149,7 @@
private KeyguardBottomAreaView mKeyguardBottomArea;
@Mock
private KeyguardBottomAreaView mQsFrame;
+ private KeyguardStatusView mKeyguardStatusView;
@Mock
private ViewGroup mBigClockContainer;
@Mock
@@ -153,6 +163,10 @@
@Mock
private KeyguardStatusBarView mKeyguardStatusBar;
@Mock
+ private View mUserSwitcherView;
+ @Mock
+ private ViewStub mUserSwitcherStubView;
+ @Mock
private HeadsUpTouchHelper.Callback mHeadsUpCallback;
@Mock
private PanelBar mPanelBar;
@@ -204,7 +218,6 @@
@Mock
private KeyguardClockSwitch mKeyguardClockSwitch;
private PanelViewController.TouchHandler mTouchHandler;
- @Mock
private ConfigurationController mConfigurationController;
@Mock
private MediaHierarchyManager mMediaHiearchyManager;
@@ -265,6 +278,8 @@
@Mock
private SecureSettings mSecureSettings;
@Mock
+ private ContentResolver mContentResolver;
+ @Mock
private TapAgainViewController mTapAgainViewController;
@Mock
private KeyguardIndicationController mKeyguardIndicationController;
@@ -287,6 +302,9 @@
MockitoAnnotations.initMocks(this);
mStatusBarStateController = new StatusBarStateControllerImpl(mUiEventLogger);
+ mKeyguardStatusView = new KeyguardStatusView(mContext);
+ mKeyguardStatusView.setId(R.id.keyguard_status_view);
+
when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(false);
when(mHeadsUpCallback.getContext()).thenReturn(mContext);
when(mView.getResources()).thenReturn(mResources);
@@ -301,6 +319,9 @@
when(mResources.getDimensionPixelSize(R.dimen.notification_panel_width)).thenReturn(400);
when(mView.getContext()).thenReturn(getContext());
when(mView.findViewById(R.id.keyguard_header)).thenReturn(mKeyguardStatusBar);
+ when(mView.findViewById(R.id.keyguard_user_switcher_view)).thenReturn(mUserSwitcherView);
+ when(mView.findViewById(R.id.keyguard_user_switcher_stub)).thenReturn(
+ mUserSwitcherStubView);
when(mView.findViewById(R.id.keyguard_clock_container)).thenReturn(mKeyguardClockSwitch);
when(mView.findViewById(R.id.notification_stack_scroller))
.thenReturn(mNotificationStackScrollLayout);
@@ -320,7 +341,7 @@
mNotificationContainerParent = new NotificationsQuickSettingsContainer(getContext(), null);
mNotificationContainerParent.addView(newViewWithId(R.id.qs_frame));
mNotificationContainerParent.addView(newViewWithId(R.id.notification_stack_scroller));
- mNotificationContainerParent.addView(newViewWithId(R.id.keyguard_status_view));
+ mNotificationContainerParent.addView(mKeyguardStatusView);
when(mView.findViewById(R.id.notification_container_parent))
.thenReturn(mNotificationContainerParent);
when(mFragmentService.getFragmentHostManager(mView)).thenReturn(mFragmentHostManager);
@@ -348,6 +369,7 @@
mFalsingManager,
mLockscreenShadeTransitionController,
new FalsingCollectorFake());
+ mConfigurationController = new ConfigurationControllerImpl(mContext);
when(mKeyguardStatusViewComponentFactory.build(any()))
.thenReturn(mKeyguardStatusViewComponent);
when(mKeyguardStatusViewComponent.getKeyguardClockSwitchController())
@@ -358,10 +380,16 @@
.thenReturn(mKeyguardStatusBarViewComponent);
when(mKeyguardStatusBarViewComponent.getKeyguardStatusBarViewController())
.thenReturn(mKeyguardStatusBarViewController);
+ when(mLayoutInflater.inflate(eq(R.layout.keyguard_status_view), any(), anyBoolean()))
+ .thenReturn(mKeyguardStatusView);
+ when(mLayoutInflater.inflate(eq(R.layout.keyguard_bottom_area), any(), anyBoolean()))
+ .thenReturn(mKeyguardBottomArea);
reset(mView);
+
mNotificationPanelViewController = new NotificationPanelViewController(mView,
mResources,
+ new Handler(Looper.getMainLooper()),
mLayoutInflater,
coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController,
mFalsingManager, new FalsingCollectorFake(),
@@ -395,6 +423,7 @@
mTapAgainViewController,
mNavigationModeController,
mFragmentService,
+ mContentResolver,
mQuickAccessWalletController,
new FakeExecutor(new FakeSystemClock()),
mSecureSettings,
@@ -549,6 +578,38 @@
}
@Test
+ public void testDisableUserSwitcherAfterEnabling_returnsViewStubToTheViewHierarchy() {
+ givenViewAttached();
+ when(mResources.getBoolean(
+ com.android.internal.R.bool.config_keyguardUserSwitcher)).thenReturn(true);
+ updateMultiUserSetting(true);
+ clearInvocations(mView);
+
+ updateMultiUserSetting(false);
+
+ ArgumentCaptor<View> captor = ArgumentCaptor.forClass(View.class);
+ verify(mView, atLeastOnce()).addView(captor.capture(), anyInt());
+ final View userSwitcherStub = CollectionUtils.find(captor.getAllValues(),
+ view -> view.getId() == R.id.keyguard_user_switcher_stub);
+ assertThat(userSwitcherStub).isNotNull();
+ assertThat(userSwitcherStub).isInstanceOf(ViewStub.class);
+ }
+
+ @Test
+ public void testChangeSmallestScreenWidthAndUserSwitchEnabled_inflatesUserSwitchView() {
+ givenViewAttached();
+ when(mView.findViewById(R.id.keyguard_user_switcher_view)).thenReturn(null);
+ updateSmallestScreenWidth(300);
+ when(mResources.getBoolean(
+ com.android.internal.R.bool.config_keyguardUserSwitcher)).thenReturn(true);
+ when(mUserManager.isUserSwitcherEnabled()).thenReturn(true);
+
+ updateSmallestScreenWidth(800);
+
+ verify(mUserSwitcherStubView).inflate();
+ }
+
+ @Test
public void testSplitShadeLayout_isAlignedToGuideline() {
enableSplitShade();
@@ -682,6 +743,12 @@
return mFalsingManager.getTapListeners().get(0);
}
+ private void givenViewAttached() {
+ for (View.OnAttachStateChangeListener listener : mOnAttachStateChangeListeners) {
+ listener.onViewAttachedToWindow(mView);
+ }
+ }
+
private View newViewWithId(int id) {
View view = new View(mContext);
view.setId(id);
@@ -704,6 +771,21 @@
mNotificationPanelViewController.updateResources();
}
+ private void updateMultiUserSetting(boolean enabled) {
+ when(mUserManager.isUserSwitcherEnabled()).thenReturn(enabled);
+ final ArgumentCaptor<ContentObserver> observerCaptor =
+ ArgumentCaptor.forClass(ContentObserver.class);
+ verify(mContentResolver)
+ .registerContentObserver(any(), anyBoolean(), observerCaptor.capture());
+ observerCaptor.getValue().onChange(/* selfChange */ false);
+ }
+
+ private void updateSmallestScreenWidth(int smallestScreenWidthDp) {
+ Configuration configuration = new Configuration();
+ configuration.smallestScreenWidthDp = smallestScreenWidthDp;
+ mConfigurationController.onConfigurationChanged(configuration);
+ }
+
private void onTouchEvent(MotionEvent ev) {
mTouchHandler.onTouch(mView, ev);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index 208790b..1a24c11 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -415,13 +415,6 @@
}
@Test
- public void onUserSwitch_setsTheme() {
- mBroadcastReceiver.getValue().onReceive(null,
- new Intent(Intent.ACTION_USER_STARTED));
- verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
- }
-
- @Test
public void onProfileAdded_setsTheme() {
mBroadcastReceiver.getValue().onReceive(null,
new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED));
diff --git a/packages/services/CameraExtensionsProxy/AndroidManifest.xml b/packages/services/CameraExtensionsProxy/AndroidManifest.xml
index e5f460e..d356894 100644
--- a/packages/services/CameraExtensionsProxy/AndroidManifest.xml
+++ b/packages/services/CameraExtensionsProxy/AndroidManifest.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.camera">
+ package="com.android.cameraextensions">
<application
android:label="@string/app_name"
diff --git a/packages/services/CameraExtensionsProxy/src/com/android/camera/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
similarity index 99%
rename from packages/services/CameraExtensionsProxy/src/com/android/camera/CameraExtensionsProxyService.java
rename to packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
index 7b9ca2d..69874f8 100644
--- a/packages/services/CameraExtensionsProxy/src/com/android/camera/CameraExtensionsProxyService.java
+++ b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.camera;
+package com.android.cameraextensions;
import android.app.Service;
import android.content.Context;
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 241a0db..f631988 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -872,18 +872,32 @@
"userId=" + userId);
}
+ final int resolvedUserId;
+ final List<AccessibilityServiceInfo> serviceInfos;
synchronized (mLock) {
// We treat calls from a profile as if made by its parent as profiles
// share the accessibility state of the parent. The call below
// performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
+ resolvedUserId = mSecurityPolicy
.resolveCallingUserIdEnforcingPermissionsLocked(userId);
-
- if (Binder.getCallingPid() == OWN_PROCESS_ID) {
- return new ArrayList<>(getUserStateLocked(resolvedUserId).mInstalledServices);
- }
- return getUserStateLocked(resolvedUserId).mInstalledServices;
+ serviceInfos = new ArrayList<>(
+ getUserStateLocked(resolvedUserId).mInstalledServices);
}
+
+ if (Binder.getCallingPid() == OWN_PROCESS_ID) {
+ return serviceInfos;
+ }
+ final PackageManagerInternal pm = LocalServices.getService(
+ PackageManagerInternal.class);
+ final int callingUid = Binder.getCallingUid();
+ for (int i = serviceInfos.size() - 1; i >= 0; i--) {
+ final AccessibilityServiceInfo serviceInfo = serviceInfos.get(i);
+ if (pm.filterAppAccess(serviceInfo.getComponentName().getPackageName(), callingUid,
+ resolvedUserId)) {
+ serviceInfos.remove(i);
+ }
+ }
+ return serviceInfos;
}
@Override
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index acbf487..5aec6aa 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -409,6 +409,8 @@
// If the set of providers has been modified, notify each active AppWidgetHost
scheduleNotifyGroupHostsForProvidersChangedLocked(userId);
+ // Possibly notify any new components of widget id changes
+ mBackupRestoreController.widgetComponentsChanged(userId);
}
}
}
@@ -2471,8 +2473,8 @@
}
@Override
- public void restoreStarting(int userId) {
- mBackupRestoreController.restoreStarting(userId);
+ public void systemRestoreStarting(int userId) {
+ mBackupRestoreController.systemRestoreStarting(userId);
}
@Override
@@ -2481,8 +2483,8 @@
}
@Override
- public void restoreFinished(int userId) {
- mBackupRestoreController.restoreFinished(userId);
+ public void systemRestoreFinished(int userId) {
+ mBackupRestoreController.systemRestoreFinished(userId);
}
@SuppressWarnings("deprecation")
@@ -4272,6 +4274,9 @@
private final HashMap<Host, ArrayList<RestoreUpdateRecord>> mUpdatesByHost =
new HashMap<>();
+ @GuardedBy("mLock")
+ private boolean mHasSystemRestoreFinished;
+
public List<String> getWidgetParticipants(int userId) {
if (DEBUG) {
Slog.i(TAG, "Getting widget participants for user: " + userId);
@@ -4375,12 +4380,13 @@
return stream.toByteArray();
}
- public void restoreStarting(int userId) {
+ public void systemRestoreStarting(int userId) {
if (DEBUG) {
- Slog.i(TAG, "Restore starting for user: " + userId);
+ Slog.i(TAG, "System restore starting for user: " + userId);
}
synchronized (mLock) {
+ mHasSystemRestoreFinished = false;
// We're starting a new "system" restore operation, so any widget restore
// state that we see from here on is intended to replace the current
// widget configuration of any/all of the affected apps.
@@ -4542,26 +4548,90 @@
}
}
- // Called once following the conclusion of a restore operation. This is when we
+ // Called once following the conclusion of a system restore operation. This is when we
// send out updates to apps involved in widget-state restore telling them about
- // the new widget ID space.
- public void restoreFinished(int userId) {
+ // the new widget ID space. Apps that are not yet installed will be notifed when they are.
+ public void systemRestoreFinished(int userId) {
if (DEBUG) {
- Slog.i(TAG, "restoreFinished for " + userId);
+ Slog.i(TAG, "systemRestoreFinished for " + userId);
+ }
+ synchronized (mLock) {
+ mHasSystemRestoreFinished = true;
+ maybeSendWidgetRestoreBroadcastsLocked(userId);
+ }
+ }
+
+ // Called when widget components (hosts or providers) are added or changed. If system
+ // restore has completed, we use this opportunity to tell the apps to update to the new
+ // widget ID space. If system restore is still in progress, we delay the updates until
+ // the end, to allow all participants to restore their state before updating widget IDs.
+ public void widgetComponentsChanged(int userId) {
+ synchronized (mLock) {
+ if (mHasSystemRestoreFinished) {
+ maybeSendWidgetRestoreBroadcastsLocked(userId);
+ }
+ }
+ }
+
+ // Called following the conclusion of a restore operation and when widget components
+ // are added or changed. This is when we send out updates to apps involved in widget-state
+ // restore telling them about the new widget ID space.
+ @GuardedBy("mLock")
+ private void maybeSendWidgetRestoreBroadcastsLocked(int userId) {
+ if (DEBUG) {
+ Slog.i(TAG, "maybeSendWidgetRestoreBroadcasts for " + userId);
}
final UserHandle userHandle = new UserHandle(userId);
- synchronized (mLock) {
- // Build the providers' broadcasts and send them off
- Set<Map.Entry<Provider, ArrayList<RestoreUpdateRecord>>> providerEntries
- = mUpdatesByProvider.entrySet();
- for (Map.Entry<Provider, ArrayList<RestoreUpdateRecord>> e : providerEntries) {
- // For each provider there's a list of affected IDs
- Provider provider = e.getKey();
+ // Build the providers' broadcasts and send them off
+ Set<Map.Entry<Provider, ArrayList<RestoreUpdateRecord>>> providerEntries
+ = mUpdatesByProvider.entrySet();
+ for (Map.Entry<Provider, ArrayList<RestoreUpdateRecord>> e : providerEntries) {
+ // For each provider there's a list of affected IDs
+ Provider provider = e.getKey();
+ if (provider.zombie) {
+ // Provider not installed, we can't send them broadcasts yet.
+ // We'll be called again when the provider is installed.
+ continue;
+ }
+ ArrayList<RestoreUpdateRecord> updates = e.getValue();
+ final int pending = countPendingUpdates(updates);
+ if (DEBUG) {
+ Slog.i(TAG, "Provider " + provider + " pending: " + pending);
+ }
+ if (pending > 0) {
+ int[] oldIds = new int[pending];
+ int[] newIds = new int[pending];
+ final int N = updates.size();
+ int nextPending = 0;
+ for (int i = 0; i < N; i++) {
+ RestoreUpdateRecord r = updates.get(i);
+ if (!r.notified) {
+ r.notified = true;
+ oldIds[nextPending] = r.oldId;
+ newIds[nextPending] = r.newId;
+ nextPending++;
+ if (DEBUG) {
+ Slog.i(TAG, " " + r.oldId + " => " + r.newId);
+ }
+ }
+ }
+ sendWidgetRestoreBroadcastLocked(
+ AppWidgetManager.ACTION_APPWIDGET_RESTORED,
+ provider, null, oldIds, newIds, userHandle);
+ }
+ }
+
+ // same thing per host
+ Set<Map.Entry<Host, ArrayList<RestoreUpdateRecord>>> hostEntries
+ = mUpdatesByHost.entrySet();
+ for (Map.Entry<Host, ArrayList<RestoreUpdateRecord>> e : hostEntries) {
+ Host host = e.getKey();
+ if (host.id.uid != UNKNOWN_UID) {
ArrayList<RestoreUpdateRecord> updates = e.getValue();
final int pending = countPendingUpdates(updates);
if (DEBUG) {
- Slog.i(TAG, "Provider " + provider + " pending: " + pending);
+ Slog.i(TAG, "Host " + host + " pending: " + pending);
}
if (pending > 0) {
int[] oldIds = new int[pending];
@@ -4581,43 +4651,8 @@
}
}
sendWidgetRestoreBroadcastLocked(
- AppWidgetManager.ACTION_APPWIDGET_RESTORED,
- provider, null, oldIds, newIds, userHandle);
- }
- }
-
- // same thing per host
- Set<Map.Entry<Host, ArrayList<RestoreUpdateRecord>>> hostEntries
- = mUpdatesByHost.entrySet();
- for (Map.Entry<Host, ArrayList<RestoreUpdateRecord>> e : hostEntries) {
- Host host = e.getKey();
- if (host.id.uid != UNKNOWN_UID) {
- ArrayList<RestoreUpdateRecord> updates = e.getValue();
- final int pending = countPendingUpdates(updates);
- if (DEBUG) {
- Slog.i(TAG, "Host " + host + " pending: " + pending);
- }
- if (pending > 0) {
- int[] oldIds = new int[pending];
- int[] newIds = new int[pending];
- final int N = updates.size();
- int nextPending = 0;
- for (int i = 0; i < N; i++) {
- RestoreUpdateRecord r = updates.get(i);
- if (!r.notified) {
- r.notified = true;
- oldIds[nextPending] = r.oldId;
- newIds[nextPending] = r.newId;
- nextPending++;
- if (DEBUG) {
- Slog.i(TAG, " " + r.oldId + " => " + r.newId);
- }
- }
- }
- sendWidgetRestoreBroadcastLocked(
- AppWidgetManager.ACTION_APPWIDGET_HOST_RESTORED,
- null, host, oldIds, newIds, userHandle);
- }
+ AppWidgetManager.ACTION_APPWIDGET_HOST_RESTORED,
+ null, host, oldIds, newIds, userHandle);
}
}
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 312cde6..de5f47d 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -662,6 +662,26 @@
return false;
}
+ /**
+ * Requests a count of saved passwords from the current service.
+ *
+ * @return {@code true} if the request succeeded
+ */
+ // Called by Shell command
+ boolean requestSavedPasswordCount(@UserIdInt int userId, @NonNull IResultReceiver receiver) {
+ enforceCallingPermissionForManagement();
+ synchronized (mLock) {
+ final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
+ if (service != null) {
+ service.requestSavedPasswordCount(receiver);
+ return true;
+ } else if (sVerbose) {
+ Slog.v(TAG, "requestSavedPasswordCount(): no service for " + userId);
+ }
+ }
+ return false;
+ }
+
private void setLoggingLevelsLocked(boolean debug, boolean verbose) {
com.android.server.autofill.Helper.sDebug = debug;
android.view.autofill.Helper.sDebug = debug;
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index a80efc4..5f2d4e8 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -76,6 +76,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.os.IResultReceiver;
import com.android.server.LocalServices;
import com.android.server.autofill.AutofillManagerService.AutofillCompatState;
import com.android.server.autofill.AutofillManagerService.DisabledInfoCache;
@@ -1181,6 +1182,15 @@
}
@GuardedBy("mLock")
+ void requestSavedPasswordCount(IResultReceiver receiver) {
+ RemoteFillService remoteService =
+ new RemoteFillService(
+ getContext(), mInfo.getServiceInfo().getComponentName(), mUserId,
+ /* callbacks= */ null, mMaster.isInstantServiceAllowed());
+ remoteService.onSavedPasswordCountRequest(receiver);
+ }
+
+ @GuardedBy("mLock")
@Nullable RemoteAugmentedAutofillService getRemoteAugmentedAutofillServiceLocked() {
if (mRemoteAugmentedAutofillService == null) {
final String serviceName = mMaster.mAugmentedAutofillResolver.getServiceName(mUserId);
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
index 68e6290..1eaa59a 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
@@ -17,6 +17,7 @@
package com.android.server.autofill;
import static android.service.autofill.AutofillFieldClassificationService.EXTRA_SCORES;
+import static android.service.autofill.AutofillService.EXTRA_RESULT;
import static com.android.server.autofill.AutofillManagerService.RECEIVER_BUNDLE_EXTRA_SESSIONS;
@@ -89,6 +90,9 @@
pw.println(" get bind-instant-service-allowed");
pw.println(" Gets whether binding to services provided by instant apps is allowed");
pw.println("");
+ pw.println(" get saved-password-count");
+ pw.println(" Gets the number of saved passwords in the current service.");
+ pw.println("");
pw.println(" set log_level [off | debug | verbose]");
pw.println(" Sets the Autofill log level.");
pw.println("");
@@ -145,6 +149,8 @@
return getBindInstantService(pw);
case "default-augmented-service-enabled":
return getDefaultAugmentedServiceEnabled(pw);
+ case "saved-password-count":
+ return getSavedPasswordCount(pw);
default:
pw.println("Invalid set: " + what);
return -1;
@@ -342,6 +348,25 @@
return 0;
}
+ private int getSavedPasswordCount(PrintWriter pw) {
+ final int userId = getNextIntArgRequired();
+ CountDownLatch latch = new CountDownLatch(1);
+ IResultReceiver resultReceiver = new IResultReceiver.Stub() {
+ @Override
+ public void send(int resultCode, Bundle resultData) {
+ pw.println("resultCode=" + resultCode);
+ if (resultCode == 0 && resultData != null) {
+ pw.println("value=" + resultData.getInt(EXTRA_RESULT));
+ }
+ latch.countDown();
+ }
+ };
+ if (mService.requestSavedPasswordCount(userId, resultReceiver)) {
+ waitForLatch(pw, latch);
+ }
+ return 0;
+ }
+
private int requestDestroy(PrintWriter pw) {
if (!isNextArgSessions(pw)) {
return -1;
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index b0755ac..94872b0 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -41,6 +41,7 @@
import com.android.internal.infra.AbstractRemoteService;
import com.android.internal.infra.ServiceConnector;
+import com.android.internal.os.IResultReceiver;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
@@ -225,6 +226,10 @@
}));
}
+ void onSavedPasswordCountRequest(IResultReceiver receiver) {
+ run(service -> service.onSavedPasswordCountRequest(receiver));
+ }
+
public void destroy() {
unbind();
}
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index 261ebe6..f07bac8 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -381,7 +381,7 @@
// If we're starting a full-system restore, set up to begin widget ID remapping
if (mIsSystemRestore) {
- AppWidgetBackupBridge.restoreStarting(mUserId);
+ AppWidgetBackupBridge.systemRestoreStarting(mUserId);
}
try {
@@ -1133,8 +1133,10 @@
restoreAgentTimeoutMillis);
}
- // Kick off any work that may be needed regarding app widget restores
- AppWidgetBackupBridge.restoreFinished(mUserId);
+ if (mIsSystemRestore) {
+ // Kick off any work that may be needed regarding app widget restores
+ AppWidgetBackupBridge.systemRestoreFinished(mUserId);
+ }
// If this was a full-system restore, record the ancestral
// dataset information
diff --git a/services/companion/java/com/android/server/companion/OWNERS b/services/companion/java/com/android/server/companion/OWNERS
index da723b3..734d8b6 100644
--- a/services/companion/java/com/android/server/companion/OWNERS
+++ b/services/companion/java/com/android/server/companion/OWNERS
@@ -1 +1 @@
-eugenesusla@google.com
\ No newline at end of file
+include /core/java/android/companion/OWNERS
\ No newline at end of file
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 9299624..f7ddd29 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -1151,6 +1151,8 @@
/**
* Deletes the OAT artifacts of a package.
+ * @param packageName a specific package
+ * @return the number of freed bytes or -1 if there was an error in the process.
*/
- public abstract void deleteOatArtifactsOfPackage(String packageName);
+ public abstract long deleteOatArtifactsOfPackage(String packageName);
}
diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java
index 26ecee8..70176a0 100644
--- a/services/core/java/com/android/server/VpnManagerService.java
+++ b/services/core/java/com/android/server/VpnManagerService.java
@@ -38,6 +38,7 @@
import android.net.VpnService;
import android.net.util.NetdService;
import android.os.Binder;
+import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.INetworkManagementService;
@@ -348,9 +349,17 @@
/**
* Start legacy VPN, controlling native daemons as needed. Creates a
* secondary thread to perform connection work, returning quickly.
+ *
+ * Legacy VPN is deprecated starting from Android S. So this API shouldn't be called if the
+ * initial SDK version of device is Android S+. Otherwise, UnsupportedOperationException will be
+ * thrown.
*/
+ @SuppressWarnings("AndroidFrameworkCompatChange") // This is not an app-visible API.
@Override
public void startLegacyVpn(VpnProfile profile) {
+ if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.S) {
+ throw new UnsupportedOperationException("Legacy VPN is deprecated");
+ }
int user = UserHandle.getUserId(mDeps.getCallingUid());
// Note that if the caller is not system (uid >= Process.FIRST_APPLICATION_UID),
// the code might not work well since getActiveNetwork might return null if the uid is
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 5e388d9..3b3febe 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -6165,8 +6165,10 @@
&& code != REASON_UID_VISIBLE;
}
- // TODO: remove this notification after feature development is done
private void showFgsBgRestrictedNotificationLocked(ServiceRecord r) {
+ if (!mAm.mConstants.mFgsStartRestrictionNotificationEnabled /* default is false */) {
+ return;
+ }
final Context context = mAm.mContext;
final String title = "Foreground Service BG-Launch Restricted";
final String content = "App restricted: " + r.mRecentCallingPackage;
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 0d19efc..445d0ba 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -198,6 +198,13 @@
"default_fgs_starts_restriction_enabled";
/**
+ * Default value for mFgsStartRestrictionNotificationEnabled if not explicitly set in
+ * Settings.Global.
+ */
+ private static final String KEY_DEFAULT_FGS_STARTS_RESTRICTION_NOTIFICATION_ENABLED =
+ "default_fgs_starts_restriction_notification_enabled";
+
+ /**
* Default value for mFgsStartRestrictionCheckCallerTargetSdk if not explicitly set in
* Settings.Global.
*/
@@ -432,6 +439,10 @@
// at all.
volatile boolean mFlagFgsStartRestrictionEnabled = true;
+ // Whether to display a notification when a service is restricted from startForeground due to
+ // foreground service background start restriction.
+ volatile boolean mFgsStartRestrictionNotificationEnabled = false;
+
/**
* Indicates whether the foreground service background start restriction is enabled for
* caller app that is targeting S+.
@@ -652,6 +663,9 @@
case KEY_DEFAULT_FGS_STARTS_RESTRICTION_ENABLED:
updateFgsStartsRestriction();
break;
+ case KEY_DEFAULT_FGS_STARTS_RESTRICTION_NOTIFICATION_ENABLED:
+ updateFgsStartsRestrictionNotification();
+ break;
case KEY_DEFAULT_FGS_STARTS_RESTRICTION_CHECK_CALLER_TARGET_SDK:
updateFgsStartsRestrictionCheckCallerTargetSdk();
break;
@@ -953,6 +967,13 @@
/*defaultValue*/ true);
}
+ private void updateFgsStartsRestrictionNotification() {
+ mFgsStartRestrictionNotificationEnabled = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_DEFAULT_FGS_STARTS_RESTRICTION_NOTIFICATION_ENABLED,
+ /*defaultValue*/ false);
+ }
+
private void updateFgsStartsRestrictionCheckCallerTargetSdk() {
mFgsStartRestrictionCheckCallerTargetSdk = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -1272,6 +1293,9 @@
pw.print("="); pw.println(mFlagBackgroundFgsStartRestrictionEnabled);
pw.print(" "); pw.print(KEY_DEFAULT_FGS_STARTS_RESTRICTION_ENABLED); pw.print("=");
pw.println(mFlagFgsStartRestrictionEnabled);
+ pw.print(" "); pw.print(KEY_DEFAULT_FGS_STARTS_RESTRICTION_NOTIFICATION_ENABLED);
+ pw.print("=");
+ pw.println(mFgsStartRestrictionNotificationEnabled);
pw.print(" "); pw.print(KEY_DEFAULT_FGS_STARTS_RESTRICTION_CHECK_CALLER_TARGET_SDK);
pw.print("="); pw.println(mFgsStartRestrictionCheckCallerTargetSdk);
pw.print(" "); pw.print(KEY_FGS_ATOM_SAMPLE_RATE);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2de091b..0c97724 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5684,6 +5684,16 @@
if (pid == MY_PID) {
return PackageManager.PERMISSION_GRANTED;
}
+ try {
+ if (uid != 0) { // bypass the root
+ final String[] packageNames = getPackageManager().getPackagesForUid(uid);
+ if (ArrayUtils.isEmpty(packageNames)) {
+ // The uid is not existed or not visible to the caller.
+ return PackageManager.PERMISSION_DENIED;
+ }
+ }
+ } catch (RemoteException e) {
+ }
return mUgmInternal.checkUriPermission(new GrantUri(userId, uri, modeFlags), uid, modeFlags)
? PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED;
}
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 966e746..317b775 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -203,8 +203,6 @@
updateMinOomAdjThrottle();
} else if (KEY_COMPACT_THROTTLE_MAX_OOM_ADJ.equals(name)) {
updateMaxOomAdjThrottle();
- } else if (KEY_FREEZER_DEBOUNCE_TIMEOUT.equals(name)) {
- updateFreezerDebounceTimeout();
}
}
}
@@ -344,7 +342,6 @@
updateUseFreezer();
updateMinOomAdjThrottle();
updateMaxOomAdjThrottle();
- updateFreezerDebounceTimeout();
}
}
@@ -656,6 +653,7 @@
|| DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
KEY_USE_FREEZER, DEFAULT_USE_FREEZER)) {
mUseFreezer = isFreezerSupported();
+ updateFreezerDebounceTimeout();
}
final boolean useFreezer = mUseFreezer;
@@ -834,7 +832,8 @@
@GuardedBy("mPhenotypeFlagLock")
private void updateFreezerDebounceTimeout() {
- mFreezerDebounceTimeout = DeviceConfig.getLong(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ mFreezerDebounceTimeout = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
KEY_FREEZER_DEBOUNCE_TIMEOUT, DEFAULT_FREEZER_DEBOUNCE_TIMEOUT);
if (mFreezerDebounceTimeout < 0) {
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index 697f6fa..ae1cd51 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -21,10 +21,18 @@
import static android.content.Intent.ACTION_PACKAGE_REMOVED;
import static com.android.server.wm.CompatModePackages.DOWNSCALED;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_30;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_35;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_40;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_45;
import static com.android.server.wm.CompatModePackages.DOWNSCALE_50;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_55;
import static com.android.server.wm.CompatModePackages.DOWNSCALE_60;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_65;
import static com.android.server.wm.CompatModePackages.DOWNSCALE_70;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_75;
import static com.android.server.wm.CompatModePackages.DOWNSCALE_80;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_85;
import static com.android.server.wm.CompatModePackages.DOWNSCALE_90;
import android.Manifest;
@@ -213,6 +221,39 @@
}
}
+ // Turn the raw string to the corresponding CompatChange id.
+ static long getCompatChangeId(String raw) {
+ switch (raw) {
+ case "0.3":
+ return DOWNSCALE_30;
+ case "0.35":
+ return DOWNSCALE_35;
+ case "0.4":
+ return DOWNSCALE_40;
+ case "0.45":
+ return DOWNSCALE_45;
+ case "0.5":
+ return DOWNSCALE_50;
+ case "0.55":
+ return DOWNSCALE_55;
+ case "0.6":
+ return DOWNSCALE_60;
+ case "0.65":
+ return DOWNSCALE_65;
+ case "0.7":
+ return DOWNSCALE_70;
+ case "0.75":
+ return DOWNSCALE_75;
+ case "0.8":
+ return DOWNSCALE_80;
+ case "0.85":
+ return DOWNSCALE_85;
+ case "0.9":
+ return DOWNSCALE_90;
+ }
+ return 0;
+ }
+
/**
* GamePackageConfiguration manages all game mode config details for its associated package.
*/
@@ -331,19 +372,7 @@
* Get the corresponding compat change id for the current scaling string.
*/
public long getCompatChangeId() {
- switch (mScaling) {
- case "0.5":
- return DOWNSCALE_50;
- case "0.6":
- return DOWNSCALE_60;
- case "0.7":
- return DOWNSCALE_70;
- case "0.8":
- return DOWNSCALE_80;
- case "0.9":
- return DOWNSCALE_90;
- }
- return 0;
+ return GameManagerService.getCompatChangeId(mScaling);
}
}
@@ -663,10 +692,18 @@
Slog.i(TAG, "Enabling downscale: " + scaleId + " for " + packageName);
final ArrayMap<Long, PackageOverride> overrides = new ArrayMap<>();
overrides.put(DOWNSCALED, COMPAT_ENABLED);
+ overrides.put(DOWNSCALE_30, COMPAT_DISABLED);
+ overrides.put(DOWNSCALE_35, COMPAT_DISABLED);
+ overrides.put(DOWNSCALE_40, COMPAT_DISABLED);
+ overrides.put(DOWNSCALE_45, COMPAT_DISABLED);
overrides.put(DOWNSCALE_50, COMPAT_DISABLED);
+ overrides.put(DOWNSCALE_55, COMPAT_DISABLED);
overrides.put(DOWNSCALE_60, COMPAT_DISABLED);
+ overrides.put(DOWNSCALE_65, COMPAT_DISABLED);
overrides.put(DOWNSCALE_70, COMPAT_DISABLED);
+ overrides.put(DOWNSCALE_75, COMPAT_DISABLED);
overrides.put(DOWNSCALE_80, COMPAT_DISABLED);
+ overrides.put(DOWNSCALE_85, COMPAT_DISABLED);
overrides.put(DOWNSCALE_90, COMPAT_DISABLED);
overrides.put(scaleId, COMPAT_ENABLED);
final CompatibilityOverrideConfig changeConfig = new CompatibilityOverrideConfig(
diff --git a/services/core/java/com/android/server/app/GameManagerShellCommand.java b/services/core/java/com/android/server/app/GameManagerShellCommand.java
index 2074ffa..699f9e2 100644
--- a/services/core/java/com/android/server/app/GameManagerShellCommand.java
+++ b/services/core/java/com/android/server/app/GameManagerShellCommand.java
@@ -16,6 +16,21 @@
package com.android.server.app;
+import static com.android.server.wm.CompatModePackages.DOWNSCALED;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_30;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_35;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_40;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_45;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_50;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_55;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_60;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_65;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_70;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_75;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_80;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_85;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_90;
+
import android.app.ActivityManager;
import android.app.GameManager;
import android.app.IGameManagerService;
@@ -27,7 +42,6 @@
import com.android.internal.compat.CompatibilityChangeConfig;
import com.android.server.compat.PlatformCompat;
-import com.android.server.wm.CompatModePackages;
import java.io.PrintWriter;
import java.util.Set;
@@ -43,12 +57,21 @@
public GameManagerShellCommand() {}
private static final ArraySet<Long> DOWNSCALE_CHANGE_IDS = new ArraySet<>(new Long[]{
- CompatModePackages.DOWNSCALED,
- CompatModePackages.DOWNSCALE_90,
- CompatModePackages.DOWNSCALE_80,
- CompatModePackages.DOWNSCALE_70,
- CompatModePackages.DOWNSCALE_60,
- CompatModePackages.DOWNSCALE_50});
+ DOWNSCALED,
+ DOWNSCALE_90,
+ DOWNSCALE_85,
+ DOWNSCALE_80,
+ DOWNSCALE_75,
+ DOWNSCALE_70,
+ DOWNSCALE_65,
+ DOWNSCALE_60,
+ DOWNSCALE_55,
+ DOWNSCALE_50,
+ DOWNSCALE_45,
+ DOWNSCALE_40,
+ DOWNSCALE_35,
+ DOWNSCALE_30,
+ });
@Override
public int onCommand(String cmd) {
@@ -62,32 +85,9 @@
final String ratio = getNextArgRequired();
final String packageName = getNextArgRequired();
- final long changeId;
- switch (ratio) {
- case "0.5":
- changeId = CompatModePackages.DOWNSCALE_50;
- break;
- case "0.6":
- changeId = CompatModePackages.DOWNSCALE_60;
- break;
- case "0.7":
- changeId = CompatModePackages.DOWNSCALE_70;
- break;
- case "0.8":
- changeId = CompatModePackages.DOWNSCALE_80;
- break;
- case "0.9":
- changeId = CompatModePackages.DOWNSCALE_90;
- break;
- case "disable":
- changeId = 0;
- break;
- default:
- changeId = -1;
- pw.println("Invalid scaling ratio '" + ratio + "'");
- break;
- }
- if (changeId == -1) {
+ final long changeId = GameManagerService.getCompatChangeId(ratio);
+ if (changeId == 0 && !ratio.equals("disable")) {
+ pw.println("Invalid scaling ratio '" + ratio + "'");
break;
}
@@ -96,10 +96,10 @@
if (changeId == 0) {
disabled = DOWNSCALE_CHANGE_IDS;
} else {
- enabled.add(CompatModePackages.DOWNSCALED);
+ enabled.add(DOWNSCALED);
enabled.add(changeId);
disabled = DOWNSCALE_CHANGE_IDS.stream()
- .filter(it -> it != CompatModePackages.DOWNSCALED && it != changeId)
+ .filter(it -> it != DOWNSCALED && it != changeId)
.collect(Collectors.toSet());
}
@@ -204,7 +204,7 @@
pw.println("Game manager (game) commands:");
pw.println(" help");
pw.println(" Print this help text.");
- pw.println(" downscale [0.5|0.6|0.7|0.8|0.9|disable] <PACKAGE_NAME>");
+ pw.println(" downscale [0.3|0.35|0.4|0.45|0.5|0.55|0.6|0.65|0.7|0.75|0.8|0.85|0.9|disable] <PACKAGE_NAME>");
pw.println(" Force app to run at the specified scaling ratio.");
pw.println(" mode [--user <USER_ID>] [1|2|3|standard|performance|battery] <PACKAGE_NAME>");
pw.println(" Force app to run in the specified game mode, if supported.");
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
index 4cb2e9b..7f1402d 100644
--- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
@@ -456,7 +456,9 @@
private void hibernatePackageGlobally(@NonNull String packageName, GlobalLevelState state) {
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackageGlobally");
if (mOatArtifactDeletionEnabled) {
- mPackageManagerInternal.deleteOatArtifactsOfPackage(packageName);
+ state.savedByte = Math.max(
+ mPackageManagerInternal.deleteOatArtifactsOfPackage(packageName),
+ 0);
}
state.hibernated = true;
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
@@ -469,6 +471,7 @@
private void unhibernatePackageGlobally(@NonNull String packageName, GlobalLevelState state) {
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "unhibernatePackageGlobally");
state.hibernated = false;
+ state.savedByte = 0;
state.lastUnhibernatedMs = System.currentTimeMillis();
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
@@ -943,6 +946,9 @@
}
private final class StatsPullAtomCallbackImpl implements StatsPullAtomCallback {
+
+ private static final int MEGABYTE_IN_BYTES = 1000000;
+
@Override
public int onPullAtom(int atomTag, @NonNull List<StatsEvent> data) {
if (!isAppHibernationEnabled()
@@ -969,12 +975,21 @@
break;
case FrameworkStatsLog.GLOBAL_HIBERNATED_APPS:
int hibernatedAppCount = 0;
+ long storage_saved_byte = 0;
synchronized (mLock) {
for (GlobalLevelState state : mGlobalHibernationStates.values()) {
- if (state.hibernated) hibernatedAppCount++;
+ if (state.hibernated) {
+ hibernatedAppCount++;
+ storage_saved_byte += state.savedByte;
+ }
}
}
- data.add(FrameworkStatsLog.buildStatsEvent(atomTag, hibernatedAppCount));
+ data.add(
+ FrameworkStatsLog.buildStatsEvent(
+ atomTag,
+ hibernatedAppCount,
+ storage_saved_byte / MEGABYTE_IN_BYTES)
+ );
break;
default:
return StatsManager.PULL_SKIP;
diff --git a/services/core/java/com/android/server/apphibernation/GlobalLevelHibernationProto.java b/services/core/java/com/android/server/apphibernation/GlobalLevelHibernationProto.java
index 79e995b..018d602 100644
--- a/services/core/java/com/android/server/apphibernation/GlobalLevelHibernationProto.java
+++ b/services/core/java/com/android/server/apphibernation/GlobalLevelHibernationProto.java
@@ -41,6 +41,7 @@
GlobalLevelState state = data.get(i);
stream.write(GlobalLevelHibernationStateProto.PACKAGE_NAME, state.packageName);
stream.write(GlobalLevelHibernationStateProto.HIBERNATED, state.hibernated);
+ stream.write(GlobalLevelHibernationStateProto.SAVED_BYTE, state.savedByte);
stream.end(token);
}
}
@@ -66,6 +67,10 @@
state.hibernated =
stream.readBoolean(GlobalLevelHibernationStateProto.HIBERNATED);
break;
+ case (int) GlobalLevelHibernationStateProto.SAVED_BYTE:
+ state.savedByte =
+ stream.readLong(GlobalLevelHibernationStateProto.SAVED_BYTE);
+ break;
default:
Slog.w(TAG, "Undefined field in proto: " + stream.getFieldNumber());
}
diff --git a/services/core/java/com/android/server/apphibernation/GlobalLevelState.java b/services/core/java/com/android/server/apphibernation/GlobalLevelState.java
index f4433a7..104ecbc 100644
--- a/services/core/java/com/android/server/apphibernation/GlobalLevelState.java
+++ b/services/core/java/com/android/server/apphibernation/GlobalLevelState.java
@@ -29,6 +29,8 @@
public String packageName;
public boolean hibernated;
+ // The number of saved bytes from the current hibernation. It will be 0 if not in hibernation.
+ public long savedByte;
@CurrentTimeMillisLong
public long lastUnhibernatedMs;
@@ -37,6 +39,7 @@
return "GlobalLevelState{"
+ "packageName='" + packageName + '\''
+ ", hibernated=" + hibernated + '\''
+ + ", savedByte=" + savedByte + '\''
+ ", lastUnhibernated=" + DATE_FORMAT.format(lastUnhibernatedMs)
+ '}';
}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 99a33e4..5ba75d3 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -19,11 +19,13 @@
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
+import static android.app.AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE;
import static android.app.AppOpsManager.CALL_BACK_ON_SWITCHED_OP;
import static android.app.AppOpsManager.FILTER_BY_ATTRIBUTION_TAG;
import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
import static android.app.AppOpsManager.FILTER_BY_PACKAGE_NAME;
import static android.app.AppOpsManager.FILTER_BY_UID;
+import static android.app.AppOpsManager.HISTORY_FLAG_GET_ATTRIBUTION_CHAINS;
import static android.app.AppOpsManager.HistoricalOpsRequestFilter;
import static android.app.AppOpsManager.KEY_BG_STATE_SETTLE_TIME;
import static android.app.AppOpsManager.KEY_FG_SERVICE_STATE_SETTLE_TIME;
@@ -130,6 +132,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManagerInternal;
+import android.permission.PermissionManager;
import android.provider.Settings;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -200,8 +203,8 @@
import java.util.Map;
import java.util.Objects;
import java.util.Scanner;
+import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
-import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
public class AppOpsService extends IAppOpsService.Stub {
@@ -2357,10 +2360,21 @@
final String[] opNamesArray = (opNames != null)
? opNames.toArray(new String[opNames.size()]) : null;
+ Set<String> attributionChainExemptPackages = null;
+ if ((dataType & HISTORY_FLAG_GET_ATTRIBUTION_CHAINS) != 0) {
+ attributionChainExemptPackages =
+ PermissionManager.getIndicatorExemptedPackages(mContext);
+ }
+
+ final String[] chainExemptPkgArray = attributionChainExemptPackages != null
+ ? attributionChainExemptPackages.toArray(
+ new String[attributionChainExemptPackages.size()]) : null;
+
// Must not hold the appops lock
mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::getHistoricalOps,
mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray, dataType,
- filter, beginTimeMillis, endTimeMillis, flags, callback).recycleOnUse());
+ filter, beginTimeMillis, endTimeMillis, flags, chainExemptPkgArray,
+ callback).recycleOnUse());
}
@Override
@@ -2377,10 +2391,21 @@
final String[] opNamesArray = (opNames != null)
? opNames.toArray(new String[opNames.size()]) : null;
+ Set<String> attributionChainExemptPackages = null;
+ if ((dataType & HISTORY_FLAG_GET_ATTRIBUTION_CHAINS) != 0) {
+ attributionChainExemptPackages =
+ PermissionManager.getIndicatorExemptedPackages(mContext);
+ }
+
+ final String[] chainExemptPkgArray = attributionChainExemptPackages != null
+ ? attributionChainExemptPackages.toArray(
+ new String[attributionChainExemptPackages.size()]) : null;
+
// Must not hold the appops lock
mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::getHistoricalOpsFromDiskRaw,
mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray, dataType,
- filter, beginTimeMillis, endTimeMillis, flags, callback).recycleOnUse());
+ filter, beginTimeMillis, endTimeMillis, flags, chainExemptPkgArray,
+ callback).recycleOnUse());
}
@Override
@@ -3838,7 +3863,8 @@
final boolean isSelfBlame = Binder.getCallingUid() == proxiedUid;
final boolean isProxyTrusted = mContext.checkPermission(
Manifest.permission.UPDATE_APP_OPS_STATS, -1, proxyUid)
- == PackageManager.PERMISSION_GRANTED || isSelfBlame;
+ == PackageManager.PERMISSION_GRANTED || isSelfBlame
+ || attributionChainId != ATTRIBUTION_CHAIN_ID_NONE;
String resolvedProxiedPackageName = AppOpsManager.resolvePackageName(proxiedUid,
proxiedPackageName);
@@ -5174,8 +5200,6 @@
}
static class Shell extends ShellCommand {
- static final AtomicInteger sAttributionChainIds = new AtomicInteger(0);
-
final IAppOpsService mInterface;
final AppOpsService mInternal;
@@ -5645,8 +5669,7 @@
shell.mInterface.startOperation(shell.mToken, shell.op, shell.packageUid,
shell.packageName, shell.attributionTag, true, true,
"appops start shell command", true,
- AppOpsManager.ATTRIBUTION_FLAG_ACCESSOR,
- shell.sAttributionChainIds.incrementAndGet());
+ AppOpsManager.ATTRIBUTION_FLAG_ACCESSOR, ATTRIBUTION_CHAIN_ID_NONE);
} else {
return -1;
}
diff --git a/services/core/java/com/android/server/appop/DiscreteRegistry.java b/services/core/java/com/android/server/appop/DiscreteRegistry.java
index 49469cc..0439660 100644
--- a/services/core/java/com/android/server/appop/DiscreteRegistry.java
+++ b/services/core/java/com/android/server/appop/DiscreteRegistry.java
@@ -16,6 +16,9 @@
package com.android.server.appop;
+import static android.app.AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE;
+import static android.app.AppOpsManager.ATTRIBUTION_FLAG_ACCESSOR;
+import static android.app.AppOpsManager.ATTRIBUTION_FLAG_RECEIVER;
import static android.app.AppOpsManager.FILTER_BY_ATTRIBUTION_TAG;
import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
import static android.app.AppOpsManager.FILTER_BY_PACKAGE_NAME;
@@ -58,7 +61,9 @@
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
+import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.time.Duration;
@@ -69,6 +74,8 @@
import java.util.Collections;
import java.util.Date;
import java.util.List;
+import java.util.Objects;
+import java.util.Set;
/**
* This class manages information about recent accesses to ops for permission usage timeline.
@@ -138,6 +145,7 @@
private static final String TAG_HISTORY = "h";
private static final String ATTR_VERSION = "v";
+ private static final String ATTR_LARGEST_CHAIN_ID = "lc";
private static final int CURRENT_VERSION = 1;
private static final String TAG_UID = "u";
@@ -182,6 +190,16 @@
DiscreteRegistry(Object inMemoryLock) {
mInMemoryLock = inMemoryLock;
+ synchronized (mOnDiskLock) {
+ mDiscreteAccessDir = new File(
+ new File(Environment.getDataSystemDirectory(), "appops"),
+ "discrete");
+ createDiscreteAccessDirLocked();
+ int largestChainId = readLargestChainIdFromDiskLocked();
+ synchronized (mInMemoryLock) {
+ mDiscreteOps = new DiscreteOps(largestChainId);
+ }
+ }
}
void systemReady() {
@@ -190,15 +208,6 @@
setDiscreteHistoryParameters(p);
});
setDiscreteHistoryParameters(DeviceConfig.getProperties(DeviceConfig.NAMESPACE_PRIVACY));
- synchronized (mOnDiskLock) {
- synchronized (mInMemoryLock) {
- mDiscreteAccessDir = new File(
- new File(Environment.getDataSystemDirectory(), "appops"),
- "discrete");
- createDiscreteAccessDirLocked();
- mDiscreteOps = new DiscreteOps();
- }
- }
}
private void setDiscreteHistoryParameters(DeviceConfig.Properties p) {
@@ -251,7 +260,7 @@
DiscreteOps discreteOps;
synchronized (mInMemoryLock) {
discreteOps = mDiscreteOps;
- mDiscreteOps = new DiscreteOps();
+ mDiscreteOps = new DiscreteOps(discreteOps.mChainIdOffset);
mCachedOps = null;
}
deleteOldDiscreteHistoryFilesLocked();
@@ -265,16 +274,109 @@
long beginTimeMillis, long endTimeMillis,
@AppOpsManager.HistoricalOpsRequestFilter int filter, int uidFilter,
@Nullable String packageNameFilter, @Nullable String[] opNamesFilter,
- @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
+ @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter,
+ Set<String> attributionExemptPkgs) {
+ boolean assembleChains = attributionExemptPkgs != null;
DiscreteOps discreteOps = getAllDiscreteOps();
+ ArrayMap<Integer, AttributionChain> attributionChains = new ArrayMap<>();
+ if (assembleChains) {
+ attributionChains = createAttributionChains(discreteOps, attributionExemptPkgs);
+ }
beginTimeMillis = max(beginTimeMillis, Instant.now().minus(sDiscreteHistoryCutoff,
ChronoUnit.MILLIS).toEpochMilli());
discreteOps.filter(beginTimeMillis, endTimeMillis, filter, uidFilter, packageNameFilter,
- opNamesFilter, attributionTagFilter, flagsFilter);
- discreteOps.applyToHistoricalOps(result);
+ opNamesFilter, attributionTagFilter, flagsFilter, attributionChains);
+ discreteOps.applyToHistoricalOps(result, attributionChains);
return;
}
+ private int readLargestChainIdFromDiskLocked() {
+ final File[] files = mDiscreteAccessDir.listFiles();
+ if (files != null && files.length > 0) {
+ File latestFile = null;
+ long latestFileTimestamp = 0;
+ for (File f : files) {
+ final String fileName = f.getName();
+ if (!fileName.endsWith(DISCRETE_HISTORY_FILE_SUFFIX)) {
+ continue;
+ }
+ long timestamp = Long.valueOf(fileName.substring(0,
+ fileName.length() - DISCRETE_HISTORY_FILE_SUFFIX.length()));
+ if (latestFileTimestamp < timestamp) {
+ latestFile = f;
+ latestFileTimestamp = timestamp;
+ }
+ }
+ if (latestFile == null) {
+ return 0;
+ }
+ FileInputStream stream;
+ try {
+ stream = new FileInputStream(latestFile);
+ } catch (FileNotFoundException e) {
+ return 0;
+ }
+ try {
+ TypedXmlPullParser parser = Xml.resolvePullParser(stream);
+ XmlUtils.beginDocument(parser, TAG_HISTORY);
+
+ final int largestChainId = parser.getAttributeInt(null, ATTR_LARGEST_CHAIN_ID, 0);
+ return largestChainId;
+ } catch (Throwable t) {
+ return 0;
+ } finally {
+ try {
+ stream.close();
+ } catch (IOException e) {
+ }
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ private ArrayMap<Integer, AttributionChain> createAttributionChains(
+ DiscreteOps discreteOps, Set<String> attributionExemptPkgs) {
+ ArrayMap<Integer, AttributionChain> chains = new ArrayMap<>();
+ int nUids = discreteOps.mUids.size();
+ for (int uidNum = 0; uidNum < nUids; uidNum++) {
+ ArrayMap<String, DiscretePackageOps> pkgs = discreteOps.mUids.valueAt(uidNum).mPackages;
+ int uid = discreteOps.mUids.keyAt(uidNum);
+ int nPackages = pkgs.size();
+ for (int pkgNum = 0; pkgNum < nPackages; pkgNum++) {
+ ArrayMap<Integer, DiscreteOp> ops = pkgs.valueAt(pkgNum).mPackageOps;
+ String pkg = pkgs.keyAt(pkgNum);
+ int nOps = ops.size();
+ for (int opNum = 0; opNum < nOps; opNum++) {
+ ArrayMap<String, List<DiscreteOpEvent>> attrOps =
+ ops.valueAt(opNum).mAttributedOps;
+ int op = ops.keyAt(opNum);
+ int nAttrOps = attrOps.size();
+ for (int attrOpNum = 0; attrOpNum < nAttrOps; attrOpNum++) {
+ List<DiscreteOpEvent> opEvents = attrOps.valueAt(attrOpNum);
+ String attributionTag = attrOps.keyAt(attrOpNum);
+ int nOpEvents = opEvents.size();
+ for (int opEventNum = 0; opEventNum < nOpEvents; opEventNum++) {
+ DiscreteOpEvent event = opEvents.get(opEventNum);
+ if (event == null
+ || event.mAttributionChainId == ATTRIBUTION_CHAIN_ID_NONE) {
+ continue;
+ }
+
+ if (!chains.containsKey(event.mAttributionChainId)) {
+ chains.put(event.mAttributionChainId,
+ new AttributionChain(attributionExemptPkgs));
+ }
+ chains.get(event.mAttributionChainId)
+ .addEvent(pkg, uid, attributionTag, op, event);
+ }
+ }
+ }
+ }
+ }
+ return chains;
+ }
+
private void readDiscreteOpsFromDisk(DiscreteOps discreteOps) {
synchronized (mOnDiskLock) {
long beginTimeMillis = Instant.now().minus(sDiscreteHistoryCutoff,
@@ -301,7 +403,7 @@
void clearHistory() {
synchronized (mOnDiskLock) {
synchronized (mInMemoryLock) {
- mDiscreteOps = new DiscreteOps();
+ mDiscreteOps = new DiscreteOps(0);
}
clearOnDiskHistoryLocked();
}
@@ -340,7 +442,11 @@
String[] opNamesFilter = dumpOp == OP_NONE ? null
: new String[]{AppOpsManager.opToPublicName(dumpOp)};
discreteOps.filter(0, Instant.now().toEpochMilli(), filter, uidFilter, packageNameFilter,
- opNamesFilter, attributionTagFilter, OP_FLAGS_ALL);
+ opNamesFilter, attributionTagFilter, OP_FLAGS_ALL, new ArrayMap<>());
+ pw.print(prefix);
+ pw.print("Largest chain id: ");
+ pw.print(mDiscreteOps.mLargestChainId);
+ pw.println();
discreteOps.dump(pw, sdf, date, prefix, nDiscreteOps);
}
@@ -351,14 +457,14 @@
}
private DiscreteOps getAllDiscreteOps() {
- DiscreteOps discreteOps = new DiscreteOps();
+ DiscreteOps discreteOps = new DiscreteOps(0);
synchronized (mOnDiskLock) {
synchronized (mInMemoryLock) {
discreteOps.merge(mDiscreteOps);
}
if (mCachedOps == null) {
- mCachedOps = new DiscreteOps();
+ mCachedOps = new DiscreteOps(0);
readDiscreteOpsFromDisk(mCachedOps);
}
discreteOps.merge(mCachedOps);
@@ -366,11 +472,143 @@
}
}
+ /**
+ * Represents a chain of usages, each attributing its usage to the one before it
+ */
+ private static final class AttributionChain {
+ private static final class OpEvent {
+ String mPkgName;
+ int mUid;
+ String mAttributionTag;
+ int mOpCode;
+ DiscreteOpEvent mOpEvent;
+
+ OpEvent(String pkgName, int uid, String attributionTag, int opCode,
+ DiscreteOpEvent event) {
+ mPkgName = pkgName;
+ mUid = uid;
+ mAttributionTag = attributionTag;
+ mOpCode = opCode;
+ mOpEvent = event;
+ }
+
+ public boolean matches(String pkgName, int uid, String attributionTag, int opCode,
+ DiscreteOpEvent event) {
+ return Objects.equals(pkgName, mPkgName) && mUid == uid
+ && Objects.equals(attributionTag, mAttributionTag) && mOpCode == opCode
+ && mOpEvent.mAttributionChainId == event.mAttributionChainId
+ && mOpEvent.mAttributionFlags == event.mAttributionFlags
+ && mOpEvent.mNoteTime == event.mNoteTime;
+ }
+
+ public boolean packageOpEquals(OpEvent other) {
+ return Objects.equals(other.mPkgName, mPkgName) && other.mUid == mUid
+ && Objects.equals(other.mAttributionTag, mAttributionTag)
+ && mOpCode == other.mOpCode;
+ }
+
+ public boolean equalsExceptDuration(OpEvent other) {
+ if (other.mOpEvent.mNoteDuration == mOpEvent.mNoteDuration) {
+ return false;
+ }
+ return packageOpEquals(other) && mOpEvent.equalsExceptDuration(other.mOpEvent);
+ }
+ }
+
+ ArrayList<OpEvent> mChain = new ArrayList<>();
+ Set<String> mExemptPkgs;
+ OpEvent mStartEvent = null;
+ OpEvent mLastVisibleEvent = null;
+
+ AttributionChain(Set<String> exemptPkgs) {
+ mExemptPkgs = exemptPkgs;
+ }
+
+ boolean isComplete() {
+ return !mChain.isEmpty() && getStart() != null && isEnd(mChain.get(mChain.size() - 1));
+ }
+
+ boolean isStart(String pkgName, int uid, String attributionTag, int op,
+ DiscreteOpEvent opEvent) {
+ if (mStartEvent == null || opEvent == null) {
+ return false;
+ }
+ return mStartEvent.matches(pkgName, uid, attributionTag, op, opEvent);
+ }
+
+ private OpEvent getStart() {
+ return mChain.isEmpty() || !isStart(mChain.get(0)) ? null : mChain.get(0);
+ }
+
+ private OpEvent getLastVisible() {
+ // Search all nodes but the first one, which is the start node
+ for (int i = mChain.size() - 1; i > 0; i--) {
+ OpEvent event = mChain.get(i);
+ if (!mExemptPkgs.contains(event.mPkgName)) {
+ return event;
+ }
+ }
+ return null;
+ }
+
+ void addEvent(String pkgName, int uid, String attributionTag, int op,
+ DiscreteOpEvent opEvent) {
+ OpEvent event = new OpEvent(pkgName, uid, attributionTag, op, opEvent);
+
+ // check if we have a matching event, without duration, replacing duration otherwise
+ for (int i = 0; i < mChain.size(); i++) {
+ OpEvent item = mChain.get(i);
+ if (item.equalsExceptDuration(event)) {
+ if (event.mOpEvent.mNoteDuration != -1) {
+ item.mOpEvent = event.mOpEvent;
+ }
+ return;
+ }
+ }
+
+ if (mChain.isEmpty() || isEnd(event)) {
+ mChain.add(event);
+ } else if (isStart(event)) {
+ mChain.add(0, event);
+
+ } else {
+ for (int i = 0; i < mChain.size(); i++) {
+ OpEvent currEvent = mChain.get(i);
+ if ((!isStart(currEvent)
+ && currEvent.mOpEvent.mNoteTime > event.mOpEvent.mNoteTime)
+ || i == mChain.size() - 1 && isEnd(currEvent)) {
+ mChain.add(i, event);
+ break;
+ } else if (i == mChain.size() - 1) {
+ mChain.add(event);
+ break;
+ }
+ }
+ }
+ mStartEvent = isComplete() ? getStart() : null;
+ mLastVisibleEvent = isComplete() ? getLastVisible() : null;
+ }
+
+ private boolean isEnd(OpEvent event) {
+ return event != null
+ && (event.mOpEvent.mAttributionFlags & ATTRIBUTION_FLAG_ACCESSOR) != 0;
+ }
+
+ private boolean isStart(OpEvent event) {
+ return event != null
+ && (event.mOpEvent.mAttributionFlags & ATTRIBUTION_FLAG_RECEIVER) != 0;
+ }
+ }
+
private final class DiscreteOps {
ArrayMap<Integer, DiscreteUidOps> mUids;
+ int mChainIdOffset;
+ int mLargestChainId;
- DiscreteOps() {
+ DiscreteOps(int chainIdOffset) {
mUids = new ArrayMap<>();
+ mChainIdOffset = chainIdOffset;
+ mLargestChainId = chainIdOffset;
}
boolean isEmpty() {
@@ -378,6 +616,7 @@
}
void merge(DiscreteOps other) {
+ mLargestChainId = max(mLargestChainId, other.mLargestChainId);
int nUids = other.mUids.size();
for (int i = 0; i < nUids; i++) {
int uid = other.mUids.keyAt(i);
@@ -390,14 +629,27 @@
@Nullable String attributionTag, @AppOpsManager.OpFlags int flags,
@AppOpsManager.UidState int uidState, long accessTime, long accessDuration,
@AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId) {
+ int offsetChainId = attributionChainId;
+ if (attributionChainId != ATTRIBUTION_CHAIN_ID_NONE) {
+ offsetChainId = attributionChainId + mChainIdOffset;
+ if (offsetChainId > mLargestChainId) {
+ mLargestChainId = offsetChainId;
+ } else if (offsetChainId < 0) {
+ // handle overflow
+ offsetChainId = 0;
+ mLargestChainId = 0;
+ mChainIdOffset = -1 * attributionChainId;
+ }
+ }
getOrCreateDiscreteUidOps(uid).addDiscreteAccess(op, packageName, attributionTag, flags,
- uidState, accessTime, accessDuration, attributionFlags, attributionChainId);
+ uidState, accessTime, accessDuration, attributionFlags, offsetChainId);
}
private void filter(long beginTimeMillis, long endTimeMillis,
@AppOpsManager.HistoricalOpsRequestFilter int filter, int uidFilter,
@Nullable String packageNameFilter, @Nullable String[] opNamesFilter,
- @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
+ @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter,
+ ArrayMap<Integer, AttributionChain> attributionChains) {
if ((filter & FILTER_BY_UID) != 0) {
ArrayMap<Integer, DiscreteUidOps> uids = new ArrayMap<>();
uids.put(uidFilter, getOrCreateDiscreteUidOps(uidFilter));
@@ -406,7 +658,8 @@
int nUids = mUids.size();
for (int i = nUids - 1; i >= 0; i--) {
mUids.valueAt(i).filter(beginTimeMillis, endTimeMillis, filter, packageNameFilter,
- opNamesFilter, attributionTagFilter, flagsFilter);
+ opNamesFilter, attributionTagFilter, flagsFilter, mUids.keyAt(i),
+ attributionChains);
if (mUids.valueAt(i).isEmpty()) {
mUids.removeAt(i);
}
@@ -429,10 +682,11 @@
}
}
- private void applyToHistoricalOps(AppOpsManager.HistoricalOps result) {
+ private void applyToHistoricalOps(AppOpsManager.HistoricalOps result,
+ ArrayMap<Integer, AttributionChain> attributionChains) {
int nUids = mUids.size();
for (int i = 0; i < nUids; i++) {
- mUids.valueAt(i).applyToHistory(result, mUids.keyAt(i));
+ mUids.valueAt(i).applyToHistory(result, mUids.keyAt(i), attributionChains);
}
}
@@ -442,6 +696,7 @@
out.startDocument(null, true);
out.startTag(null, TAG_HISTORY);
out.attributeInt(null, ATTR_VERSION, CURRENT_VERSION);
+ out.attributeInt(null, ATTR_LARGEST_CHAIN_ID, mLargestChainId);
int nUids = mUids.size();
for (int i = 0; i < nUids; i++) {
@@ -476,8 +731,13 @@
}
private void readFromFile(File f, long beginTimeMillis) {
+ FileInputStream stream;
try {
- FileInputStream stream = new FileInputStream(f);
+ stream = new FileInputStream(f);
+ } catch (FileNotFoundException e) {
+ return;
+ }
+ try {
TypedXmlPullParser parser = Xml.resolvePullParser(stream);
XmlUtils.beginDocument(parser, TAG_HISTORY);
@@ -487,7 +747,6 @@
if (version != CURRENT_VERSION) {
throw new IllegalStateException("Dropping unsupported discrete history " + f);
}
-
int depth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, depth)) {
if (TAG_UID.equals(parser.getName())) {
@@ -498,8 +757,12 @@
} catch (Throwable t) {
Slog.e(TAG, "Failed to read file " + f.getName() + " " + t.getMessage() + " "
+ Arrays.toString(t.getStackTrace()));
+ } finally {
+ try {
+ stream.close();
+ } catch (IOException e) {
+ }
}
-
}
}
@@ -590,7 +853,8 @@
private void filter(long beginTimeMillis, long endTimeMillis,
@AppOpsManager.HistoricalOpsRequestFilter int filter,
@Nullable String packageNameFilter, @Nullable String[] opNamesFilter,
- @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
+ @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter,
+ int currentUid, ArrayMap<Integer, AttributionChain> attributionChains) {
if ((filter & FILTER_BY_PACKAGE_NAME) != 0) {
ArrayMap<String, DiscretePackageOps> packages = new ArrayMap<>();
packages.put(packageNameFilter, getOrCreateDiscretePackageOps(packageNameFilter));
@@ -599,7 +863,8 @@
int nPackages = mPackages.size();
for (int i = nPackages - 1; i >= 0; i--) {
mPackages.valueAt(i).filter(beginTimeMillis, endTimeMillis, filter, opNamesFilter,
- attributionTagFilter, flagsFilter);
+ attributionTagFilter, flagsFilter, currentUid, mPackages.keyAt(i),
+ attributionChains);
if (mPackages.valueAt(i).isEmpty()) {
mPackages.removeAt(i);
}
@@ -634,10 +899,12 @@
return result;
}
- private void applyToHistory(AppOpsManager.HistoricalOps result, int uid) {
+ private void applyToHistory(AppOpsManager.HistoricalOps result, int uid,
+ @NonNull ArrayMap<Integer, AttributionChain> attributionChains) {
int nPackages = mPackages.size();
for (int i = 0; i < nPackages; i++) {
- mPackages.valueAt(i).applyToHistory(result, uid, mPackages.keyAt(i));
+ mPackages.valueAt(i).applyToHistory(result, uid, mPackages.keyAt(i),
+ attributionChains);
}
}
@@ -705,7 +972,8 @@
private void filter(long beginTimeMillis, long endTimeMillis,
@AppOpsManager.HistoricalOpsRequestFilter int filter,
@Nullable String[] opNamesFilter, @Nullable String attributionTagFilter,
- @AppOpsManager.OpFlags int flagsFilter) {
+ @AppOpsManager.OpFlags int flagsFilter, int currentUid, String currentPkgName,
+ ArrayMap<Integer, AttributionChain> attributionChains) {
int nOps = mPackageOps.size();
for (int i = nOps - 1; i >= 0; i--) {
int opId = mPackageOps.keyAt(i);
@@ -715,7 +983,8 @@
continue;
}
mPackageOps.valueAt(i).filter(beginTimeMillis, endTimeMillis, filter,
- attributionTagFilter, flagsFilter);
+ attributionTagFilter, flagsFilter, currentUid, currentPkgName,
+ mPackageOps.keyAt(i), attributionChains);
if (mPackageOps.valueAt(i).isEmpty()) {
mPackageOps.removeAt(i);
}
@@ -739,11 +1008,12 @@
}
private void applyToHistory(AppOpsManager.HistoricalOps result, int uid,
- @NonNull String packageName) {
+ @NonNull String packageName,
+ @NonNull ArrayMap<Integer, AttributionChain> attributionChains) {
int nPackageOps = mPackageOps.size();
for (int i = 0; i < nPackageOps; i++) {
mPackageOps.valueAt(i).applyToHistory(result, uid, packageName,
- mPackageOps.keyAt(i));
+ mPackageOps.keyAt(i), attributionChains);
}
}
@@ -802,7 +1072,9 @@
private void filter(long beginTimeMillis, long endTimeMillis,
@AppOpsManager.HistoricalOpsRequestFilter int filter,
- @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
+ @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter,
+ int currentUid, String currentPkgName, int currentOp,
+ ArrayMap<Integer, AttributionChain> attributionChains) {
if ((filter & FILTER_BY_ATTRIBUTION_TAG) != 0) {
ArrayMap<String, List<DiscreteOpEvent>> attributedOps = new ArrayMap<>();
attributedOps.put(attributionTagFilter,
@@ -814,7 +1086,9 @@
for (int i = nTags - 1; i >= 0; i--) {
String tag = mAttributedOps.keyAt(i);
List<DiscreteOpEvent> list = mAttributedOps.valueAt(i);
- list = filterEventsList(list, beginTimeMillis, endTimeMillis, flagsFilter);
+ list = filterEventsList(list, beginTimeMillis, endTimeMillis, flagsFilter,
+ currentUid, currentPkgName, currentOp, mAttributedOps.keyAt(i),
+ attributionChains);
mAttributedOps.put(tag, list);
if (list.size() == 0) {
mAttributedOps.removeAt(i);
@@ -876,7 +1150,8 @@
}
private void applyToHistory(AppOpsManager.HistoricalOps result, int uid,
- @NonNull String packageName, int op) {
+ @NonNull String packageName, int op,
+ @NonNull ArrayMap<Integer, AttributionChain> attributionChains) {
int nOps = mAttributedOps.size();
for (int i = 0; i < nOps; i++) {
String tag = mAttributedOps.keyAt(i);
@@ -884,9 +1159,21 @@
int nEvents = events.size();
for (int j = 0; j < nEvents; j++) {
DiscreteOpEvent event = events.get(j);
+ AppOpsManager.OpEventProxyInfo proxy = null;
+ if (event.mAttributionChainId != ATTRIBUTION_CHAIN_ID_NONE
+ && attributionChains != null) {
+ AttributionChain chain = attributionChains.get(event.mAttributionChainId);
+ if (chain != null && chain.isComplete()
+ && chain.isStart(packageName, uid, tag, op, event)
+ && chain.mLastVisibleEvent != null) {
+ AttributionChain.OpEvent proxyEvent = chain.mLastVisibleEvent;
+ proxy = new AppOpsManager.OpEventProxyInfo(proxyEvent.mUid,
+ proxyEvent.mPkgName, proxyEvent.mAttributionTag);
+ }
+ }
result.addDiscreteAccess(op, uid, packageName, tag, event.mUidState,
event.mOpFlag, discretizeTimeStamp(event.mNoteTime),
- discretizeDuration(event.mNoteDuration));
+ discretizeDuration(event.mNoteDuration), proxy);
}
}
}
@@ -981,6 +1268,13 @@
mAttributionChainId = attributionChainId;
}
+ public boolean equalsExceptDuration(DiscreteOpEvent o) {
+ return mNoteTime == o.mNoteTime && mUidState == o.mUidState && mOpFlag == o.mOpFlag
+ && mAttributionFlags == o.mAttributionFlags
+ && mAttributionChainId == o.mAttributionChainId;
+
+ }
+
private void dump(@NonNull PrintWriter pw, @NonNull SimpleDateFormat sdf,
@NonNull Date date, @NonNull String prefix) {
pw.print(prefix);
@@ -1063,11 +1357,20 @@
}
private static List<DiscreteOpEvent> filterEventsList(List<DiscreteOpEvent> list,
- long beginTimeMillis, long endTimeMillis, @AppOpsManager.OpFlags int flagsFilter) {
+ long beginTimeMillis, long endTimeMillis, @AppOpsManager.OpFlags int flagsFilter,
+ int currentUid, String currentPackageName, int currentOp, String currentAttrTag,
+ ArrayMap<Integer, AttributionChain> attributionChains) {
int n = list.size();
List<DiscreteOpEvent> result = new ArrayList<>(n);
for (int i = 0; i < n; i++) {
DiscreteOpEvent event = list.get(i);
+ AttributionChain chain = attributionChains.get(event.mAttributionChainId);
+ // If we have an attribution chain, and this event isn't the beginning node, remove it
+ if (chain != null && !chain.isStart(currentPackageName, currentUid, currentAttrTag,
+ currentOp, event) && chain.isComplete()
+ && event.mAttributionChainId != ATTRIBUTION_CHAIN_ID_NONE) {
+ continue;
+ }
if ((event.mOpFlag & flagsFilter) != 0
&& event.mNoteTime + event.mNoteDuration > beginTimeMillis
&& event.mNoteTime < endTimeMillis) {
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index dd5df50..2c68aaf 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -209,6 +209,7 @@
mMode = other.mMode;
mBaseSnapshotInterval = other.mBaseSnapshotInterval;
mIntervalCompressionMultiplier = other.mIntervalCompressionMultiplier;
+ mDiscreteRegistry = other.mDiscreteRegistry;
}
void systemReady(@NonNull ContentResolver resolver) {
@@ -369,7 +370,7 @@
@Nullable String attributionTag, @Nullable String[] opNames,
@OpHistoryFlags int historyFlags, @HistoricalOpsRequestFilter int filter,
long beginTimeMillis, long endTimeMillis, @OpFlags int flags,
- @NonNull RemoteCallback callback) {
+ String[] attributionExemptedPackages, @NonNull RemoteCallback callback) {
if (!isApiEnabled()) {
callback.sendResult(new Bundle());
return;
@@ -395,7 +396,7 @@
if ((historyFlags & HISTORY_FLAG_DISCRETE) != 0) {
mDiscreteRegistry.addFilteredDiscreteOpsToHistoricalOps(result, beginTimeMillis,
endTimeMillis, filter, uid, packageName, opNames, attributionTag,
- flags);
+ flags, new ArraySet<>(attributionExemptedPackages));
}
final Bundle payload = new Bundle();
@@ -406,7 +407,8 @@
void getHistoricalOps(int uid, @Nullable String packageName, @Nullable String attributionTag,
@Nullable String[] opNames, @OpHistoryFlags int historyFlags,
@HistoricalOpsRequestFilter int filter, long beginTimeMillis, long endTimeMillis,
- @OpFlags int flags, @NonNull RemoteCallback callback) {
+ @OpFlags int flags, @Nullable String[] attributionExemptPkgs,
+ @NonNull RemoteCallback callback) {
if (!isApiEnabled()) {
callback.sendResult(new Bundle());
return;
@@ -428,7 +430,8 @@
if ((historyFlags & HISTORY_FLAG_DISCRETE) != 0) {
mDiscreteRegistry.addFilteredDiscreteOpsToHistoricalOps(result, beginTimeMillis,
- endTimeMillis, filter, uid, packageName, opNames, attributionTag, flags);
+ endTimeMillis, filter, uid, packageName, opNames, attributionTag, flags,
+ new ArraySet<>(attributionExemptPkgs));
}
if ((historyFlags & HISTORY_FLAG_AGGREGATE) != 0) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
index a5bb0f4..0981f18 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
@@ -866,7 +866,7 @@
private void scheduleUpdateActiveUserWithoutHandler(int targetUserId) {
final boolean hasEnrolled = !getEnrolledFaces(mSensorId, targetUserId).isEmpty();
final FaceUpdateActiveUserClient client = new FaceUpdateActiveUserClient(mContext,
- mLazyDaemon, targetUserId, mContext.getOpPackageName(), mSensorId, mCurrentUserId,
+ mLazyDaemon, targetUserId, mContext.getOpPackageName(), mSensorId,
hasEnrolled, mAuthenticatorIds);
mScheduler.scheduleClientMonitor(client, new BaseClientMonitor.Callback() {
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java
index 70e2033..5343d0d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java
@@ -34,38 +34,23 @@
private static final String TAG = "FaceUpdateActiveUserClient";
private static final String FACE_DATA_DIR = "facedata";
- private final int mCurrentUserId;
private final boolean mHasEnrolledBiometrics;
@NonNull private final Map<Integer, Long> mAuthenticatorIds;
FaceUpdateActiveUserClient(@NonNull Context context,
- @NonNull LazyDaemon<IBiometricsFace> lazyDaemon, int userId, @NonNull String owner,
- int sensorId, int currentUserId, boolean hasEnrolledBIometrics,
+ @NonNull LazyDaemon<IBiometricsFace> lazyDaemon, int userId, @NonNull String owner,
+ int sensorId, boolean hasEnrolledBiometrics,
@NonNull Map<Integer, Long> authenticatorIds) {
super(context, lazyDaemon, null /* token */, null /* listener */, userId, owner,
0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN,
BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
- mCurrentUserId = currentUserId;
- mHasEnrolledBiometrics = hasEnrolledBIometrics;
+ mHasEnrolledBiometrics = hasEnrolledBiometrics;
mAuthenticatorIds = authenticatorIds;
}
@Override
public void start(@NonNull Callback callback) {
super.start(callback);
-
- if (mCurrentUserId == getTargetUserId()) {
- Slog.d(TAG, "Already user: " + mCurrentUserId + ", refreshing authenticatorId");
- try {
- mAuthenticatorIds.put(getTargetUserId(), mHasEnrolledBiometrics
- ? getFreshDaemon().getAuthenticatorId().value : 0L);
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to refresh authenticatorId", e);
- }
- callback.onClientFinished(this, true /* success */);
- return;
- }
-
startHalOperation();
}
@@ -85,7 +70,10 @@
}
try {
- getFreshDaemon().setActiveUser(getTargetUserId(), storePath.getAbsolutePath());
+ final IBiometricsFace daemon = getFreshDaemon();
+ daemon.setActiveUser(getTargetUserId(), storePath.getAbsolutePath());
+ mAuthenticatorIds.put(getTargetUserId(),
+ mHasEnrolledBiometrics ? daemon.getAuthenticatorId().value : 0L);
mCallback.onClientFinished(this, true /* success */);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to setActiveUser: " + e);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlConversionUtils.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlConversionUtils.java
index f1f9456..0ae2e38 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlConversionUtils.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlConversionUtils.java
@@ -80,8 +80,7 @@
// No framework constant available
return BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_UNKNOWN;
} else if (aidlAcquiredInfo == AcquiredInfo.IMMOBILE) {
- // No framework constant available
- return BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_UNKNOWN;
+ return BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_IMMOBILE;
} else if (aidlAcquiredInfo == AcquiredInfo.RETRYING_CAPTURE) {
// No framework constant available
return BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_UNKNOWN;
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index c237535..de6e494 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -603,6 +603,10 @@
try (InputStream in = new BufferedInputStream(new FileInputStream(overridesFile))) {
Overrides overrides = com.android.server.compat.overrides.XmlParser.read(in);
+ if (overrides == null) {
+ Slog.w(TAG, "Parsing " + overridesFile.getPath() + " failed");
+ return;
+ }
for (ChangeOverrides changeOverrides : overrides.getChangeOverrides()) {
long changeId = changeOverrides.getChangeId();
CompatChange compatChange = mChanges.get(changeId);
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 19e858c..0d317f4 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -36,6 +36,7 @@
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
+import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Slog;
@@ -359,7 +360,7 @@
private ApplicationInfo getApplicationInfo(String packageName, int userId) {
return LocalServices.getService(PackageManagerInternal.class).getApplicationInfo(
- packageName, 0, userId, userId);
+ packageName, 0, Process.myUid(), userId);
}
private void killPackage(String packageName) {
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index aeb1893..e6210b2 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -45,6 +45,7 @@
import android.app.compat.CompatChanges;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.location.Criteria;
import android.location.GeocoderParams;
import android.location.Geofence;
@@ -91,6 +92,7 @@
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
import com.android.server.FgThread;
@@ -134,6 +136,8 @@
import com.android.server.location.provider.PassiveLocationProviderManager;
import com.android.server.location.provider.StationaryThrottlingLocationProvider;
import com.android.server.location.provider.proxy.ProxyLocationProvider;
+import com.android.server.location.settings.LocationSettings;
+import com.android.server.location.settings.LocationUserSettings;
import com.android.server.pm.permission.LegacyPermissionManagerInternal;
import java.io.FileDescriptor;
@@ -270,6 +274,8 @@
mGeofenceManager = new GeofenceManager(mContext, injector);
+ mInjector.getLocationSettings().registerLocationUserSettingsListener(
+ this::onLocationUserSettingsChanged);
mInjector.getSettingsHelper().addOnLocationEnabledChangedListener(
this::onLocationModeChanged);
mInjector.getSettingsHelper().addIgnoreSettingsAllowlistChangedListener(
@@ -476,6 +482,25 @@
}
}
+ private void onLocationUserSettingsChanged(int userId, LocationUserSettings oldSettings,
+ LocationUserSettings newSettings) {
+ if (oldSettings.isAdasGnssLocationEnabled() != newSettings.isAdasGnssLocationEnabled()) {
+ boolean enabled = newSettings.isAdasGnssLocationEnabled();
+
+ if (D) {
+ Log.d(TAG, "[u" + userId + "] adas gnss location enabled = " + enabled);
+ }
+
+ EVENT_LOG.logAdasLocationEnabled(userId, enabled);
+
+ Intent intent = new Intent(LocationManager.ACTION_ADAS_GNSS_ENABLED_CHANGED)
+ .putExtra(LocationManager.EXTRA_ADAS_GNSS_ENABLED, enabled)
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
+ }
+ }
+
private void onLocationModeChanged(int userId) {
boolean enabled = mInjector.getSettingsHelper().isLocationEnabled(userId);
LocationManager.invalidateLocalLocationEnabledCaches();
@@ -661,7 +686,7 @@
// clients in the system process must have an attribution tag set
Preconditions.checkState(identity.getPid() != Process.myPid() || attributionTag != null);
- request = validateLocationRequest(request, identity);
+ request = validateLocationRequest(provider, request, identity);
LocationProviderManager manager = getLocationProviderManager(provider);
Preconditions.checkArgument(manager != null,
@@ -687,7 +712,7 @@
new IllegalArgumentException());
}
- request = validateLocationRequest(request, identity);
+ request = validateLocationRequest(provider, request, identity);
LocationProviderManager manager = getLocationProviderManager(provider);
Preconditions.checkArgument(manager != null,
@@ -725,7 +750,7 @@
}
}
- request = validateLocationRequest(request, identity);
+ request = validateLocationRequest(provider, request, identity);
LocationProviderManager manager = getLocationProviderManager(provider);
Preconditions.checkArgument(manager != null,
@@ -734,33 +759,27 @@
manager.registerLocationRequest(request, identity, permissionLevel, pendingIntent);
}
- private LocationRequest validateLocationRequest(LocationRequest request,
+ private LocationRequest validateLocationRequest(String provider, LocationRequest request,
CallerIdentity identity) {
+ // validate unsanitized request
if (!request.getWorkSource().isEmpty()) {
mContext.enforceCallingOrSelfPermission(
permission.UPDATE_DEVICE_STATS,
"setting a work source requires " + permission.UPDATE_DEVICE_STATS);
}
- if (request.isHiddenFromAppOps()) {
- mContext.enforceCallingOrSelfPermission(
- permission.UPDATE_APP_OPS_STATS,
- "hiding from app ops requires " + permission.UPDATE_APP_OPS_STATS);
- }
- if (request.isLocationSettingsIgnored()) {
- mContext.enforceCallingOrSelfPermission(
- permission.WRITE_SECURE_SETTINGS,
- "ignoring location settings requires " + permission.WRITE_SECURE_SETTINGS);
- }
+ // sanitize request
LocationRequest.Builder sanitized = new LocationRequest.Builder(request);
- if (CompatChanges.isChangeEnabled(LOW_POWER_EXCEPTIONS, Binder.getCallingUid())) {
- if (request.isLowPower()) {
- mContext.enforceCallingOrSelfPermission(
- permission.LOCATION_HARDWARE,
- "low power request requires " + permission.LOCATION_HARDWARE);
- }
- } else {
+ if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
+ && GPS_PROVIDER.equals(provider)
+ && ArrayUtils.contains(mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_locationDriverAssistancePackageNames),
+ identity.getPackageName())) {
+ sanitized.setAdasGnssBypass(true);
+ }
+
+ if (!CompatChanges.isChangeEnabled(LOW_POWER_EXCEPTIONS, Binder.getCallingUid())) {
if (mContext.checkCallingPermission(permission.LOCATION_HARDWARE)
!= PERMISSION_GRANTED) {
sanitized.setLowPower(false);
@@ -786,7 +805,52 @@
}
sanitized.setWorkSource(workSource);
- return sanitized.build();
+ request = sanitized.build();
+
+ // validate sanitized request
+ boolean isLocationProvider = mLocalService.isProvider(null, identity);
+
+ if (request.isLowPower() && CompatChanges.isChangeEnabled(LOW_POWER_EXCEPTIONS,
+ identity.getUid())) {
+ mContext.enforceCallingOrSelfPermission(
+ permission.LOCATION_HARDWARE,
+ "low power request requires " + permission.LOCATION_HARDWARE);
+ }
+ if (request.isHiddenFromAppOps()) {
+ mContext.enforceCallingOrSelfPermission(
+ permission.UPDATE_APP_OPS_STATS,
+ "hiding from app ops requires " + permission.UPDATE_APP_OPS_STATS);
+ }
+ if (request.isAdasGnssBypass()) {
+ if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+ throw new IllegalArgumentException(
+ "adas gnss bypass requests are only allowed on automotive devices");
+ }
+ if (!GPS_PROVIDER.equals(provider)) {
+ throw new IllegalArgumentException(
+ "adas gnss bypass requests are only allowed on the \"gps\" provider");
+ }
+ if (!ArrayUtils.contains(mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_locationDriverAssistancePackageNames),
+ identity.getPackageName())) {
+ throw new SecurityException(
+ "only verified adas packages may use adas gnss bypass requests");
+ }
+ if (!isLocationProvider) {
+ mContext.enforceCallingOrSelfPermission(
+ permission.WRITE_SECURE_SETTINGS,
+ "adas gnss bypass requires " + permission.WRITE_SECURE_SETTINGS);
+ }
+ }
+ if (request.isLocationSettingsIgnored()) {
+ if (!isLocationProvider) {
+ mContext.enforceCallingOrSelfPermission(
+ permission.WRITE_SECURE_SETTINGS,
+ "ignoring location settings requires " + permission.WRITE_SECURE_SETTINGS);
+ }
+ }
+
+ return request;
}
@Override
@@ -834,7 +898,7 @@
// clients in the system process must have an attribution tag set
Preconditions.checkArgument(identity.getPid() != Process.myPid() || attributionTag != null);
- request = validateLastLocationRequest(request);
+ request = validateLastLocationRequest(provider, request, identity);
LocationProviderManager manager = getLocationProviderManager(provider);
if (manager == null) {
@@ -844,16 +908,58 @@
return manager.getLastLocation(request, identity, permissionLevel);
}
- private LastLocationRequest validateLastLocationRequest(LastLocationRequest request) {
+ private LastLocationRequest validateLastLocationRequest(String provider,
+ LastLocationRequest request,
+ CallerIdentity identity) {
+ // sanitize request
+ LastLocationRequest.Builder sanitized = new LastLocationRequest.Builder(request);
+
+ if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
+ && GPS_PROVIDER.equals(provider)
+ && ArrayUtils.contains(mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_locationDriverAssistancePackageNames),
+ identity.getPackageName())) {
+ sanitized.setAdasGnssBypass(true);
+ }
+
+ request = sanitized.build();
+
+ // validate request
+ boolean isLocationProvider = mLocalService.isProvider(null, identity);
+
if (request.isHiddenFromAppOps()) {
mContext.enforceCallingOrSelfPermission(
permission.UPDATE_APP_OPS_STATS,
"hiding from app ops requires " + permission.UPDATE_APP_OPS_STATS);
}
+
+ if (request.isAdasGnssBypass()) {
+ if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+ throw new IllegalArgumentException(
+ "adas gnss bypass requests are only allowed on automotive devices");
+ }
+ if (!GPS_PROVIDER.equals(provider)) {
+ throw new IllegalArgumentException(
+ "adas gnss bypass requests are only allowed on the \"gps\" provider");
+ }
+ if (!ArrayUtils.contains(mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_locationDriverAssistancePackageNames),
+ identity.getPackageName())) {
+ throw new SecurityException(
+ "only verified adas packages may use adas gnss bypass requests");
+ }
+ if (!isLocationProvider) {
+ mContext.enforceCallingOrSelfPermission(
+ permission.WRITE_SECURE_SETTINGS,
+ "adas gnss bypass requires " + permission.WRITE_SECURE_SETTINGS);
+ }
+ }
if (request.isLocationSettingsIgnored()) {
- mContext.enforceCallingOrSelfPermission(
- permission.WRITE_SECURE_SETTINGS,
- "ignoring location settings requires " + permission.WRITE_SECURE_SETTINGS);
+ if (!isLocationProvider) {
+ mContext.enforceCallingOrSelfPermission(
+ permission.WRITE_SECURE_SETTINGS,
+ "ignoring location settings requires " + permission.WRITE_SECURE_SETTINGS);
+ }
}
return request;
@@ -1126,6 +1232,24 @@
}
@Override
+ public void setAdasGnssLocationEnabledForUser(boolean enabled, int userId) {
+ userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+ userId, false, false, "setAdasGnssLocationEnabledForUser", null);
+
+ mContext.enforceCallingOrSelfPermission(permission.WRITE_SECURE_SETTINGS, null);
+
+ mInjector.getLocationSettings().updateUserSettings(userId,
+ settings -> settings.withAdasGnssLocationEnabled(enabled));
+ }
+
+ @Override
+ public boolean isAdasGnssLocationEnabledForUser(int userId) {
+ userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+ userId, false, false, "isAdasGnssLocationEnabledForUser", null);
+ return mInjector.getLocationSettings().getUserSettings(userId).isAdasGnssLocationEnabled();
+ }
+
+ @Override
public boolean isProviderEnabledForUser(String provider, int userId) {
return mLocalService.isProviderEnabledForUser(provider, userId);
}
@@ -1555,11 +1679,12 @@
}
}
- private static class SystemInjector implements Injector {
+ private static final class SystemInjector implements Injector {
private final Context mContext;
private final UserInfoHelper mUserInfoHelper;
+ private final LocationSettings mLocationSettings;
private final AlarmHelper mAlarmHelper;
private final SystemAppOpsHelper mAppOpsHelper;
private final SystemLocationPermissionsHelper mLocationPermissionsHelper;
@@ -1584,6 +1709,7 @@
mContext = context;
mUserInfoHelper = userInfoHelper;
+ mLocationSettings = new LocationSettings(context);
mAlarmHelper = new SystemAlarmHelper(context);
mAppOpsHelper = new SystemAppOpsHelper(context);
mLocationPermissionsHelper = new SystemLocationPermissionsHelper(context,
@@ -1621,6 +1747,11 @@
}
@Override
+ public LocationSettings getLocationSettings() {
+ return mLocationSettings;
+ }
+
+ @Override
public AlarmHelper getAlarmHelper() {
return mAlarmHelper;
}
diff --git a/services/core/java/com/android/server/location/LocationShellCommand.java b/services/core/java/com/android/server/location/LocationShellCommand.java
index 9378493..b65338d 100644
--- a/services/core/java/com/android/server/location/LocationShellCommand.java
+++ b/services/core/java/com/android/server/location/LocationShellCommand.java
@@ -17,6 +17,7 @@
package com.android.server.location;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.location.Criteria;
import android.location.Location;
import android.location.provider.ProviderProperties;
@@ -60,6 +61,14 @@
handleSetLocationEnabled();
return 0;
}
+ case "is-adas-gnss-location-enabled": {
+ handleIsAdasGnssLocationEnabled();
+ return 0;
+ }
+ case "set-adas-gnss-location-enabled": {
+ handleSetAdasGnssLocationEnabled();
+ return 0;
+ }
case "providers": {
String command = getNextArgRequired();
return parseProvidersCommand(command);
@@ -134,6 +143,52 @@
mService.setLocationEnabledForUser(enabled, userId);
}
+ private void handleIsAdasGnssLocationEnabled() {
+ if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+ throw new IllegalStateException("command only recognized on automotive devices");
+ }
+
+ int userId = UserHandle.USER_CURRENT_OR_SELF;
+
+ do {
+ String option = getNextOption();
+ if (option == null) {
+ break;
+ }
+ if ("--user".equals(option)) {
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ } else {
+ throw new IllegalArgumentException("Unknown option: " + option);
+ }
+ } while (true);
+
+ getOutPrintWriter().println(mService.isAdasGnssLocationEnabledForUser(userId));
+ }
+
+ private void handleSetAdasGnssLocationEnabled() {
+ if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+ throw new IllegalStateException("command only recognized on automotive devices");
+ }
+
+ boolean enabled = Boolean.parseBoolean(getNextArgRequired());
+
+ int userId = UserHandle.USER_CURRENT_OR_SELF;
+
+ do {
+ String option = getNextOption();
+ if (option == null) {
+ break;
+ }
+ if ("--user".equals(option)) {
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ } else {
+ throw new IllegalArgumentException("Unknown option: " + option);
+ }
+ } while (true);
+
+ mService.setAdasGnssLocationEnabledForUser(enabled, userId);
+ }
+
private void handleAddTestProvider() {
String provider = getNextArgRequired();
@@ -297,6 +352,14 @@
pw.println(" set-location-enabled true|false [--user <USER_ID>]");
pw.println(" Sets the master location switch enabled state. If no user is specified,");
pw.println(" the current user is assumed.");
+ if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+ pw.println(" is-adas-gnss-location-enabled [--user <USER_ID>]");
+ pw.println(" Gets the ADAS GNSS location enabled state. If no user is specified,");
+ pw.println(" the current user is assumed.");
+ pw.println(" set-adas-gnss-location-enabled true|false [--user <USER_ID>]");
+ pw.println(" Sets the ADAS GNSS location enabled state. If no user is specified,");
+ pw.println(" the current user is assumed.");
+ }
pw.println(" providers");
pw.println(" The providers command is followed by a subcommand, as listed below:");
pw.println();
@@ -323,9 +386,8 @@
pw.println(" Common commands that may be supported by the gps provider, depending on");
pw.println(" hardware and software configurations:");
pw.println(" delete_aiding_data - requests deletion of any predictive aiding data");
- pw.println(" force_time_injection - requests NTP time injection to chipset");
- pw.println(" force_psds_injection - "
- + "requests predictive aiding data injection to chipset");
- pw.println(" request_power_stats - requests GNSS power stats update from chipset");
+ pw.println(" force_time_injection - requests NTP time injection");
+ pw.println(" force_psds_injection - requests predictive aiding data injection");
+ pw.println(" request_power_stats - requests GNSS power stats update");
}
}
diff --git a/services/core/java/com/android/server/location/eventlog/LocationEventLog.java b/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
index e6d25ec..db2a43f 100644
--- a/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
+++ b/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
@@ -55,19 +55,20 @@
private static final int EVENT_USER_SWITCHED = 1;
private static final int EVENT_LOCATION_ENABLED = 2;
- private static final int EVENT_PROVIDER_ENABLED = 3;
- private static final int EVENT_PROVIDER_MOCKED = 4;
- private static final int EVENT_PROVIDER_CLIENT_REGISTER = 5;
- private static final int EVENT_PROVIDER_CLIENT_UNREGISTER = 6;
- private static final int EVENT_PROVIDER_CLIENT_FOREGROUND = 7;
- private static final int EVENT_PROVIDER_CLIENT_BACKGROUND = 8;
- private static final int EVENT_PROVIDER_CLIENT_PERMITTED = 9;
- private static final int EVENT_PROVIDER_CLIENT_UNPERMITTED = 10;
- private static final int EVENT_PROVIDER_UPDATE_REQUEST = 11;
- private static final int EVENT_PROVIDER_RECEIVE_LOCATION = 12;
- private static final int EVENT_PROVIDER_DELIVER_LOCATION = 13;
- private static final int EVENT_PROVIDER_STATIONARY_THROTTLED = 14;
- private static final int EVENT_LOCATION_POWER_SAVE_MODE_CHANGE = 15;
+ private static final int EVENT_ADAS_LOCATION_ENABLED = 3;
+ private static final int EVENT_PROVIDER_ENABLED = 4;
+ private static final int EVENT_PROVIDER_MOCKED = 5;
+ private static final int EVENT_PROVIDER_CLIENT_REGISTER = 6;
+ private static final int EVENT_PROVIDER_CLIENT_UNREGISTER = 7;
+ private static final int EVENT_PROVIDER_CLIENT_FOREGROUND = 8;
+ private static final int EVENT_PROVIDER_CLIENT_BACKGROUND = 9;
+ private static final int EVENT_PROVIDER_CLIENT_PERMITTED = 10;
+ private static final int EVENT_PROVIDER_CLIENT_UNPERMITTED = 11;
+ private static final int EVENT_PROVIDER_UPDATE_REQUEST = 12;
+ private static final int EVENT_PROVIDER_RECEIVE_LOCATION = 13;
+ private static final int EVENT_PROVIDER_DELIVER_LOCATION = 14;
+ private static final int EVENT_PROVIDER_STATIONARY_THROTTLED = 15;
+ private static final int EVENT_LOCATION_POWER_SAVE_MODE_CHANGE = 16;
@GuardedBy("mAggregateStats")
private final ArrayMap<String, ArrayMap<CallerIdentity, AggregateStats>> mAggregateStats;
@@ -116,6 +117,11 @@
addLogEvent(EVENT_LOCATION_ENABLED, userId, enabled);
}
+ /** Logs a location enabled/disabled event. */
+ public void logAdasLocationEnabled(int userId, boolean enabled) {
+ addLogEvent(EVENT_ADAS_LOCATION_ENABLED, userId, enabled);
+ }
+
/** Logs a location provider enabled/disabled event. */
public void logProviderEnabled(String provider, int userId, boolean enabled) {
addLogEvent(EVENT_PROVIDER_ENABLED, provider, userId, enabled);
@@ -219,6 +225,9 @@
return new UserSwitchedEvent(timeDelta, (Integer) args[0], (Integer) args[1]);
case EVENT_LOCATION_ENABLED:
return new LocationEnabledEvent(timeDelta, (Integer) args[0], (Boolean) args[1]);
+ case EVENT_ADAS_LOCATION_ENABLED:
+ return new LocationAdasEnabledEvent(timeDelta, (Integer) args[0],
+ (Boolean) args[1]);
case EVENT_PROVIDER_ENABLED:
return new ProviderEnabledEvent(timeDelta, (String) args[0], (Integer) args[1],
(Boolean) args[2]);
@@ -517,6 +526,23 @@
}
}
+ private static final class LocationAdasEnabledEvent extends LogEvent {
+
+ private final int mUserId;
+ private final boolean mEnabled;
+
+ LocationAdasEnabledEvent(long timeDelta, int userId, boolean enabled) {
+ super(timeDelta);
+ mUserId = userId;
+ mEnabled = enabled;
+ }
+
+ @Override
+ public String getLogString() {
+ return "adas location [u" + mUserId + "] " + (mEnabled ? "enabled" : "disabled");
+ }
+ }
+
/**
* Aggregate statistics for a single package under a single provider.
*/
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 1cccf08..f3dcfbb 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -771,10 +771,10 @@
boolean enabled = mContext.getSystemService(LocationManager.class)
.isLocationEnabledForUser(UserHandle.CURRENT);
- // .. but enable anyway, if there's an active settings-ignored request (e.g. ELS)
+ // .. but enable anyway, if there's an active bypass request (e.g. ELS or ADAS)
enabled |= (mProviderRequest != null
&& mProviderRequest.isActive()
- && mProviderRequest.isLocationSettingsIgnored());
+ && mProviderRequest.isBypass());
// ... and, finally, disable anyway, if device is being shut down
enabled &= !mShutdown;
diff --git a/services/core/java/com/android/server/location/injector/Injector.java b/services/core/java/com/android/server/location/injector/Injector.java
index b035118..173fd13 100644
--- a/services/core/java/com/android/server/location/injector/Injector.java
+++ b/services/core/java/com/android/server/location/injector/Injector.java
@@ -17,6 +17,7 @@
package com.android.server.location.injector;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.location.settings.LocationSettings;
/**
* Injects various location dependencies so that they may be controlled by tests.
@@ -27,6 +28,9 @@
/** Returns a UserInfoHelper. */
UserInfoHelper getUserInfoHelper();
+ /** Returns a LocationSettings. */
+ LocationSettings getLocationSettings();
+
/** Returns an AlarmHelper. */
AlarmHelper getAlarmHelper();
diff --git a/services/core/java/com/android/server/location/injector/SystemSettingsHelper.java b/services/core/java/com/android/server/location/injector/SystemSettingsHelper.java
index c315da4..3e8da7d 100644
--- a/services/core/java/com/android/server/location/injector/SystemSettingsHelper.java
+++ b/services/core/java/com/android/server/location/injector/SystemSettingsHelper.java
@@ -670,8 +670,6 @@
}
}
-
-
private static class PackageTagsListSetting extends DeviceConfigSetting {
private final Supplier<ArrayMap<String, ArraySet<String>>> mBaseValuesSupplier;
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index 8d335b8..43886f7 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -113,6 +113,8 @@
import com.android.server.location.injector.UserInfoHelper.UserListener;
import com.android.server.location.listeners.ListenerMultiplexer;
import com.android.server.location.listeners.RemoteListenerRegistration;
+import com.android.server.location.settings.LocationSettings;
+import com.android.server.location.settings.LocationUserSettings;
import java.io.FileDescriptor;
import java.lang.annotation.Retention;
@@ -549,6 +551,19 @@
}
@GuardedBy("mLock")
+ final boolean onAdasGnssLocationEnabledChanged(int userId) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ if (getIdentity().getUserId() == userId) {
+ return onProviderLocationRequestChanged();
+ }
+
+ return false;
+ }
+
+ @GuardedBy("mLock")
final boolean onForegroundChanged(int uid, boolean foreground) {
if (Build.IS_DEBUGGABLE) {
Preconditions.checkState(Thread.holdsLock(mLock));
@@ -592,8 +607,8 @@
onHighPowerUsageChanged();
updateService();
- // if location settings ignored has changed then the active state may have changed
- return oldRequest.isLocationSettingsIgnored() != newRequest.isLocationSettingsIgnored();
+ // if bypass state has changed then the active state may have changed
+ return oldRequest.isBypass() != newRequest.isBypass();
}
private LocationRequest calculateProviderLocationRequest() {
@@ -616,9 +631,24 @@
if (!mSettingsHelper.getIgnoreSettingsAllowlist().contains(
getIdentity().getPackageName(), getIdentity().getAttributionTag())
&& !mLocationManagerInternal.isProvider(null, getIdentity())) {
- builder.setLocationSettingsIgnored(false);
locationSettingsIgnored = false;
}
+
+ builder.setLocationSettingsIgnored(locationSettingsIgnored);
+ }
+
+ boolean adasGnssBypass = baseRequest.isAdasGnssBypass();
+ if (adasGnssBypass) {
+ // if we are not currently allowed use adas gnss bypass, disable it
+ if (!GPS_PROVIDER.equals(mName)) {
+ Log.e(TAG, "adas gnss bypass request received in non-gps provider");
+ adasGnssBypass = false;
+ } else if (!mLocationSettings.getUserSettings(
+ getIdentity().getUserId()).isAdasGnssLocationEnabled()) {
+ adasGnssBypass = false;
+ }
+
+ builder.setAdasGnssBypass(adasGnssBypass);
}
if (!locationSettingsIgnored && !isThrottlingExempt()) {
@@ -769,7 +799,7 @@
Location lastLocation = getLastLocationUnsafe(
getIdentity().getUserId(),
getPermissionLevel(),
- getRequest().isLocationSettingsIgnored(),
+ getRequest().isBypass(),
maxLocationAgeMs);
if (lastLocation != null) {
executeOperation(acceptLocationChange(LocationResult.wrap(lastLocation)));
@@ -1114,7 +1144,7 @@
Location lastLocation = getLastLocationUnsafe(
getIdentity().getUserId(),
getPermissionLevel(),
- getRequest().isLocationSettingsIgnored(),
+ getRequest().isBypass(),
MAX_CURRENT_LOCATION_AGE_MS);
if (lastLocation != null) {
executeOperation(acceptLocationChange(LocationResult.wrap(lastLocation)));
@@ -1267,6 +1297,7 @@
private final CopyOnWriteArrayList<IProviderRequestListener> mProviderRequestListeners;
protected final LocationManagerInternal mLocationManagerInternal;
+ protected final LocationSettings mLocationSettings;
protected final SettingsHelper mSettingsHelper;
protected final UserInfoHelper mUserHelper;
protected final AlarmHelper mAlarmHelper;
@@ -1280,6 +1311,8 @@
protected final LocationFudger mLocationFudger;
private final UserListener mUserChangedListener = this::onUserChanged;
+ private final LocationSettings.LocationUserSettingsListener mLocationUserSettingsListener =
+ this::onLocationUserSettingsChanged;
private final UserSettingChangedListener mLocationEnabledChangedListener =
this::onLocationEnabledChanged;
private final GlobalSettingChangedListener mBackgroundThrottlePackageWhitelistChangedListener =
@@ -1332,6 +1365,7 @@
mLocationManagerInternal = Objects.requireNonNull(
LocalServices.getService(LocationManagerInternal.class));
+ mLocationSettings = injector.getLocationSettings();
mSettingsHelper = injector.getSettingsHelper();
mUserHelper = injector.getUserInfoHelper();
mAlarmHelper = injector.getAlarmHelper();
@@ -1362,6 +1396,7 @@
mStateChangedListener = listener;
mUserHelper.addListener(mUserChangedListener);
+ mLocationSettings.registerLocationUserSettingsListener(mLocationUserSettingsListener);
mSettingsHelper.addOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
final long identity = Binder.clearCallingIdentity();
@@ -1389,6 +1424,7 @@
}
mUserHelper.removeListener(mUserChangedListener);
+ mLocationSettings.unregisterLocationUserSettingsListener(mLocationUserSettingsListener);
mSettingsHelper.removeOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
// if external entities are registering listeners it's their responsibility to
@@ -1550,7 +1586,7 @@
public @Nullable Location getLastLocation(LastLocationRequest request,
CallerIdentity identity, @PermissionLevel int permissionLevel) {
- if (!isActive(request.isLocationSettingsIgnored(), identity)) {
+ if (!isActive(request.isBypass(), identity)) {
return null;
}
@@ -1564,7 +1600,7 @@
getLastLocationUnsafe(
identity.getUserId(),
permissionLevel,
- request.isLocationSettingsIgnored(),
+ request.isBypass(),
Long.MAX_VALUE),
permissionLevel);
@@ -1584,7 +1620,7 @@
* location if necessary.
*/
public @Nullable Location getLastLocationUnsafe(int userId,
- @PermissionLevel int permissionLevel, boolean ignoreLocationSettings,
+ @PermissionLevel int permissionLevel, boolean isBypass,
long maximumAgeMs) {
if (userId == UserHandle.USER_ALL) {
// find the most recent location across all users
@@ -1592,7 +1628,7 @@
final int[] runningUserIds = mUserHelper.getRunningUserIds();
for (int i = 0; i < runningUserIds.length; i++) {
Location next = getLastLocationUnsafe(runningUserIds[i], permissionLevel,
- ignoreLocationSettings, maximumAgeMs);
+ isBypass, maximumAgeMs);
if (lastLocation == null || (next != null && next.getElapsedRealtimeNanos()
> lastLocation.getElapsedRealtimeNanos())) {
lastLocation = next;
@@ -1601,7 +1637,7 @@
return lastLocation;
} else if (userId == UserHandle.USER_CURRENT) {
return getLastLocationUnsafe(mUserHelper.getCurrentUserId(), permissionLevel,
- ignoreLocationSettings, maximumAgeMs);
+ isBypass, maximumAgeMs);
}
Preconditions.checkArgument(userId >= 0);
@@ -1613,7 +1649,7 @@
if (lastLocation == null) {
location = null;
} else {
- location = lastLocation.get(permissionLevel, ignoreLocationSettings);
+ location = lastLocation.get(permissionLevel, isBypass);
}
}
@@ -1925,7 +1961,7 @@
// provider, under the assumption that once we send the request off, the provider will
// immediately attempt to deliver a new location satisfying that request.
long delayMs;
- if (!oldRequest.isLocationSettingsIgnored() && newRequest.isLocationSettingsIgnored()) {
+ if (!oldRequest.isBypass() && newRequest.isBypass()) {
delayMs = 0;
} else if (newRequest.getIntervalMillis() > oldRequest.getIntervalMillis()) {
// if the interval has increased, tell the provider immediately, so it can save power
@@ -2002,12 +2038,12 @@
return false;
}
- boolean locationSettingsIgnored = registration.getRequest().isLocationSettingsIgnored();
- if (!isActive(locationSettingsIgnored, registration.getIdentity())) {
+ boolean isBypass = registration.getRequest().isBypass();
+ if (!isActive(isBypass, registration.getIdentity())) {
return false;
}
- if (!locationSettingsIgnored) {
+ if (!isBypass) {
switch (mLocationPowerSaveModeHelper.getLocationPowerSaveMode()) {
case LOCATION_MODE_FOREGROUND_ONLY:
if (!registration.isForeground()) {
@@ -2036,15 +2072,15 @@
return true;
}
- private boolean isActive(boolean locationSettingsIgnored, CallerIdentity identity) {
+ private boolean isActive(boolean isBypass, CallerIdentity identity) {
if (identity.isSystemServer()) {
- if (!locationSettingsIgnored) {
+ if (!isBypass) {
if (!isEnabled(mUserHelper.getCurrentUserId())) {
return false;
}
}
} else {
- if (!locationSettingsIgnored) {
+ if (!isBypass) {
if (!isEnabled(identity.getUserId())) {
return false;
}
@@ -2071,6 +2107,7 @@
long intervalMs = ProviderRequest.INTERVAL_DISABLED;
int quality = LocationRequest.QUALITY_LOW_POWER;
long maxUpdateDelayMs = Long.MAX_VALUE;
+ boolean adasGnssBypass = false;
boolean locationSettingsIgnored = false;
boolean lowPower = true;
@@ -2086,6 +2123,7 @@
intervalMs = min(request.getIntervalMillis(), intervalMs);
quality = min(request.getQuality(), quality);
maxUpdateDelayMs = min(request.getMaxUpdateDelayMillis(), maxUpdateDelayMs);
+ adasGnssBypass |= request.isAdasGnssBypass();
locationSettingsIgnored |= request.isLocationSettingsIgnored();
lowPower &= request.isLowPower();
}
@@ -2123,6 +2161,7 @@
.setIntervalMillis(intervalMs)
.setQuality(quality)
.setMaxUpdateDelayMillis(maxUpdateDelayMs)
+ .setAdasGnssBypass(adasGnssBypass)
.setLocationSettingsIgnored(locationSettingsIgnored)
.setLowPower(lowPower)
.setWorkSource(workSource)
@@ -2191,6 +2230,16 @@
}
}
+ private void onLocationUserSettingsChanged(int userId, LocationUserSettings oldSettings,
+ LocationUserSettings newSettings) {
+ if (oldSettings.isAdasGnssLocationEnabled() != newSettings.isAdasGnssLocationEnabled()) {
+ synchronized (mLock) {
+ updateRegistrations(
+ registration -> registration.onAdasGnssLocationEnabledChanged(userId));
+ }
+ }
+ }
+
private void onLocationEnabledChanged(int userId) {
synchronized (mLock) {
if (mState == STATE_STOPPED) {
@@ -2560,16 +2609,16 @@
}
public @Nullable Location get(@PermissionLevel int permissionLevel,
- boolean ignoreLocationSettings) {
+ boolean isBypass) {
switch (permissionLevel) {
case PERMISSION_FINE:
- if (ignoreLocationSettings) {
+ if (isBypass) {
return mFineBypassLocation;
} else {
return mFineLocation;
}
case PERMISSION_COARSE:
- if (ignoreLocationSettings) {
+ if (isBypass) {
return mCoarseBypassLocation;
} else {
return mCoarseLocation;
diff --git a/services/core/java/com/android/server/location/settings/LocationSettings.java b/services/core/java/com/android/server/location/settings/LocationSettings.java
new file mode 100644
index 0000000..d521538
--- /dev/null
+++ b/services/core/java/com/android/server/location/settings/LocationSettings.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location.settings;
+
+import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
+
+import android.content.Context;
+import android.os.Environment;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.FgThread;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.File;
+import java.io.IOException;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.Function;
+
+/**
+ * Accessor for location user settings. Ensure there is only ever one instance as multiple instances
+ * don't play nicely with each other.
+ */
+public class LocationSettings {
+
+ /** Listens for changes to location user settings. */
+ public interface LocationUserSettingsListener {
+ /** Invoked when location user settings have changed for the given user. */
+ void onLocationUserSettingsChanged(int userId, LocationUserSettings oldSettings,
+ LocationUserSettings newSettings);
+ }
+
+ private static final String LOCATION_DIRNAME = "location";
+ private static final String LOCATION_SETTINGS_FILENAME = "settings";
+
+ final Context mContext;
+
+ @GuardedBy("mUserSettings")
+ private final SparseArray<LocationUserSettingsStore> mUserSettings;
+ private final CopyOnWriteArrayList<LocationUserSettingsListener> mUserSettingsListeners;
+
+ public LocationSettings(Context context) {
+ mContext = context;
+ mUserSettings = new SparseArray<>(1);
+ mUserSettingsListeners = new CopyOnWriteArrayList<>();
+ }
+
+ /** Registers a listener for changes to location user settings. */
+ public final void registerLocationUserSettingsListener(LocationUserSettingsListener listener) {
+ mUserSettingsListeners.add(listener);
+ }
+
+ /** Unregisters a listener for changes to location user settings. */
+ public final void unregisterLocationUserSettingsListener(
+ LocationUserSettingsListener listener) {
+ mUserSettingsListeners.remove(listener);
+ }
+
+ protected File getUserSettingsDir(int userId) {
+ return Environment.getDataSystemDeDirectory(userId);
+ }
+
+ protected LocationUserSettingsStore createUserSettingsStore(int userId, File file) {
+ return new LocationUserSettingsStore(userId, file);
+ }
+
+ private LocationUserSettingsStore getUserSettingsStore(int userId) {
+ synchronized (mUserSettings) {
+ LocationUserSettingsStore settingsStore = mUserSettings.get(userId);
+ if (settingsStore == null) {
+ File file = new File(new File(getUserSettingsDir(userId), LOCATION_DIRNAME),
+ LOCATION_SETTINGS_FILENAME);
+ settingsStore = createUserSettingsStore(userId, file);
+ mUserSettings.put(userId, settingsStore);
+ }
+ return settingsStore;
+ }
+ }
+
+ /** Retrieves the current state of location user settings. */
+ public final LocationUserSettings getUserSettings(int userId) {
+ return getUserSettingsStore(userId).get();
+ }
+
+ /** Updates the current state of location user settings for the given user. */
+ public final void updateUserSettings(int userId,
+ Function<LocationUserSettings, LocationUserSettings> updater) {
+ getUserSettingsStore(userId).update(updater);
+ }
+
+ @VisibleForTesting
+ final void flushFiles() throws InterruptedException {
+ synchronized (mUserSettings) {
+ int size = mUserSettings.size();
+ for (int i = 0; i < size; i++) {
+ mUserSettings.valueAt(i).flushFile();
+ }
+ }
+ }
+
+ @VisibleForTesting
+ final void deleteFiles() throws InterruptedException {
+ synchronized (mUserSettings) {
+ int size = mUserSettings.size();
+ for (int i = 0; i < size; i++) {
+ mUserSettings.valueAt(i).deleteFile();
+ }
+ }
+ }
+
+ protected final void fireListeners(int userId, LocationUserSettings oldSettings,
+ LocationUserSettings newSettings) {
+ for (LocationUserSettingsListener listener : mUserSettingsListeners) {
+ listener.onLocationUserSettingsChanged(userId, oldSettings, newSettings);
+ }
+ }
+
+ class LocationUserSettingsStore extends SettingsStore<LocationUserSettings> {
+
+ protected final int mUserId;
+
+ LocationUserSettingsStore(int userId, File file) {
+ super(file);
+ mUserId = userId;
+ }
+
+ @Override
+ protected LocationUserSettings read(int version, DataInput in) throws IOException {
+ return filterSettings(LocationUserSettings.read(mContext.getResources(), version, in));
+ }
+
+ @Override
+ protected void write(DataOutput out, LocationUserSettings settings) throws IOException {
+ settings.write(out);
+ }
+
+ @Override
+ public void update(Function<LocationUserSettings, LocationUserSettings> updater) {
+ super.update(settings -> filterSettings(updater.apply(settings)));
+ }
+
+ @Override
+ protected void onChange(LocationUserSettings oldSettings,
+ LocationUserSettings newSettings) {
+ FgThread.getExecutor().execute(() -> fireListeners(mUserId, oldSettings, newSettings));
+ }
+
+ private LocationUserSettings filterSettings(LocationUserSettings settings) {
+ if (settings.isAdasGnssLocationEnabled()
+ && !mContext.getPackageManager().hasSystemFeature(FEATURE_AUTOMOTIVE)) {
+ // prevent non-automotive devices from ever enabling this
+ settings = settings.withAdasGnssLocationEnabled(false);
+ }
+ return settings;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/location/settings/LocationUserSettings.java b/services/core/java/com/android/server/location/settings/LocationUserSettings.java
new file mode 100644
index 0000000..283255e
--- /dev/null
+++ b/services/core/java/com/android/server/location/settings/LocationUserSettings.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location.settings;
+
+import android.content.res.Resources;
+
+import com.android.internal.R;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.Objects;
+
+/** Holds the state of location user settings. */
+public final class LocationUserSettings implements SettingsStore.VersionedSettings {
+
+ // remember to bump this version code and add the appropriate upgrade logic whenever the format
+ // is changed.
+ private static final int VERSION = 1;
+
+ private final boolean mAdasGnssLocationEnabled;
+
+ private LocationUserSettings(boolean adasGnssLocationEnabled) {
+ mAdasGnssLocationEnabled = adasGnssLocationEnabled;
+ }
+
+ @Override
+ public int getVersion() {
+ return VERSION;
+ }
+
+ public boolean isAdasGnssLocationEnabled() {
+ return mAdasGnssLocationEnabled;
+ }
+
+ /** Returns an instance with ADAS GNSS location enabled state set as given. */
+ public LocationUserSettings withAdasGnssLocationEnabled(boolean adasEnabled) {
+ if (adasEnabled == mAdasGnssLocationEnabled) {
+ return this;
+ }
+
+ return new LocationUserSettings(adasEnabled);
+ }
+
+ void write(DataOutput out) throws IOException {
+ out.writeBoolean(mAdasGnssLocationEnabled);
+ }
+
+ static LocationUserSettings read(Resources resources, int version, DataInput in)
+ throws IOException {
+ boolean adasGnssLocationEnabled;
+
+ // upgrade code goes here. remember to bump the version field when changing the format
+ switch (version) {
+ default:
+ // set all fields to defaults
+ adasGnssLocationEnabled = resources.getBoolean(
+ R.bool.config_defaultAdasGnssLocationEnabled);
+ break;
+ case 1:
+ adasGnssLocationEnabled = in.readBoolean();
+ // fall through
+ }
+
+ return new LocationUserSettings(adasGnssLocationEnabled);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof LocationUserSettings)) {
+ return false;
+ }
+ LocationUserSettings that = (LocationUserSettings) o;
+ return mAdasGnssLocationEnabled == that.mAdasGnssLocationEnabled;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mAdasGnssLocationEnabled);
+ }
+}
diff --git a/services/core/java/com/android/server/location/settings/SettingsStore.java b/services/core/java/com/android/server/location/settings/SettingsStore.java
new file mode 100644
index 0000000..01338a3
--- /dev/null
+++ b/services/core/java/com/android/server/location/settings/SettingsStore.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location.settings;
+
+import static com.android.server.location.LocationManagerService.TAG;
+import static com.android.server.location.settings.SettingsStore.VersionedSettings.VERSION_DOES_NOT_EXIST;
+
+import android.util.AtomicFile;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.Preconditions;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.DataOutput;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Objects;
+import java.util.concurrent.CountDownLatch;
+import java.util.function.Function;
+
+/** Base class for read/write/versioning functionality for storing persistent settings to a file. */
+abstract class SettingsStore<T extends SettingsStore.VersionedSettings> {
+
+ interface VersionedSettings {
+ /** Represents that the settings do not exist. */
+ int VERSION_DOES_NOT_EXIST = Integer.MAX_VALUE;
+
+ /** Must always return a version number less than {@link #VERSION_DOES_NOT_EXIST}. */
+ int getVersion();
+ }
+
+ private final AtomicFile mFile;
+
+ @GuardedBy("this")
+ private boolean mInitialized;
+ @GuardedBy("this")
+ private T mCache;
+
+ protected SettingsStore(File file) {
+ mFile = new AtomicFile(file);
+ }
+
+ /**
+ * Must be implemented to read in a settings instance, and upgrade to the appropriate version
+ * where necessary. If the provided version is {@link VersionedSettings#VERSION_DOES_NOT_EXIST}
+ * then the DataInput will be empty, and the method should return a settings instance with all
+ * settings set to the default value.
+ */
+ protected abstract T read(int version, DataInput in) throws IOException;
+
+ /**
+ * Must be implemented to write the given settings to the given DataOutput.
+ */
+ protected abstract void write(DataOutput out, T settings) throws IOException;
+
+ /**
+ * Invoked when settings change, and while holding the internal lock. If used to invoke
+ * listeners, ensure they are not invoked while holding the lock (ie, asynchronously).
+ */
+ protected abstract void onChange(T oldSettings, T newSettings);
+
+ public final synchronized void initializeCache() {
+ if (!mInitialized) {
+ if (mFile.exists()) {
+ try (DataInputStream is = new DataInputStream(mFile.openRead())) {
+ mCache = read(is.readInt(), is);
+ Preconditions.checkState(mCache.getVersion() < VERSION_DOES_NOT_EXIST);
+ } catch (IOException e) {
+ Log.e(TAG, "error reading location settings (" + mFile
+ + "), falling back to defaults", e);
+ }
+ }
+
+ if (mCache == null) {
+ try {
+ mCache = read(VERSION_DOES_NOT_EXIST,
+ new DataInputStream(new ByteArrayInputStream(new byte[0])));
+ Preconditions.checkState(mCache.getVersion() < VERSION_DOES_NOT_EXIST);
+ } catch (IOException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ mInitialized = true;
+ }
+ }
+
+ public final synchronized T get() {
+ initializeCache();
+ return mCache;
+ }
+
+ public synchronized void update(Function<T, T> updater) {
+ initializeCache();
+
+ T oldSettings = mCache;
+ T newSettings = Objects.requireNonNull(updater.apply(oldSettings));
+ if (oldSettings.equals(newSettings)) {
+ return;
+ }
+
+ mCache = newSettings;
+ Preconditions.checkState(mCache.getVersion() < VERSION_DOES_NOT_EXIST);
+
+ writeLazily(newSettings);
+
+ onChange(oldSettings, newSettings);
+ }
+
+ @VisibleForTesting
+ synchronized void flushFile() throws InterruptedException {
+ CountDownLatch latch = new CountDownLatch(1);
+ BackgroundThread.getExecutor().execute(latch::countDown);
+ latch.await();
+ }
+
+ @VisibleForTesting
+ synchronized void deleteFile() throws InterruptedException {
+ CountDownLatch latch = new CountDownLatch(1);
+ BackgroundThread.getExecutor().execute(() -> {
+ mFile.delete();
+ latch.countDown();
+ });
+ latch.await();
+ }
+
+ private void writeLazily(T settings) {
+ BackgroundThread.getExecutor().execute(() -> {
+ FileOutputStream os = null;
+ try {
+ os = mFile.startWrite();
+ DataOutputStream out = new DataOutputStream(os);
+ out.writeInt(settings.getVersion());
+ write(out, settings);
+ mFile.finishWrite(os);
+ } catch (IOException e) {
+ mFile.failWrite(os);
+ Log.e(TAG, "failure serializing location settings", e);
+ } catch (Throwable e) {
+ mFile.failWrite(os);
+ throw e;
+ }
+ });
+ }
+}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 21f68ae..d791bd6 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -1235,11 +1235,7 @@
final private BroadcastReceiver mWifiReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- synchronized (mUidRulesFirstLock) {
- synchronized (mNetworkPoliciesSecondLock) {
- upgradeWifiMeteredOverrideAL();
- }
- }
+ upgradeWifiMeteredOverride();
// Only need to perform upgrade logic once
mContext.unregisterReceiver(this);
}
@@ -2617,34 +2613,43 @@
* Perform upgrade step of moving any user-defined meterness overrides over
* into {@link WifiConfiguration}.
*/
- @GuardedBy({"mNetworkPoliciesSecondLock", "mUidRulesFirstLock"})
- private void upgradeWifiMeteredOverrideAL() {
- boolean modified = false;
- final WifiManager wm = mContext.getSystemService(WifiManager.class);
- final List<WifiConfiguration> configs = wm.getConfiguredNetworks();
- for (int i = 0; i < mNetworkPolicy.size(); ) {
- final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
- if (policy.template.getMatchRule() == NetworkTemplate.MATCH_WIFI
- && !policy.inferred) {
- mNetworkPolicy.removeAt(i);
- modified = true;
-
- final String networkId = resolveNetworkId(policy.template.getNetworkId());
- for (WifiConfiguration config : configs) {
- if (Objects.equals(resolveNetworkId(config), networkId)) {
- Slog.d(TAG, "Found network " + networkId + "; upgrading metered hint");
- config.meteredOverride = policy.metered
- ? WifiConfiguration.METERED_OVERRIDE_METERED
- : WifiConfiguration.METERED_OVERRIDE_NOT_METERED;
- wm.updateNetwork(config);
- }
+ private void upgradeWifiMeteredOverride() {
+ final ArrayMap<String, Boolean> wifiNetworkIds = new ArrayMap<>();
+ synchronized (mNetworkPoliciesSecondLock) {
+ for (int i = 0; i < mNetworkPolicy.size();) {
+ final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
+ if (policy.template.getMatchRule() == NetworkTemplate.MATCH_WIFI
+ && !policy.inferred) {
+ mNetworkPolicy.removeAt(i);
+ wifiNetworkIds.put(policy.template.getNetworkId(), policy.metered);
+ } else {
+ i++;
}
- } else {
- i++;
}
}
- if (modified) {
- writePolicyAL();
+
+ if (wifiNetworkIds.isEmpty()) {
+ return;
+ }
+ final WifiManager wm = mContext.getSystemService(WifiManager.class);
+ final List<WifiConfiguration> configs = wm.getConfiguredNetworks();
+ for (int i = 0; i < configs.size(); ++i) {
+ final WifiConfiguration config = configs.get(i);
+ final String networkId = resolveNetworkId(config);
+ final Boolean metered = wifiNetworkIds.get(networkId);
+ if (metered != null) {
+ Slog.d(TAG, "Found network " + networkId + "; upgrading metered hint");
+ config.meteredOverride = metered
+ ? WifiConfiguration.METERED_OVERRIDE_METERED
+ : WifiConfiguration.METERED_OVERRIDE_NOT_METERED;
+ wm.updateNetwork(config);
+ }
+ }
+
+ synchronized (mUidRulesFirstLock) {
+ synchronized (mNetworkPoliciesSecondLock) {
+ writePolicyAL();
+ }
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index a3f3a3a..d78fbdb 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -140,6 +140,7 @@
import android.app.ITransientNotification;
import android.app.ITransientNotificationCallback;
import android.app.IUriGrantsManager;
+import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
@@ -549,6 +550,8 @@
// Used for rate limiting toasts by package.
private MultiRateLimiter mToastRateLimiter;
+ private KeyguardManager mKeyguardManager;
+
// The last key in this list owns the hardware.
ArrayList<String> mLights = new ArrayList<>();
@@ -2008,6 +2011,11 @@
}
@VisibleForTesting
+ void setKeyguardManager(KeyguardManager keyguardManager) {
+ mKeyguardManager = keyguardManager;
+ }
+
+ @VisibleForTesting
ShortcutHelper getShortcutHelper() {
return mShortcutHelper;
}
@@ -2653,6 +2661,7 @@
mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
+ mKeyguardManager = getContext().getSystemService(KeyguardManager.class);
mZenModeHelper.onSystemReady();
RoleObserver roleObserver = new RoleObserver(getContext(),
getContext().getSystemService(RoleManager.class),
@@ -3806,15 +3815,18 @@
enforceDeletingChannelHasNoFgService(pkg, callingUser, channelId);
cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
callingUser, REASON_CHANNEL_REMOVED, null);
- mPreferencesHelper.deleteNotificationChannel(pkg, callingUid, channelId);
- // Remove from both recent notification archive and notification history
- mArchive.removeChannelNotifications(pkg, callingUser, channelId);
- mHistoryManager.deleteNotificationChannel(pkg, callingUid, channelId);
- mListeners.notifyNotificationChannelChanged(pkg,
- UserHandle.getUserHandleForUid(callingUid),
- mPreferencesHelper.getNotificationChannel(pkg, callingUid, channelId, true),
- NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
- handleSavePolicyFile();
+ boolean previouslyExisted = mPreferencesHelper.deleteNotificationChannel(
+ pkg, callingUid, channelId);
+ if (previouslyExisted) {
+ // Remove from both recent notification archive and notification history
+ mArchive.removeChannelNotifications(pkg, callingUser, channelId);
+ mHistoryManager.deleteNotificationChannel(pkg, callingUid, channelId);
+ mListeners.notifyNotificationChannelChanged(pkg,
+ UserHandle.getUserHandleForUid(callingUid),
+ mPreferencesHelper.getNotificationChannel(pkg, callingUid, channelId, true),
+ NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
+ handleSavePolicyFile();
+ }
}
@Override
@@ -7388,7 +7400,6 @@
boolean beep = false;
boolean blink = false;
- final Notification notification = record.getSbn().getNotification();
final String key = record.getKey();
// Should this notification make noise, vibe, or use the LED?
@@ -7410,7 +7421,7 @@
if (!record.isUpdate
&& record.getImportance() > IMPORTANCE_MIN
&& !suppressedByDnd) {
- sendAccessibilityEvent(notification, record.getSbn().getPackageName());
+ sendAccessibilityEvent(record);
sentAccessibilityEvent = true;
}
@@ -7433,7 +7444,7 @@
boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
if (!sentAccessibilityEvent) {
- sendAccessibilityEvent(notification, record.getSbn().getPackageName());
+ sendAccessibilityEvent(record);
sentAccessibilityEvent = true;
}
if (DBG) Slog.v(TAG, "Interrupting!");
@@ -8261,17 +8272,30 @@
return (x < low) ? low : ((x > high) ? high : x);
}
- void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
+ void sendAccessibilityEvent(NotificationRecord record) {
if (!mAccessibilityManager.isEnabled()) {
return;
}
- AccessibilityEvent event =
+ final Notification notification = record.getNotification();
+ final CharSequence packageName = record.getSbn().getPackageName();
+ final AccessibilityEvent event =
AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
event.setPackageName(packageName);
event.setClassName(Notification.class.getName());
- event.setParcelableData(notification);
- CharSequence tickerText = notification.tickerText;
+ final int visibilityOverride = record.getPackageVisibilityOverride();
+ final int notifVisibility = visibilityOverride == NotificationManager.VISIBILITY_NO_OVERRIDE
+ ? notification.visibility : visibilityOverride;
+ final int userId = record.getUser().getIdentifier();
+ final boolean needPublic = userId >= 0 && mKeyguardManager.isDeviceLocked(userId);
+ if (needPublic && notifVisibility != Notification.VISIBILITY_PUBLIC) {
+ // Emit the public version if we're on the lockscreen and this notification isn't
+ // publicly visible.
+ event.setParcelableData(notification.publicVersion);
+ } else {
+ event.setParcelableData(notification);
+ }
+ final CharSequence tickerText = notification.tickerText;
if (!TextUtils.isEmpty(tickerText)) {
event.getText().add(tickerText);
}
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 03676b55..96bde3d 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -1126,20 +1126,21 @@
}
@Override
- public void deleteNotificationChannel(String pkg, int uid, String channelId) {
+ public boolean deleteNotificationChannel(String pkg, int uid, String channelId) {
synchronized (mPackagePreferences) {
PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
if (r == null) {
- return;
+ return false;
}
NotificationChannel channel = r.channels.get(channelId);
if (channel != null) {
- deleteNotificationChannelLocked(channel, pkg, uid);
+ return deleteNotificationChannelLocked(channel, pkg, uid);
}
+ return false;
}
}
- private void deleteNotificationChannelLocked(NotificationChannel channel, String pkg, int uid) {
+ private boolean deleteNotificationChannelLocked(NotificationChannel channel, String pkg, int uid) {
if (!channel.isDeleted()) {
channel.setDeleted(true);
channel.setDeletedTimeMs(System.currentTimeMillis());
@@ -1151,7 +1152,9 @@
if (mAreChannelsBypassingDnd && channel.canBypassDnd()) {
updateChannelsBypassingDnd();
}
+ return true;
}
+ return false;
}
@Override
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index b1d6546..3982593 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -53,7 +53,7 @@
NotificationChannel getConversationNotificationChannel(String pkg, int uid, String channelId,
String conversationId, boolean returnParentIfNoConversationChannel,
boolean includeDeleted);
- void deleteNotificationChannel(String pkg, int uid, String channelId);
+ boolean deleteNotificationChannel(String pkg, int uid, String channelId);
void permanentlyDeleteNotificationChannel(String pkg, int uid, String channelId);
void permanentlyDeleteNotificationChannels(String pkg, int uid);
ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid,
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index a98f113..b144ff2 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -417,7 +417,14 @@
newConfig = mConfig.copy();
for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) {
ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
- if (rule.pkg.equals(packageName) && canManageAutomaticZenRule(rule)) {
+ String pkg = rule.pkg != null
+ ? rule.pkg
+ : (rule.component != null)
+ ? rule.component.getPackageName()
+ : (rule.configurationActivity != null)
+ ? rule.configurationActivity.getPackageName()
+ : null;
+ if (Objects.equals(pkg, packageName) && canManageAutomaticZenRule(rule)) {
newConfig.automaticRules.removeAt(i);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index c331300..acc83cf 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -2799,7 +2799,7 @@
private boolean isApexUpdateAllowed(String apexPackageName) {
return mPm.getModuleInfo(apexPackageName, 0) != null
- || SystemConfig.getInstance().getAllowedPartnerApexes().contains(apexPackageName);
+ || SystemConfig.getInstance().getAllowedVendorApexes().contains(apexPackageName);
}
/**
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 463520f..2419873 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -21480,6 +21480,8 @@
// for the uninstall-updates case and restricted profiles, remember the per-
// user handle installed state
int[] allUsers;
+ final int freezeUser;
+ final SparseArray<Pair<Integer, String>> enabledStateAndCallerPerUser;
/** enabled state of the uninstalled application */
synchronized (mLock) {
uninstalledPs = mSettings.getPackageLPr(packageName);
@@ -21524,16 +21526,23 @@
}
info.origUsers = uninstalledPs.queryInstalledUsers(allUsers, true);
- }
- final int freezeUser;
- if (isUpdatedSystemApp(uninstalledPs)
- && ((deleteFlags & PackageManager.DELETE_SYSTEM_APP) == 0)) {
- // We're downgrading a system app, which will apply to all users, so
- // freeze them all during the downgrade
- freezeUser = UserHandle.USER_ALL;
- } else {
- freezeUser = removeUser;
+ if (isUpdatedSystemApp(uninstalledPs)
+ && ((deleteFlags & PackageManager.DELETE_SYSTEM_APP) == 0)) {
+ // We're downgrading a system app, which will apply to all users, so
+ // freeze them all during the downgrade
+ freezeUser = UserHandle.USER_ALL;
+ enabledStateAndCallerPerUser = new SparseArray<>();
+ for (int i = 0; i < allUsers.length; i++) {
+ PackageUserState userState = uninstalledPs.readUserState(allUsers[i]);
+ Pair<Integer, String> enabledStateAndCaller =
+ new Pair<>(userState.enabled, userState.lastDisableAppCaller);
+ enabledStateAndCallerPerUser.put(allUsers[i], enabledStateAndCaller);
+ }
+ } else {
+ freezeUser = removeUser;
+ enabledStateAndCallerPerUser = null;
+ }
}
synchronized (mInstallLock) {
@@ -21602,6 +21611,19 @@
}
}
}
+ if (enabledStateAndCallerPerUser != null) {
+ synchronized (mLock) {
+ for (int i = 0; i < allUsers.length; i++) {
+ Pair<Integer, String> enabledStateAndCaller =
+ enabledStateAndCallerPerUser.get(allUsers[i]);
+ getPackageSetting(packageName)
+ .setEnabled(enabledStateAndCaller.first,
+ allUsers[i],
+ enabledStateAndCaller.second);
+ }
+ mSettings.writeAllUsersPackageRestrictionsLPr();
+ }
+ }
}
return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR;
@@ -28126,8 +28148,8 @@
}
@Override
- public void deleteOatArtifactsOfPackage(String packageName) {
- PackageManagerService.this.deleteOatArtifactsOfPackage(packageName);
+ public long deleteOatArtifactsOfPackage(String packageName) {
+ return PackageManagerService.this.deleteOatArtifactsOfPackage(packageName);
}
@Override
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 4a68b76..c842ff1 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -955,8 +955,7 @@
continue;
} else if (isApexSessionFailed(apexSession)) {
hasFailedApexSession = true;
- String errorMsg = "APEX activation failed. Check logcat messages from apexd "
- + "for more information.";
+ String errorMsg = "APEX activation failed. " + apexSession.errorMessage;
if (!TextUtils.isEmpty(apexSession.crashingNativeProcess)) {
prepareForLoggingApexdRevert(session, apexSession.crashingNativeProcess);
errorMsg = "Session reverted due to crashing native process: "
diff --git a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
index 83d4ce7..b26b694 100644
--- a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
+++ b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
@@ -22,6 +22,7 @@
import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK;
import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK;
+import android.os.SystemClock;
import android.util.Slog;
import android.util.jar.StrictJarFile;
@@ -288,7 +289,7 @@
ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_UNKNOWN),
COMPILATION_REASON_MAP.getOrDefault(compilationReason, ArtStatsLog.
ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_UNKNOWN),
- /*timestamp_millis=*/ 0L,
+ /*timestamp_millis=*/ SystemClock.uptimeMillis(),
ArtStatsLog.ART_DATUM_REPORTED__THREAD_TYPE__ART_THREAD_MAIN,
kind,
value,
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index bad7e5c..dab980a 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -641,7 +641,7 @@
// Cell Broadcast Receiver
grantSystemFixedPermissionsToSystemPackage(pm,
getDefaultSystemHandlerActivityPackage(pm, Intents.SMS_CB_RECEIVED_ACTION, userId),
- userId, SMS_PERMISSIONS);
+ userId, SMS_PERMISSIONS, NEARBY_DEVICES_PERMISSIONS);
// Carrier Provisioning Service
grantPermissionsToSystemPackage(pm,
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 a391dbc..38e9d3e 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -5720,10 +5720,8 @@
boolean fromDatasource, int attributedOp) {
// Now let's check the identity chain...
final int op = AppOpsManager.permissionToOpCode(permission);
- final int attributionChainId = (startDataDelivery)
- ? sAttributionChainIds.incrementAndGet()
- : AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE;
-
+ final int attributionChainId =
+ getAttributionChainId(startDataDelivery, attributionSource);
AttributionSource current = attributionSource;
AttributionSource next = null;
@@ -5879,9 +5877,8 @@
return PermissionChecker.PERMISSION_HARD_DENIED;
}
- final int attributionChainId = (startDataDelivery)
- ? sAttributionChainIds.incrementAndGet()
- : AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE;
+ final int attributionChainId =
+ getAttributionChainId(startDataDelivery, attributionSource);
AttributionSource current = attributionSource;
AttributionSource next = null;
@@ -6064,6 +6061,21 @@
}
}
+ private static int getAttributionChainId(boolean startDataDelivery,
+ AttributionSource source) {
+ if (source == null || source.getNext() == null || !startDataDelivery) {
+ return AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE;
+ }
+ int attributionChainId = sAttributionChainIds.incrementAndGet();
+
+ // handle overflow
+ if (attributionChainId < 0) {
+ attributionChainId = 0;
+ sAttributionChainIds.set(0);
+ }
+ return attributionChainId;
+ }
+
private static @Nullable String resolvePackageName(@NonNull Context context,
@NonNull AttributionSource attributionSource) {
if (attributionSource.getPackageName() != null) {
diff --git a/services/core/java/com/android/server/vibrator/StepToRampAdapter.java b/services/core/java/com/android/server/vibrator/StepToRampAdapter.java
index d439b94..1d8c64b 100644
--- a/services/core/java/com/android/server/vibrator/StepToRampAdapter.java
+++ b/services/core/java/com/android/server/vibrator/StepToRampAdapter.java
@@ -22,6 +22,7 @@
import android.os.vibrator.StepSegment;
import android.os.vibrator.VibrationEffectSegment;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -59,6 +60,7 @@
convertStepsToRamps(segments);
int newRepeatIndex = addRampDownToZeroAmplitudeSegments(segments, repeatIndex);
newRepeatIndex = addRampDownToLoop(segments, newRepeatIndex);
+ newRepeatIndex = splitLongRampSegments(info, segments, newRepeatIndex);
return newRepeatIndex;
}
@@ -210,11 +212,70 @@
return repeatIndex;
}
+ /**
+ * Split {@link RampSegment} entries that have duration longer than {@link
+ * VibratorInfo#getPwlePrimitiveDurationMax()}.
+ */
+ private int splitLongRampSegments(VibratorInfo info, List<VibrationEffectSegment> segments,
+ int repeatIndex) {
+ int maxDuration = info.getPwlePrimitiveDurationMax();
+ if (maxDuration <= 0) {
+ // No limit set to PWLE primitive duration.
+ return repeatIndex;
+ }
+
+ int segmentCount = segments.size();
+ for (int i = 0; i < segmentCount; i++) {
+ if (!(segments.get(i) instanceof RampSegment)) {
+ continue;
+ }
+ RampSegment ramp = (RampSegment) segments.get(i);
+ int splits = ((int) ramp.getDuration() + maxDuration - 1) / maxDuration;
+ if (splits <= 1) {
+ continue;
+ }
+ segments.remove(i);
+ segments.addAll(i, splitRampSegment(ramp, splits));
+ int addedSegments = splits - 1;
+ if (repeatIndex > i) {
+ repeatIndex += addedSegments;
+ }
+ i += addedSegments;
+ segmentCount += addedSegments;
+ }
+
+ return repeatIndex;
+ }
+
private static RampSegment apply(StepSegment segment) {
return new RampSegment(segment.getAmplitude(), segment.getAmplitude(),
segment.getFrequency(), segment.getFrequency(), (int) segment.getDuration());
}
+ private static List<RampSegment> splitRampSegment(RampSegment ramp, int splits) {
+ List<RampSegment> ramps = new ArrayList<>(splits);
+ long splitDuration = ramp.getDuration() / splits;
+ float previousAmplitude = ramp.getStartAmplitude();
+ float previousFrequency = ramp.getStartFrequency();
+ long accumulatedDuration = 0;
+
+ for (int i = 1; i < splits; i++) {
+ accumulatedDuration += splitDuration;
+ RampSegment rampSplit = new RampSegment(
+ previousAmplitude, interpolateAmplitude(ramp, accumulatedDuration),
+ previousFrequency, interpolateFrequency(ramp, accumulatedDuration),
+ (int) splitDuration);
+ ramps.add(rampSplit);
+ previousAmplitude = rampSplit.getEndAmplitude();
+ previousFrequency = rampSplit.getEndFrequency();
+ }
+
+ ramps.add(new RampSegment(previousAmplitude, ramp.getEndAmplitude(), previousFrequency,
+ ramp.getEndFrequency(), (int) (ramp.getDuration() - accumulatedDuration)));
+
+ return ramps;
+ }
+
private static RampSegment createRampDown(float amplitude, float frequency, long duration) {
return new RampSegment(amplitude, /* endAmplitude= */ 0, frequency, frequency,
(int) duration);
@@ -244,4 +305,19 @@
}
return false;
}
+
+ private static float interpolateAmplitude(RampSegment ramp, long duration) {
+ return interpolate(ramp.getStartAmplitude(), ramp.getEndAmplitude(), duration,
+ ramp.getDuration());
+ }
+
+ private static float interpolateFrequency(RampSegment ramp, long duration) {
+ return interpolate(ramp.getStartFrequency(), ramp.getEndFrequency(), duration,
+ ramp.getDuration());
+ }
+
+ private static float interpolate(float start, float end, long duration, long totalDuration) {
+ float position = (float) duration / totalDuration;
+ return start + position * (end - start);
+ }
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 782e18b..7713320 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -405,20 +405,10 @@
needsExtraction = wallpaper.primaryColors == null;
}
- // Let's notify the current values, it's fine if it's null, it just means
- // that we don't know yet.
- notifyColorListeners(wallpaper.primaryColors, which, wallpaper.userId, displayId);
-
if (needsExtraction) {
extractColors(wallpaper);
- synchronized (mLock) {
- // Don't need to notify if nothing changed.
- if (wallpaper.primaryColors == null) {
- return;
- }
- }
- notifyColorListeners(wallpaper.primaryColors, which, wallpaper.userId, displayId);
}
+ notifyColorListeners(wallpaper.primaryColors, which, wallpaper.userId, displayId);
}
private static <T extends IInterface> boolean emptyCallbackList(RemoteCallbackList<T> list) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 55d1920..0ad8782 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -38,6 +38,7 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
@@ -277,6 +278,7 @@
import android.os.Trace;
import android.os.UserHandle;
import android.os.storage.StorageManager;
+import android.service.contentcapture.ActivityEvent;
import android.service.dreams.DreamActivity;
import android.service.dreams.DreamManagerInternal;
import android.service.voice.IVoiceInteractionSession;
@@ -327,6 +329,7 @@
import com.android.server.LocalServices;
import com.android.server.am.AppTimeTracker;
import com.android.server.am.PendingIntentRecord;
+import com.android.server.contentcapture.ContentCaptureManagerInternal;
import com.android.server.display.color.ColorDisplayService;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.uri.NeededUriGrants;
@@ -677,8 +680,6 @@
private boolean mInSizeCompatModeForBounds = false;
// Whether the aspect ratio restrictions applied to the activity bounds in applyAspectRatio().
- // TODO(b/182268157): Aspect ratio can also be applie in resolveFixedOrientationConfiguration
- // but that isn't reflected in this boolean.
private boolean mIsAspectRatioApplied = false;
// Bounds populated in resolveFixedOrientationConfiguration when this activity is letterboxed
@@ -1788,17 +1789,19 @@
/**
* Evaluate the theme for a starting window.
+ * @param prev Previous activity which may have a starting window.
* @param originalTheme The original theme which read from activity or application.
* @param replaceTheme The replace theme which requested from starter.
* @return Resolved theme.
*/
- private int evaluateStartingWindowTheme(String pkg, int originalTheme, int replaceTheme) {
+ private int evaluateStartingWindowTheme(ActivityRecord prev, String pkg, int originalTheme,
+ int replaceTheme) {
// Skip if the package doesn't want a starting window.
- if (!validateStartingWindowTheme(pkg, originalTheme)) {
+ if (!validateStartingWindowTheme(prev, pkg, originalTheme)) {
return 0;
}
int selectedTheme = originalTheme;
- if (replaceTheme != 0 && validateStartingWindowTheme(pkg, replaceTheme)) {
+ if (replaceTheme != 0 && validateStartingWindowTheme(prev, pkg, replaceTheme)) {
// allow to replace theme
selectedTheme = replaceTheme;
}
@@ -1835,7 +1838,7 @@
return LAUNCH_SOURCE_TYPE_APPLICATION;
}
- private boolean validateStartingWindowTheme(String pkg, int theme) {
+ private boolean validateStartingWindowTheme(ActivityRecord prev, String pkg, int theme) {
// If this is a translucent window, then don't show a starting window -- the current
// effect (a full-screen opaque starting window that fades away to the real contents
// when it is ready) does not work for this.
@@ -1872,7 +1875,11 @@
return false;
}
if (windowDisableStarting && !launchedFromSystemSurface()) {
- return false;
+ // Check if previous activity can transfer the starting window to this activity.
+ return prev != null && prev.getActivityType() == ACTIVITY_TYPE_STANDARD
+ && prev.mTransferringSplashScreenState == TRANSFER_SPLASH_SCREEN_IDLE
+ && (prev.mStartingData != null
+ || (prev.mStartingWindow != null && prev.mStartingSurface != null));
}
return true;
}
@@ -4873,6 +4880,12 @@
true /* activityChange */, true /* updateOomAdj */,
true /* addPendingTopUid */);
}
+ final ContentCaptureManagerInternal contentCaptureService =
+ LocalServices.getService(ContentCaptureManagerInternal.class);
+ if (contentCaptureService != null) {
+ contentCaptureService.notifyActivityEvent(mUserId, mActivityComponent,
+ ActivityEvent.TYPE_ACTIVITY_STARTED);
+ }
break;
case PAUSED:
mAtmService.updateBatteryStats(this, false);
@@ -6278,15 +6291,21 @@
mSplashScreenStyleEmpty = shouldUseEmptySplashScreen(sourceRecord);
- final int resolvedTheme = evaluateStartingWindowTheme(packageName, theme,
+ final int resolvedTheme = evaluateStartingWindowTheme(prev, packageName, theme,
splashScreenTheme);
+ final boolean activityCreated =
+ mState.ordinal() >= STARTED.ordinal() && mState.ordinal() <= STOPPED.ordinal();
+ // If this activity is just created and all activities below are finish, treat this
+ // scenario as warm launch.
+ final boolean newSingleActivity = !newTask && !activityCreated
+ && task.getActivity((r) -> !r.finishing && r != this) == null;
+
final boolean shown = addStartingWindow(packageName, resolvedTheme,
compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
- prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning(),
- allowTaskSnapshot(),
- mState.ordinal() >= STARTED.ordinal() && mState.ordinal() <= STOPPED.ordinal(),
- mSplashScreenStyleEmpty);
+ prev != null ? prev.appToken : null,
+ newTask || newSingleActivity, taskSwitch, isProcessRunning(),
+ allowTaskSnapshot(), activityCreated, mSplashScreenStyleEmpty);
if (shown) {
mStartingWindowState = STARTING_WINDOW_SHOWN;
}
@@ -7266,41 +7285,48 @@
}
final Rect parentBounds = newParentConfig.windowConfiguration.getBounds();
- final int parentWidth = parentBounds.width();
- final int parentHeight = parentBounds.height();
- float aspect = Math.max(parentWidth, parentHeight)
- / (float) Math.min(parentWidth, parentHeight);
+ final Rect parentAppBounds = newParentConfig.windowConfiguration.getAppBounds();
+ final Rect containingBounds = new Rect();
+ final Rect containingAppBounds = new Rect();
+ // Need to shrink the containing bounds into a square because the parent orientation does
+ // not match the activity requested orientation.
+ if (forcedOrientation == ORIENTATION_LANDSCAPE) {
+ // Shrink height to match width. Position height within app bounds.
+ final int bottom = Math.min(parentAppBounds.top + parentBounds.width(),
+ parentAppBounds.bottom);
+ containingBounds.set(parentBounds.left, parentAppBounds.top, parentBounds.right,
+ bottom);
+ containingAppBounds.set(parentAppBounds.left, parentAppBounds.top,
+ parentAppBounds.right, bottom);
+ } else {
+ // Shrink width to match height. Position width within app bounds.
+ final int right = Math.min(parentAppBounds.left + parentBounds.height(),
+ parentAppBounds.right);
+ containingBounds.set(parentAppBounds.left, parentBounds.top, right,
+ parentBounds.bottom);
+ containingAppBounds.set(parentAppBounds.left, parentAppBounds.top, right,
+ parentAppBounds.bottom);
+ }
+
+ Rect mTmpFullBounds = new Rect(resolvedBounds);
+ resolvedBounds.set(containingBounds);
// Override from config_fixedOrientationLetterboxAspectRatio or via ADB with
// set-fixed-orientation-letterbox-aspect-ratio.
final float letterboxAspectRatioOverride =
mWmService.mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio();
- aspect = letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO
- ? letterboxAspectRatioOverride : aspect;
+ final float desiredAspectRatio =
+ letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO
+ ? letterboxAspectRatioOverride : computeAspectRatio(parentBounds);
+ // Apply aspect ratio to resolved bounds
+ mIsAspectRatioApplied = applyAspectRatio(resolvedBounds, containingAppBounds,
+ containingBounds, desiredAspectRatio, true);
- // Adjust the fixed orientation letterbox bounds to fit the app request aspect ratio in
- // order to use the extra available space.
- final float maxAspectRatio = info.getMaxAspectRatio();
- final float minAspectRatio = info.getMinAspectRatio();
- if (aspect > maxAspectRatio && maxAspectRatio != 0) {
- aspect = maxAspectRatio;
- } else if (aspect < minAspectRatio) {
- aspect = minAspectRatio;
- }
-
- // Store the current bounds to be able to revert to size compat mode values below if needed.
- Rect mTmpFullBounds = new Rect(resolvedBounds);
+ // Vertically center if orientation is landscape. Bounds will later be horizontally centered
+ // in {@link updateResolvedBoundsHorizontalPosition()} regardless of orientation.
if (forcedOrientation == ORIENTATION_LANDSCAPE) {
- final int height = (int) Math.rint(parentWidth / aspect);
- final int top = parentBounds.centerY() - height / 2;
- resolvedBounds.set(parentBounds.left, top, parentBounds.right, top + height);
- } else {
- final int width = (int) Math.rint(parentHeight / aspect);
- final Rect parentAppBounds = newParentConfig.windowConfiguration.getAppBounds();
- final int left = width <= parentAppBounds.width()
- // Avoid overlapping with the horizontal decor area when possible.
- ? parentAppBounds.left : parentBounds.centerX() - width / 2;
- resolvedBounds.set(left, parentBounds.top, left + width, parentBounds.bottom);
+ final int offsetY = parentBounds.centerY() - resolvedBounds.centerY();
+ resolvedBounds.offset(0, offsetY);
}
if (mCompatDisplayInsets != null) {
@@ -7342,8 +7368,6 @@
// then they should be aligned later in #updateResolvedBoundsHorizontalPosition().
if (!mTmpBounds.isEmpty()) {
resolvedBounds.set(mTmpBounds);
- // Exclude the horizontal decor area.
- resolvedBounds.left = parentAppBounds.left;
}
if (!resolvedBounds.isEmpty() && !resolvedBounds.equals(parentBounds)) {
// Compute the configuration based on the resolved bounds. If aspect ratio doesn't
@@ -7404,13 +7428,6 @@
mIsAspectRatioApplied =
applyAspectRatio(resolvedBounds, containingAppBounds, containingBounds);
}
- // If the bounds are restricted by fixed aspect ratio, the resolved bounds should be put in
- // the container app bounds. Otherwise the entire container bounds are available.
- final boolean fillContainer = resolvedBounds.equals(containingBounds);
- if (!fillContainer) {
- // The horizontal position should not cover insets.
- resolvedBounds.left = containingAppBounds.left;
- }
// Use resolvedBounds to compute other override configurations such as appBounds. The bounds
// are calculated in compat container space. The actual position on screen will be applied
@@ -7477,6 +7494,7 @@
// Align to top of parent (bounds) - this is a UX choice and exclude the horizontal decor
// if needed. Horizontal position is adjusted in updateResolvedBoundsHorizontalPosition.
// Above coordinates are in "@" space, now place "*" and "#" to screen space.
+ final boolean fillContainer = resolvedBounds.equals(containingBounds);
final int screenPosX = fillContainer ? containerBounds.left : containerAppBounds.left;
final int screenPosY = containerBounds.top;
if (screenPosX != 0 || screenPosY != 0) {
@@ -7713,6 +7731,12 @@
return true;
}
+ private boolean applyAspectRatio(Rect outBounds, Rect containingAppBounds,
+ Rect containingBounds) {
+ return applyAspectRatio(outBounds, containingAppBounds, containingBounds,
+ 0 /* desiredAspectRatio */, false /* fixedOrientationLetterboxed */);
+ }
+
/**
* Applies aspect ratio restrictions to outBounds. If no restrictions, then no change is
* made to outBounds.
@@ -7721,17 +7745,19 @@
*/
// TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
private boolean applyAspectRatio(Rect outBounds, Rect containingAppBounds,
- Rect containingBounds) {
+ Rect containingBounds, float desiredAspectRatio, boolean fixedOrientationLetterboxed) {
final float maxAspectRatio = info.getMaxAspectRatio();
final Task rootTask = getRootTask();
final float minAspectRatio = info.getMinAspectRatio();
if (task == null || rootTask == null
- || (inMultiWindowMode() && !shouldCreateCompatDisplayInsets())
- || (maxAspectRatio == 0 && minAspectRatio == 0)
+ || (inMultiWindowMode() && !shouldCreateCompatDisplayInsets()
+ && !fixedOrientationLetterboxed)
+ || (maxAspectRatio < 1 && minAspectRatio < 1 && desiredAspectRatio < 1)
|| isInVrUiMode(getConfiguration())) {
- // We don't enforce aspect ratio if the activity task is in multiwindow unless it
- // is in size-compat mode. We also don't set it if we are in VR mode.
+ // We don't enforce aspect ratio if the activity task is in multiwindow unless it is in
+ // size-compat mode or is letterboxed from fixed orientation. We also don't set it if we
+ // are in VR mode.
return false;
}
@@ -7739,20 +7765,30 @@
final int containingAppHeight = containingAppBounds.height();
final float containingRatio = computeAspectRatio(containingAppBounds);
+ if (desiredAspectRatio < 1) {
+ desiredAspectRatio = containingRatio;
+ }
+
+ if (maxAspectRatio >= 1 && desiredAspectRatio > maxAspectRatio) {
+ desiredAspectRatio = maxAspectRatio;
+ } else if (minAspectRatio >= 1 && desiredAspectRatio < minAspectRatio) {
+ desiredAspectRatio = minAspectRatio;
+ }
+
int activityWidth = containingAppWidth;
int activityHeight = containingAppHeight;
- if (containingRatio > maxAspectRatio && maxAspectRatio != 0) {
+ if (containingRatio > desiredAspectRatio) {
if (containingAppWidth < containingAppHeight) {
// Width is the shorter side, so we use that to figure-out what the max. height
// should be given the aspect ratio.
- activityHeight = (int) ((activityWidth * maxAspectRatio) + 0.5f);
+ activityHeight = (int) ((activityWidth * desiredAspectRatio) + 0.5f);
} else {
// Height is the shorter side, so we use that to figure-out what the max. width
// should be given the aspect ratio.
- activityWidth = (int) ((activityHeight * maxAspectRatio) + 0.5f);
+ activityWidth = (int) ((activityHeight * desiredAspectRatio) + 0.5f);
}
- } else if (containingRatio < minAspectRatio) {
+ } else if (containingRatio < desiredAspectRatio) {
boolean adjustWidth;
switch (getRequestedConfigurationOrientation()) {
case ORIENTATION_LANDSCAPE:
@@ -7780,9 +7816,9 @@
break;
}
if (adjustWidth) {
- activityWidth = (int) ((activityHeight / minAspectRatio) + 0.5f);
+ activityWidth = (int) ((activityHeight / desiredAspectRatio) + 0.5f);
} else {
- activityHeight = (int) ((activityWidth / minAspectRatio) + 0.5f);
+ activityHeight = (int) ((activityWidth / desiredAspectRatio) + 0.5f);
}
}
@@ -7806,6 +7842,13 @@
}
outBounds.set(containingBounds.left, containingBounds.top, right, bottom);
+ // If the bounds are restricted by fixed aspect ratio, then out bounds should be put in the
+ // container app bounds. Otherwise the entire container bounds are available.
+ if (!outBounds.equals(containingBounds)) {
+ // The horizontal position should not cover insets.
+ outBounds.left = containingAppBounds.left;
+ }
+
return true;
}
diff --git a/services/core/java/com/android/server/wm/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java
index 0ec0142..2ea043a 100644
--- a/services/core/java/com/android/server/wm/CompatModePackages.java
+++ b/services/core/java/com/android/server/wm/CompatModePackages.java
@@ -75,10 +75,18 @@
* CompatModePackages#DOWNSCALED is the gatekeeper of all per-app buffer downscaling
* changes. Disabling this change will prevent the following scaling factors from working:
* CompatModePackages#DOWNSCALE_90
+ * CompatModePackages#DOWNSCALE_85
* CompatModePackages#DOWNSCALE_80
+ * CompatModePackages#DOWNSCALE_75
* CompatModePackages#DOWNSCALE_70
+ * CompatModePackages#DOWNSCALE_65
* CompatModePackages#DOWNSCALE_60
+ * CompatModePackages#DOWNSCALE_55
* CompatModePackages#DOWNSCALE_50
+ * CompatModePackages#DOWNSCALE_45
+ * CompatModePackages#DOWNSCALE_40
+ * CompatModePackages#DOWNSCALE_35
+ * CompatModePackages#DOWNSCALE_30
*
* If CompatModePackages#DOWNSCALED is enabled for an app package, then the app will be forcibly
* resized to the highest enabled scaling factor e.g. 80% if both 80% and 70% were enabled.
@@ -100,6 +108,16 @@
/**
* With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
+ * CompatModePackages#DOWNSCALE_85 for a package will force the app to assume it's
+ * running on a display with 85% the vertical and horizontal resolution of the real display.
+ */
+ @ChangeId
+ @Disabled
+ @Overridable
+ public static final long DOWNSCALE_85 = 189969734L;
+
+ /**
+ * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
* CompatModePackages#DOWNSCALE_80 for a package will force the app to assume it's
* running on a display with 80% the vertical and horizontal resolution of the real display.
*/
@@ -110,6 +128,16 @@
/**
* With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
+ * CompatModePackages#DOWNSCALE_75 for a package will force the app to assume it's
+ * running on a display with 75% the vertical and horizontal resolution of the real display.
+ */
+ @ChangeId
+ @Disabled
+ @Overridable
+ public static final long DOWNSCALE_75 = 189969779L;
+
+ /**
+ * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
* CompatModePackages#DOWNSCALE_70 for a package will force the app to assume it's
* running on a display with 70% the vertical and horizontal resolution of the real display.
*/
@@ -120,6 +148,16 @@
/**
* With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
+ * CompatModePackages#DOWNSCALE_65 for a package will force the app to assume it's
+ * running on a display with 65% the vertical and horizontal resolution of the real display.
+ */
+ @ChangeId
+ @Disabled
+ @Overridable
+ public static final long DOWNSCALE_65 = 189969744L;
+
+ /**
+ * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
* CompatModePackages#DOWNSCALE_60 for a package will force the app to assume it's
* running on a display with 60% the vertical and horizontal resolution of the real display.
*/
@@ -130,6 +168,16 @@
/**
* With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
+ * CompatModePackages#DOWNSCALE_55 for a package will force the app to assume it's
+ * running on a display with 55% the vertical and horizontal resolution of the real display.
+ */
+ @ChangeId
+ @Disabled
+ @Overridable
+ public static final long DOWNSCALE_55 = 189970036L;
+
+ /**
+ * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
* CompatModePackages#DOWNSCALE_50 for a package will force the app to assume it's
* running on a display with 50% vertical and horizontal resolution of the real display.
*/
@@ -139,6 +187,46 @@
public static final long DOWNSCALE_50 = 176926741L;
/**
+ * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
+ * CompatModePackages#DOWNSCALE_45 for a package will force the app to assume it's
+ * running on a display with 45% the vertical and horizontal resolution of the real display.
+ */
+ @ChangeId
+ @Disabled
+ @Overridable
+ public static final long DOWNSCALE_45 = 189969782L;
+
+ /**
+ * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
+ * CompatModePackages#DOWNSCALE_40 for a package will force the app to assume it's
+ * running on a display with 40% the vertical and horizontal resolution of the real display.
+ */
+ @ChangeId
+ @Disabled
+ @Overridable
+ public static final long DOWNSCALE_40 = 189970038L;
+
+ /**
+ * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
+ * CompatModePackages#DOWNSCALE_35 for a package will force the app to assume it's
+ * running on a display with 35% the vertical and horizontal resolution of the real display.
+ */
+ @ChangeId
+ @Disabled
+ @Overridable
+ public static final long DOWNSCALE_35 = 189969749L;
+
+ /**
+ * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
+ * CompatModePackages#DOWNSCALE_30 for a package will force the app to assume it's
+ * running on a display with 30% the vertical and horizontal resolution of the real display.
+ */
+ @ChangeId
+ @Disabled
+ @Overridable
+ public static final long DOWNSCALE_30 = 189970040L;
+
+ /**
* On Android TV applications that target pre-S are not expecting to receive a Window larger
* than 1080p, so if needed we are downscaling their Windows to 1080p.
* However, applications that target S and greater release version are expected to be able to
@@ -291,18 +379,42 @@
if (CompatChanges.isChangeEnabled(DOWNSCALE_90, packageName, userHandle)) {
return 1f / 0.9f;
}
+ if (CompatChanges.isChangeEnabled(DOWNSCALE_85, packageName, userHandle)) {
+ return 1f / 0.85f;
+ }
if (CompatChanges.isChangeEnabled(DOWNSCALE_80, packageName, userHandle)) {
return 1f / 0.8f;
}
+ if (CompatChanges.isChangeEnabled(DOWNSCALE_75, packageName, userHandle)) {
+ return 1f / 0.75f;
+ }
if (CompatChanges.isChangeEnabled(DOWNSCALE_70, packageName, userHandle)) {
return 1f / 0.7f;
}
+ if (CompatChanges.isChangeEnabled(DOWNSCALE_65, packageName, userHandle)) {
+ return 1f / 0.65f;
+ }
if (CompatChanges.isChangeEnabled(DOWNSCALE_60, packageName, userHandle)) {
return 1f / 0.6f;
}
+ if (CompatChanges.isChangeEnabled(DOWNSCALE_55, packageName, userHandle)) {
+ return 1f / 0.55f;
+ }
if (CompatChanges.isChangeEnabled(DOWNSCALE_50, packageName, userHandle)) {
return 1f / 0.5f;
}
+ if (CompatChanges.isChangeEnabled(DOWNSCALE_45, packageName, userHandle)) {
+ return 1f / 0.45f;
+ }
+ if (CompatChanges.isChangeEnabled(DOWNSCALE_40, packageName, userHandle)) {
+ return 1f / 0.4f;
+ }
+ if (CompatChanges.isChangeEnabled(DOWNSCALE_35, packageName, userHandle)) {
+ return 1f / 0.35f;
+ }
+ if (CompatChanges.isChangeEnabled(DOWNSCALE_30, packageName, userHandle)) {
+ return 1f / 0.3f;
+ }
}
if (mService.mHasLeanbackFeature) {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index c510603..bc2556a 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -221,6 +221,9 @@
// transaction from the global transaction.
private final SurfaceControl.Transaction mDisplayTransaction;
+ // The tag for the token to put root tasks on the displays to sleep.
+ private static final String DISPLAY_OFF_SLEEP_TOKEN_TAG = "Display-off";
+
/** The token acquirer to put root tasks on the displays to sleep */
final ActivityTaskManagerInternal.SleepTokenAcquirer mDisplayOffTokenAcquirer;
@@ -450,7 +453,7 @@
mService = service.mAtmService;
mTaskSupervisor = mService.mTaskSupervisor;
mTaskSupervisor.mRootWindowContainer = this;
- mDisplayOffTokenAcquirer = mService.new SleepTokenAcquirerImpl("Display-off");
+ mDisplayOffTokenAcquirer = mService.new SleepTokenAcquirerImpl(DISPLAY_OFF_SLEEP_TOKEN_TAG);
}
boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
@@ -2654,12 +2657,14 @@
Slog.d(TAG, "Remove non-exist sleep token: " + token + " from " + Debug.getCallers(6));
}
mSleepTokens.remove(token.mHashKey);
-
final DisplayContent display = getDisplayContent(token.mDisplayId);
if (display != null) {
display.mAllSleepTokens.remove(token);
if (display.mAllSleepTokens.isEmpty()) {
mService.updateSleepIfNeededLocked();
+ if (token.mTag.equals(DISPLAY_OFF_SLEEP_TOKEN_TAG)) {
+ display.mSkipAppTransitionAnimation = true;
+ }
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2c8fceb..147260b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -34,6 +34,7 @@
import static android.content.pm.PackageManager.FEATURE_PC;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+import static android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE;
import static android.os.Process.SYSTEM_UID;
import static android.os.Process.myPid;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
@@ -2545,12 +2546,13 @@
// We will leave the critical section before returning the leash to the client,
// so we need to copy the leash to prevent others release the one that we are
// about to return.
- // TODO: We will have an extra copy if the client is not local.
- // For now, we rely on GC to release it.
- // Maybe we can modify InsetsSourceControl.writeToParcel so it can release
- // the extra leash as soon as possible.
- outControls[i] = controls[i] != null
- ? new InsetsSourceControl(controls[i]) : null;
+ if (controls[i] != null) {
+ // This source control is an extra copy if the client is not local. By setting
+ // PARCELABLE_WRITE_RETURN_VALUE, the leash will be released at the end of
+ // SurfaceControl.writeToParcel.
+ outControls[i] = new InsetsSourceControl(controls[i]);
+ outControls[i].setParcelableFlags(PARCELABLE_WRITE_RETURN_VALUE);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 9a6e444..4471f6c 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -683,8 +683,9 @@
}
// We don't apply animation for application main window here since this window type
- // should be controlled by AppWindowToken in general.
- if (mAttrType != TYPE_BASE_APPLICATION) {
+ // should be controlled by ActivityRecord in general. Wallpaper is also excluded because
+ // WallpaperController should handle it.
+ if (mAttrType != TYPE_BASE_APPLICATION && !mIsWallpaper) {
applyAnimationLocked(transit, true);
}
diff --git a/services/net/Android.bp b/services/net/Android.bp
index dd864ae..a822257 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -51,7 +51,6 @@
// All the classes in netd_aidl_interface must be jarjar so they do not conflict with the
// classes generated by netd_aidl_interfaces-platform-java above.
"netd_aidl_interface-V3-java",
- "netlink-client",
"networkstack-client",
"modules-utils-build_system",
],
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index 9706d7f..e3e2708 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -37,6 +37,7 @@
import android.provider.DeviceConfig;
import android.util.Log;
+import com.android.internal.R;
import com.android.server.IoThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -302,8 +303,15 @@
return;
}
+ if (!getUploaderEnabledConfig(getContext())) {
+ return;
+ }
+
new Thread(() -> {
try {
+ Context context = getContext();
+ final String uploaderPkg = getUploaderPackageName(context);
+ final String uploaderAction = getUploaderActionName(context);
String reportUuid = mIProfcollect.report();
final int profileId = getBBProfileId();
@@ -317,13 +325,12 @@
}
Intent uploadIntent =
- new Intent("com.google.android.apps.betterbug.intent.action.UPLOAD_PROFILE")
- .setPackage("com.google.android.apps.internal.betterbug")
+ new Intent(uploaderAction)
+ .setPackage(uploaderPkg)
.putExtra("EXTRA_DESTINATION", "PROFCOLLECT")
.putExtra("EXTRA_PACKAGE_NAME", getContext().getPackageName())
.putExtra("EXTRA_PROFILE_PATH", reportPath)
.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- Context context = getContext();
List<ResolveInfo> receivers =
context.getPackageManager().queryBroadcastReceivers(uploadIntent, 0);
@@ -356,4 +363,19 @@
}
return UserHandle.USER_SYSTEM;
}
+
+ private boolean getUploaderEnabledConfig(Context context) {
+ return context.getResources().getBoolean(
+ R.bool.config_profcollectReportUploaderEnabled);
+ }
+
+ private String getUploaderPackageName(Context context) {
+ return context.getResources().getString(
+ R.string.config_defaultProfcollectReportUploaderApp);
+ }
+
+ private String getUploaderActionName(Context context) {
+ return context.getResources().getString(
+ R.string.config_defaultProfcollectReportUploaderAction);
+ }
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
index e99113d..acf50b45 100644
--- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
@@ -323,6 +323,8 @@
when(mPowerManager.newWakeLock(anyInt(), anyString())).thenReturn(mWakeLock);
doNothing().when(mWakeLock).acquire();
doNothing().when(mAlarmManager).set(anyInt(), anyLong(), anyString(), any(), any());
+ doNothing().when(mAlarmManager)
+ .setWindow(anyInt(), anyLong(), anyLong(), anyString(), any(), any());
doReturn(mock(Sensor.class)).when(mSensorManager)
.getDefaultSensor(eq(Sensor.TYPE_SIGNIFICANT_MOTION), eq(true));
doReturn(true).when(mSensorManager).registerListener(any(), any(), anyInt());
@@ -1043,24 +1045,28 @@
mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE);
inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked(
- longThat(l -> l == mConstants.LIGHT_IDLE_TIMEOUT));
+ longThat(l -> l == mConstants.LIGHT_IDLE_TIMEOUT),
+ longThat(l -> l == mConstants.LIGHT_IDLE_TIMEOUT_INITIAL_FLEX));
// Should just alternate between IDLE and IDLE_MAINTENANCE now.
mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked(
- longThat(l -> l >= mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET));
+ longThat(l -> l >= mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET),
+ longThat(l -> l == mConstants.FLEX_TIME_SHORT));
mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE);
inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked(
- longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT));
+ longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT),
+ longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT_INITIAL_FLEX));
mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked(
- longThat(l -> l >= mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET));
+ longThat(l -> l >= mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET),
+ longThat(l -> l == mConstants.FLEX_TIME_SHORT));
// Test that motion doesn't reset the idle timeout.
mDeviceIdleController.handleMotionDetectedLocked(50, "test");
@@ -1068,7 +1074,8 @@
mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE);
inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked(
- longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT));
+ longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT),
+ longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT_INITIAL_FLEX));
}
///////////////// EXIT conditions ///////////////////
@@ -1824,9 +1831,9 @@
.forClass(AlarmManager.OnAlarmListener.class);
final ArgumentCaptor<AlarmManager.OnAlarmListener> motionRegistrationAlarmListener =
ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
- doNothing().when(mAlarmManager).set(anyInt(), anyLong(), eq("DeviceIdleController.motion"),
- motionAlarmListener.capture(), any());
- doNothing().when(mAlarmManager).set(anyInt(), anyLong(),
+ doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(),
+ eq("DeviceIdleController.motion"), motionAlarmListener.capture(), any());
+ doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(),
eq("DeviceIdleController.motion_registration"),
motionRegistrationAlarmListener.capture(), any());
@@ -1900,9 +1907,9 @@
mInjector.nowElapsed += mConstants.QUICK_DOZE_DELAY_TIMEOUT;
final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListener = ArgumentCaptor
.forClass(AlarmManager.OnAlarmListener.class);
- doNothing().when(mAlarmManager)
- .set(anyInt(), anyLong(), eq("DeviceIdleController.motion"), any(), any());
- doNothing().when(mAlarmManager).set(anyInt(), anyLong(),
+ doNothing().when(mAlarmManager).setWindow(
+ anyInt(), anyLong(), anyLong(), eq("DeviceIdleController.motion"), any(), any());
+ doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(),
eq("DeviceIdleController.motion_registration"),
alarmListener.capture(), any());
ArgumentCaptor<TriggerEventListener> listenerCaptor =
@@ -1944,9 +1951,9 @@
mInjector.nowElapsed += mConstants.QUICK_DOZE_DELAY_TIMEOUT;
final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListener = ArgumentCaptor
.forClass(AlarmManager.OnAlarmListener.class);
- doNothing().when(mAlarmManager)
- .set(anyInt(), anyLong(), eq("DeviceIdleController.motion"), any(), any());
- doNothing().when(mAlarmManager).set(anyInt(), anyLong(),
+ doNothing().when(mAlarmManager).setWindow(
+ anyInt(), anyLong(), anyLong(), eq("DeviceIdleController.motion"), any(), any());
+ doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(),
eq("DeviceIdleController.motion_registration"),
alarmListener.capture(), any());
ArgumentCaptor<SensorEventListener> listenerCaptor =
diff --git a/services/tests/mockingservicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java b/services/tests/mockingservicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java
index da0b83e..28fcaee 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java
@@ -21,7 +21,6 @@
import static com.google.common.truth.Truth.assertThat;
import android.os.SystemClock;
-import android.os.UserHandle;
import android.provider.DeviceConfig;
import androidx.test.core.app.ApplicationProvider;
@@ -63,7 +62,6 @@
public void testCreateExtraStatsLocked_samplingIntervalNotSet_returnsDefault() {
PlatformLogger logger = new PlatformLogger(
ApplicationProvider.getApplicationContext(),
- UserHandle.of(UserHandle.USER_NULL),
mAppSearchConfig);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
@@ -96,8 +94,7 @@
int putDocumentSamplingInterval = 1;
int batchCallSamplingInterval = 2;
PlatformLogger logger = new PlatformLogger(
- ApplicationProvider.getApplicationContext(),
- UserHandle.of(UserHandle.USER_NULL), mAppSearchConfig);
+ ApplicationProvider.getApplicationContext(), mAppSearchConfig);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
@@ -143,7 +140,6 @@
final String testPackageName = "packageName";
PlatformLogger logger = new PlatformLogger(
ApplicationProvider.getApplicationContext(),
- UserHandle.of(UserHandle.USER_NULL),
mAppSearchConfig);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
@@ -162,7 +158,6 @@
final String testPackageName = "packageName";
PlatformLogger logger = new PlatformLogger(
ApplicationProvider.getApplicationContext(),
- UserHandle.of(UserHandle.USER_NULL),
mAppSearchConfig);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
@@ -186,7 +181,6 @@
final String testPackageName = "packageName";
PlatformLogger logger = new PlatformLogger(
ApplicationProvider.getApplicationContext(),
- UserHandle.of(UserHandle.USER_NULL),
mAppSearchConfig);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
@@ -214,7 +208,6 @@
final String testPackageName = "packageName";
PlatformLogger logger = new PlatformLogger(
ApplicationProvider.getApplicationContext(),
- UserHandle.of(UserHandle.USER_NULL),
mAppSearchConfig);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssGeofenceProxyTest.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssGeofenceProxyTest.java
index b480f24..5e219a2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssGeofenceProxyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssGeofenceProxyTest.java
@@ -18,6 +18,7 @@
import static com.google.common.truth.Truth.assertThat;
+import android.content.Context;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
@@ -49,6 +50,7 @@
private static final int NOTIFICATION_RESPONSIVENESS = 0;
private static final int UNKNOWN_TIMER = 0;
+ private @Mock Context mContext;
private @Mock GnssConfiguration mMockConfiguration;
private @Mock GnssNative.GeofenceCallbacks mGeofenceCallbacks;
@@ -63,7 +65,7 @@
GnssNative.setGnssHalForTest(mFakeHal);
GnssNative gnssNative = Objects.requireNonNull(
- GnssNative.create(new TestInjector(), mMockConfiguration));
+ GnssNative.create(new TestInjector(mContext), mMockConfiguration));
gnssNative.setGeofenceCallbacks(mGeofenceCallbacks);
mTestProvider = new GnssGeofenceProxy(gnssNative);
gnssNative.register();
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeAppOpsHelper.java b/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeAppOpsHelper.java
index 3d03781..d728451 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeAppOpsHelper.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeAppOpsHelper.java
@@ -29,9 +29,10 @@
public class FakeAppOpsHelper extends AppOpsHelper {
private static class AppOp {
- private boolean mAllowed = true;
- private boolean mStarted = false;
- private int mNoteCount = 0;
+ AppOp() {}
+ boolean mAllowed = true;
+ boolean mStarted = false;
+ int mNoteCount = 0;
}
private final HashMap<String, SparseArray<AppOp>> mAppOps;
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeSettingsHelper.java b/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeSettingsHelper.java
index f1099f0..cd70020 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeSettingsHelper.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeSettingsHelper.java
@@ -29,8 +29,8 @@
import java.util.concurrent.CopyOnWriteArrayList;
/**
- * Version of AppOpsHelper for testing. Settings are initialized to reasonable defaults (location is
- * enabled by default).
+ * Version of SettingsHelper for testing. Settings are initialized to reasonable defaults (location
+ * is enabled by default).
*/
public class FakeSettingsHelper extends SettingsHelper {
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java b/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java
index ae70dad..bd24cfd 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java
@@ -16,9 +16,14 @@
package com.android.server.location.injector;
+import android.content.Context;
+
+import com.android.server.location.settings.FakeLocationSettings;
+
public class TestInjector implements Injector {
private final FakeUserInfoHelper mUserInfoHelper;
+ private final FakeLocationSettings mLocationSettings;
private final FakeAlarmHelper mAlarmHelper;
private final FakeAppOpsHelper mAppOpsHelper;
private final FakeLocationPermissionsHelper mLocationPermissionsHelper;
@@ -32,8 +37,9 @@
private final FakeEmergencyHelper mEmergencyHelper;
private final LocationUsageLogger mLocationUsageLogger;
- public TestInjector() {
+ public TestInjector(Context context) {
mUserInfoHelper = new FakeUserInfoHelper();
+ mLocationSettings = new FakeLocationSettings(context);
mAlarmHelper = new FakeAlarmHelper();
mAppOpsHelper = new FakeAppOpsHelper();
mLocationPermissionsHelper = new FakeLocationPermissionsHelper(mAppOpsHelper);
@@ -54,6 +60,11 @@
}
@Override
+ public FakeLocationSettings getLocationSettings() {
+ return mLocationSettings;
+ }
+
+ @Override
public FakeAlarmHelper getAlarmHelper() {
return mAlarmHelper;
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
index 6bc3b60..f703e2e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
@@ -19,6 +19,8 @@
import static android.app.AppOpsManager.OP_FINE_LOCATION;
import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION;
import static android.app.AppOpsManager.OP_MONITOR_LOCATION;
+import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
+import static android.location.LocationManager.GPS_PROVIDER;
import static android.location.LocationRequest.PASSIVE_INTERVAL;
import static android.location.provider.ProviderProperties.POWER_USAGE_HIGH;
import static android.os.PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF;
@@ -56,6 +58,8 @@
import static org.testng.Assert.assertThrows;
import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.location.ILocationCallback;
import android.location.ILocationListener;
import android.location.LastLocationRequest;
@@ -82,6 +86,7 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.R;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.location.injector.FakeUserInfoHelper;
@@ -139,6 +144,10 @@
@Mock
private Context mContext;
@Mock
+ private Resources mResources;
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
private PowerManager mPowerManager;
@Mock
private PowerManager.WakeLock mWakeLock;
@@ -161,20 +170,28 @@
LocalServices.addService(LocationManagerInternal.class, mInternal);
doReturn("android").when(mContext).getPackageName();
+ doReturn(mResources).when(mContext).getResources();
+ doReturn(mPackageManager).when(mContext).getPackageManager();
doReturn(mPowerManager).when(mContext).getSystemService(PowerManager.class);
doReturn(mWakeLock).when(mPowerManager).newWakeLock(anyInt(), anyString());
- mInjector = new TestInjector();
+ mInjector = new TestInjector(mContext);
mInjector.getUserInfoHelper().startUser(OTHER_USER);
mPassive = new PassiveLocationProviderManager(mContext, mInjector);
mPassive.startManager(null);
mPassive.setRealProvider(new PassiveLocationProvider(mContext));
+ createManager(NAME);
+ }
+
+ private void createManager(String name) {
+ mStateChangedListener = mock(LocationProviderManager.StateChangedListener.class);
+
mProvider = new TestProvider(PROPERTIES, PROVIDER_IDENTITY);
mProvider.setProviderAllowed(true);
- mManager = new LocationProviderManager(mContext, mInjector, NAME, mPassive);
+ mManager = new LocationProviderManager(mContext, mInjector, name, mPassive);
mManager.startManager(mStateChangedListener);
mManager.setRealProvider(mProvider);
}
@@ -1017,6 +1034,95 @@
}
@Test
+ public void testProviderRequest_AdasGnssBypass() {
+ doReturn(true).when(mPackageManager).hasSystemFeature(FEATURE_AUTOMOTIVE);
+ doReturn(true).when(mResources).getBoolean(R.bool.config_defaultAdasGnssLocationEnabled);
+
+ createManager(GPS_PROVIDER);
+
+ ILocationListener listener1 = createMockLocationListener();
+ LocationRequest request1 = new LocationRequest.Builder(5)
+ .setWorkSource(WORK_SOURCE)
+ .build();
+ mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
+
+ assertThat(mProvider.getRequest().isActive()).isTrue();
+ assertThat(mProvider.getRequest().getIntervalMillis()).isEqualTo(5);
+ assertThat(mProvider.getRequest().isAdasGnssBypass()).isFalse();
+
+ ILocationListener listener2 = createMockLocationListener();
+ LocationRequest request2 = new LocationRequest.Builder(1)
+ .setAdasGnssBypass(true)
+ .setWorkSource(WORK_SOURCE)
+ .build();
+ mManager.registerLocationRequest(request2, IDENTITY, PERMISSION_FINE, listener2);
+
+ assertThat(mProvider.getRequest().isActive()).isTrue();
+ assertThat(mProvider.getRequest().getIntervalMillis()).isEqualTo(1);
+ assertThat(mProvider.getRequest().isAdasGnssBypass()).isTrue();
+ }
+
+ @Test
+ public void testProviderRequest_AdasGnssBypass_ProviderDisabled() {
+ doReturn(true).when(mPackageManager).hasSystemFeature(FEATURE_AUTOMOTIVE);
+ doReturn(true).when(mResources).getBoolean(R.bool.config_defaultAdasGnssLocationEnabled);
+
+ createManager(GPS_PROVIDER);
+
+ ILocationListener listener1 = createMockLocationListener();
+ LocationRequest request1 = new LocationRequest.Builder(1)
+ .setWorkSource(WORK_SOURCE)
+ .build();
+ mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
+
+ ILocationListener listener2 = createMockLocationListener();
+ LocationRequest request2 = new LocationRequest.Builder(5)
+ .setAdasGnssBypass(true)
+ .setWorkSource(WORK_SOURCE)
+ .build();
+ mManager.registerLocationRequest(request2, IDENTITY, PERMISSION_FINE, listener2);
+
+ mInjector.getSettingsHelper().setLocationEnabled(false, IDENTITY.getUserId());
+
+ assertThat(mProvider.getRequest().isActive()).isTrue();
+ assertThat(mProvider.getRequest().getIntervalMillis()).isEqualTo(5);
+ assertThat(mProvider.getRequest().isAdasGnssBypass()).isTrue();
+ }
+
+ @Test
+ public void testProviderRequest_AdasGnssBypass_ProviderDisabled_AdasDisabled() {
+ mInjector.getSettingsHelper().setIgnoreSettingsAllowlist(
+ new PackageTagsList.Builder().add(
+ IDENTITY.getPackageName()).build());
+ doReturn(true).when(mPackageManager).hasSystemFeature(FEATURE_AUTOMOTIVE);
+ doReturn(true).when(mResources).getBoolean(R.bool.config_defaultAdasGnssLocationEnabled);
+
+ createManager(GPS_PROVIDER);
+
+ ILocationListener listener1 = createMockLocationListener();
+ LocationRequest request1 = new LocationRequest.Builder(5)
+ .setLocationSettingsIgnored(true)
+ .setWorkSource(WORK_SOURCE)
+ .build();
+ mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
+
+ ILocationListener listener2 = createMockLocationListener();
+ LocationRequest request2 = new LocationRequest.Builder(1)
+ .setAdasGnssBypass(true)
+ .setWorkSource(WORK_SOURCE)
+ .build();
+ mManager.registerLocationRequest(request2, IDENTITY, PERMISSION_FINE, listener2);
+
+ mInjector.getLocationSettings().updateUserSettings(IDENTITY.getUserId(),
+ settings -> settings.withAdasGnssLocationEnabled(false));
+ mInjector.getSettingsHelper().setLocationEnabled(false, IDENTITY.getUserId());
+
+ assertThat(mProvider.getRequest().isActive()).isTrue();
+ assertThat(mProvider.getRequest().getIntervalMillis()).isEqualTo(5);
+ assertThat(mProvider.getRequest().isAdasGnssBypass()).isFalse();
+ }
+
+ @Test
public void testProviderRequest_BatterySaver_ScreenOnOff() {
mInjector.getLocationPowerSaveModeHelper().setLocationPowerSaveMode(
LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF);
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/StationaryThrottlingLocationProviderTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/StationaryThrottlingLocationProviderTest.java
index 04e0151..63996f0 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/provider/StationaryThrottlingLocationProviderTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/StationaryThrottlingLocationProviderTest.java
@@ -27,6 +27,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.MockitoAnnotations.initMocks;
+import android.content.Context;
import android.location.Location;
import android.location.LocationResult;
import android.location.provider.ProviderRequest;
@@ -58,6 +59,7 @@
private TestInjector mInjector;
private FakeProvider mDelegateProvider;
+ private @Mock Context mContext;
private @Mock AbstractLocationProvider.Listener mListener;
private @Mock FakeProvider.FakeProviderInterface mDelegate;
@@ -72,7 +74,7 @@
mRandom = new Random(seed);
- mInjector = new TestInjector();
+ mInjector = new TestInjector(mContext);
mDelegateProvider = new FakeProvider(mDelegate);
mProvider = new StationaryThrottlingLocationProvider("test_provider", mInjector,
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/settings/FakeLocationSettings.java b/services/tests/mockingservicestests/src/com/android/server/location/settings/FakeLocationSettings.java
new file mode 100644
index 0000000..4d46aba
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/location/settings/FakeLocationSettings.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location.settings;
+
+import android.content.Context;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import java.io.File;
+
+public class FakeLocationSettings extends LocationSettings {
+
+ public FakeLocationSettings(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected File getUserSettingsDir(int userId) {
+ return ApplicationProvider.getApplicationContext().getCacheDir();
+ }
+
+ @Override
+ protected LocationUserSettingsStore createUserSettingsStore(int userId, File file) {
+ return new FakeLocationUserSettingsStore(userId, file);
+ }
+
+ private class FakeLocationUserSettingsStore extends LocationUserSettingsStore {
+
+ FakeLocationUserSettingsStore(int userId, File file) {
+ super(userId, file);
+ }
+
+ @Override
+ protected void onChange(LocationUserSettings oldSettings,
+ LocationUserSettings newSettings) {
+ fireListeners(mUserId, oldSettings, newSettings);
+ }
+ }
+}
+
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/settings/LocationSettingsTest.java b/services/tests/mockingservicestests/src/com/android/server/location/settings/LocationSettingsTest.java
new file mode 100644
index 0000000..4b6c79b
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/location/settings/LocationSettingsTest.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location.settings;
+
+import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.after;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.R;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+
+import java.io.File;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LocationSettingsTest {
+
+ private @Mock Context mContext;
+ private @Mock Resources mResources;
+ private @Mock PackageManager mPackageManager;
+
+ private LocationSettings mLocationSettings;
+
+ @Before
+ public void setUp() {
+ initMocks(this);
+
+ doReturn(mResources).when(mContext).getResources();
+ doReturn(mPackageManager).when(mContext).getPackageManager();
+ doReturn(true).when(mPackageManager).hasSystemFeature(FEATURE_AUTOMOTIVE);
+
+ resetLocationSettings();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mLocationSettings.deleteFiles();
+ }
+
+ private void resetLocationSettings() {
+ mLocationSettings = new LocationSettings(mContext) {
+ @Override
+ protected File getUserSettingsDir(int userId) {
+ return ApplicationProvider.getApplicationContext().getCacheDir();
+ }
+ };
+ }
+
+ @Test
+ public void testLoadDefaults() {
+ doReturn(true).when(mResources).getBoolean(R.bool.config_defaultAdasGnssLocationEnabled);
+ assertThat(mLocationSettings.getUserSettings(1).isAdasGnssLocationEnabled()).isTrue();
+
+ doReturn(false).when(mResources).getBoolean(R.bool.config_defaultAdasGnssLocationEnabled);
+ assertThat(mLocationSettings.getUserSettings(2).isAdasGnssLocationEnabled()).isFalse();
+ }
+
+ @Test
+ public void testUpdate() {
+ doReturn(false).when(mResources).getBoolean(R.bool.config_defaultAdasGnssLocationEnabled);
+ mLocationSettings.updateUserSettings(1,
+ settings -> settings.withAdasGnssLocationEnabled(true));
+ assertThat(mLocationSettings.getUserSettings(1).isAdasGnssLocationEnabled()).isTrue();
+
+ mLocationSettings.updateUserSettings(1,
+ settings -> settings.withAdasGnssLocationEnabled(false));
+ assertThat(mLocationSettings.getUserSettings(1).isAdasGnssLocationEnabled()).isFalse();
+ }
+
+ @Test
+ public void testSerialization() throws Exception {
+ doReturn(false).when(mResources).getBoolean(R.bool.config_defaultAdasGnssLocationEnabled);
+ mLocationSettings.updateUserSettings(1,
+ settings -> settings.withAdasGnssLocationEnabled(true));
+ assertThat(mLocationSettings.getUserSettings(1).isAdasGnssLocationEnabled()).isTrue();
+
+ mLocationSettings.flushFiles();
+ resetLocationSettings();
+ assertThat(mLocationSettings.getUserSettings(1).isAdasGnssLocationEnabled()).isTrue();
+ }
+
+ @Test
+ public void testListeners() {
+ doReturn(false).when(mResources).getBoolean(R.bool.config_defaultAdasGnssLocationEnabled);
+ LocationSettings.LocationUserSettingsListener listener = mock(
+ LocationSettings.LocationUserSettingsListener.class);
+
+ mLocationSettings.registerLocationUserSettingsListener(listener);
+
+ ArgumentCaptor<LocationUserSettings> oldCaptor = ArgumentCaptor.forClass(
+ LocationUserSettings.class);
+ ArgumentCaptor<LocationUserSettings> newCaptor = ArgumentCaptor.forClass(
+ LocationUserSettings.class);
+ mLocationSettings.updateUserSettings(1,
+ settings -> settings.withAdasGnssLocationEnabled(true));
+ verify(listener, timeout(500).times(1)).onLocationUserSettingsChanged(eq(1),
+ oldCaptor.capture(), newCaptor.capture());
+ assertThat(oldCaptor.getValue().isAdasGnssLocationEnabled()).isFalse();
+ assertThat(newCaptor.getValue().isAdasGnssLocationEnabled()).isTrue();
+
+ oldCaptor = ArgumentCaptor.forClass(LocationUserSettings.class);
+ newCaptor = ArgumentCaptor.forClass(LocationUserSettings.class);
+ mLocationSettings.updateUserSettings(1,
+ settings -> settings.withAdasGnssLocationEnabled(false));
+ verify(listener, timeout(500).times(2)).onLocationUserSettingsChanged(eq(1),
+ oldCaptor.capture(), newCaptor.capture());
+ assertThat(oldCaptor.getValue().isAdasGnssLocationEnabled()).isTrue();
+ assertThat(newCaptor.getValue().isAdasGnssLocationEnabled()).isFalse();
+
+ mLocationSettings.unregisterLocationUserSettingsListener(listener);
+ mLocationSettings.updateUserSettings(1,
+ settings -> settings.withAdasGnssLocationEnabled(true));
+ verify(listener, after(500).times(2)).onLocationUserSettingsChanged(anyInt(), any(), any());
+ }
+
+ @Test
+ public void testNonAutomotive() {
+ doReturn(false).when(mPackageManager).hasSystemFeature(FEATURE_AUTOMOTIVE);
+ doReturn(true).when(mResources).getBoolean(R.bool.config_defaultAdasGnssLocationEnabled);
+
+ LocationSettings.LocationUserSettingsListener listener = mock(
+ LocationSettings.LocationUserSettingsListener.class);
+ mLocationSettings.registerLocationUserSettingsListener(listener);
+
+ assertThat(mLocationSettings.getUserSettings(1).isAdasGnssLocationEnabled()).isFalse();
+ mLocationSettings.updateUserSettings(1,
+ settings -> settings.withAdasGnssLocationEnabled(true));
+ assertThat(mLocationSettings.getUserSettings(1).isAdasGnssLocationEnabled()).isFalse();
+ verify(listener, after(500).never()).onLocationUserSettingsChanged(anyInt(), any(), any());
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
index 7d628be..68570ff 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
@@ -286,6 +286,7 @@
ApexSessionInfo activationFailed = new ApexSessionInfo();
activationFailed.sessionId = 1543;
activationFailed.isActivationFailed = true;
+ activationFailed.errorMessage = "Failed for test";
ApexSessionInfo staged = new ApexSessionInfo();
staged.sessionId = 101;
@@ -309,8 +310,8 @@
assertThat(apexSession1.getErrorCode())
.isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED);
- assertThat(apexSession1.getErrorMessage()).isEqualTo("APEX activation failed. Check logcat "
- + "messages from apexd for more information.");
+ assertThat(apexSession1.getErrorMessage()).isEqualTo("APEX activation failed. "
+ + "Failed for test");
assertThat(apexSession2.getErrorCode())
.isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED);
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java b/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java
index f4f9073..3c10789 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java
@@ -42,7 +42,7 @@
import com.android.compatibility.common.util.SystemUtil;
import com.android.server.appsearch.external.localstorage.util.PrefixUtil;
-import com.android.server.appsearch.visibilitystore.VisibilityStore;
+import com.android.server.appsearch.visibilitystore.VisibilityStoreImpl;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -67,7 +67,7 @@
private final Map<UserHandle, PackageManager> mMockPackageManagers = new ArrayMap<>();
private Context mContext;
private AppSearchImpl mAppSearchImpl;
- private VisibilityStore mVisibilityStore;
+ private VisibilityStoreImpl mVisibilityStore;
private int mGlobalQuerierUid;
@Before
@@ -93,7 +93,7 @@
// Give ourselves global query permissions
mAppSearchImpl = AppSearchImpl.create(
mTemporaryFolder.newFolder(), /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
- mVisibilityStore = VisibilityStore.create(mAppSearchImpl, mContext);
+ mVisibilityStore = VisibilityStoreImpl.create(mAppSearchImpl, mContext);
mGlobalQuerierUid =
mContext.getPackageManager().getPackageUid(mContext.getPackageName(), /*flags=*/ 0);
}
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java b/services/tests/servicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java
index 7c275e1..ec96d6a 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java
@@ -65,13 +65,8 @@
Context context = ApplicationProvider.getApplicationContext();
mContext = new ContextWrapper(context) {
@Override
- public Context createContextAsUser(UserHandle user, int flags) {
- return new ContextWrapper(super.createContextAsUser(user, flags)) {
- @Override
- public PackageManager getPackageManager() {
- return getMockPackageManager(user);
- }
- };
+ public PackageManager getPackageManager() {
+ return getMockPackageManager(mContext.getUser());
}
};
}
@@ -153,7 +148,6 @@
final int testUid = 1234;
PlatformLogger logger = new PlatformLogger(
mContext,
- mContext.getUser(),
AppSearchConfig.create(DIRECT_EXECUTOR));
PackageManager mockPackageManager = getMockPackageManager(mContext.getUser());
when(mockPackageManager.getPackageUid(testPackageName, /*flags=*/0)).thenReturn(testUid);
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java b/services/tests/servicestests/src/com/android/server/appsearch/visibilitystore/VisibilityStoreImplTest.java
similarity index 96%
rename from services/tests/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java
rename to services/tests/servicestests/src/com/android/server/appsearch/visibilitystore/VisibilityStoreImplTest.java
index 183cb86..07a728b 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/visibilitystore/VisibilityStoreImplTest.java
@@ -14,10 +14,7 @@
* limitations under the License.
*/
-// TODO(b/169883602): This is purposely a different package from the path so that it can access
-// AppSearchImpl methods without having to make methods public. This should be moved into a proper
-// package once AppSearchImpl-VisibilityStore's dependencies are refactored.
-package com.android.server.appsearch.external.localstorage;
+package com.android.server.appsearch.visibilitystore;
import static android.Manifest.permission.READ_GLOBAL_APP_SEARCH_DATA;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
@@ -39,8 +36,10 @@
import androidx.test.core.app.ApplicationProvider;
+import com.android.server.appsearch.external.localstorage.AppSearchImpl;
+import com.android.server.appsearch.external.localstorage.OptimizeStrategy;
import com.android.server.appsearch.external.localstorage.util.PrefixUtil;
-import com.android.server.appsearch.visibilitystore.VisibilityStore;
+import com.android.server.appsearch.external.localstorage.visibilitystore.VisibilityStore;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -55,7 +54,7 @@
import java.util.Collections;
import java.util.Map;
-public class VisibilityStoreTest {
+public class VisibilityStoreImplTest {
/**
* Always trigger optimize in this class. OptimizeStrategy will be tested in its own test class.
*/
@@ -64,7 +63,7 @@
@Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
private final Map<UserHandle, PackageManager> mMockPackageManagers = new ArrayMap<>();
private Context mContext;
- private VisibilityStore mVisibilityStore;
+ private VisibilityStoreImpl mVisibilityStore;
private int mUid;
@Before
@@ -90,7 +89,7 @@
// Give ourselves global query permissions
AppSearchImpl appSearchImpl = AppSearchImpl.create(
mTemporaryFolder.newFolder(), /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
- mVisibilityStore = VisibilityStore.create(appSearchImpl, mContext);
+ mVisibilityStore = VisibilityStoreImpl.create(appSearchImpl, mContext);
mUid = mContext.getPackageManager().getPackageUid(mContext.getPackageName(), /*flags=*/ 0);
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 019254d..c572dd6 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -785,7 +785,7 @@
}
@Override
- public void getNextPage(long nextPageToken, UserHandle userHandle,
+ public void getNextPage(String packageName, long nextPageToken, UserHandle userHandle,
IAppSearchResultCallback callback) throws RemoteException {
final Bundle page = new Bundle();
page.putLong(SearchResultPage.NEXT_PAGE_TOKEN_FIELD, 1);
@@ -795,8 +795,8 @@
}
@Override
- public void invalidateNextPageToken(long nextPageToken, UserHandle userHandle)
- throws RemoteException {
+ public void invalidateNextPageToken(String packageName, long nextPageToken,
+ UserHandle userHandle) throws RemoteException {
}
@Override
@@ -875,13 +875,13 @@
}
@Override
- public void persistToDisk(UserHandle userHandle, long binderCallStartTimeMillis)
- throws RemoteException {
+ public void persistToDisk(String packageName, UserHandle userHandle,
+ long binderCallStartTimeMillis) throws RemoteException {
}
@Override
- public void initialize(UserHandle userHandle, long binderCallStartTimeMillis,
- IAppSearchResultCallback callback)
+ public void initialize(String packageName, UserHandle userHandle,
+ long binderCallStartTimeMillis, IAppSearchResultCallback callback)
throws RemoteException {
ignore(callback);
}
diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
index f880563..9044b27 100644
--- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
@@ -222,61 +222,61 @@
}
/**
- * Tests that readPermissions works correctly with {@link SystemConfig#ALLOW_APP_CONFIGS}
- * permission flag for the tag: {@code allowed-partner-apex}.
+ * Tests that readPermissions works correctly with {@link SystemConfig#ALLOW_VENDOR_APEX}
+ * permission flag for the tag: {@code allowed-vendor-apex}.
*/
@Test
- public void readPermissions_allowAppConfigs_parsesPartnerApexAllowList()
+ public void readPermissions_allowVendorApex_parsesVendorApexAllowList()
throws IOException {
final String contents =
"<config>\n"
- + " <allowed-partner-apex package=\"com.android.apex1\" />\n"
+ + " <allowed-vendor-apex package=\"com.android.apex1\" />\n"
+ "</config>";
final File folder = createTempSubfolder("folder");
- createTempFile(folder, "partner-apex-allowlist.xml", contents);
+ createTempFile(folder, "vendor-apex-allowlist.xml", contents);
mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0);
- assertThat(mSysConfig.getAllowedPartnerApexes()).containsExactly("com.android.apex1");
+ assertThat(mSysConfig.getAllowedVendorApexes()).containsExactly("com.android.apex1");
}
/**
- * Tests that readPermissions works correctly with {@link SystemConfig#ALLOW_APP_CONFIGS}
- * permission flag for the tag: {@code allowed-partner-apex}.
+ * Tests that readPermissions works correctly with {@link SystemConfig#ALLOW_VENDOR_APEX}
+ * permission flag for the tag: {@code allowed-vendor-apex}.
*/
@Test
- public void readPermissions_allowAppConfigs_parsesPartnerApexAllowList_noPackage()
+ public void readPermissions_allowVendorApex_parsesVendorApexAllowList_noPackage()
throws IOException {
final String contents =
"<config>\n"
- + " <allowed-partner-apex/>\n"
+ + " <allowed-vendor-apex/>\n"
+ "</config>";
final File folder = createTempSubfolder("folder");
- createTempFile(folder, "partner-apex-allowlist.xml", contents);
+ createTempFile(folder, "vendor-apex-allowlist.xml", contents);
mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0);
- assertThat(mSysConfig.getAllowedPartnerApexes()).isEmpty();
+ assertThat(mSysConfig.getAllowedVendorApexes()).isEmpty();
}
/**
- * Tests that readPermissions works correctly without {@link SystemConfig#ALLOW_APP_CONFIGS}
- * permission flag for the tag: {@code allowed-partner-apex}.
+ * Tests that readPermissions works correctly without {@link SystemConfig#ALLOW_VENDOR_APEX}
+ * permission flag for the tag: {@code allowed-oem-apex}.
*/
@Test
- public void readPermissions_notAllowAppConfigs_doesNotParsePartnerApexAllowList()
+ public void readPermissions_notAllowVendorApex_doesNotParseVendorApexAllowList()
throws IOException {
final String contents =
"<config>\n"
- + " <allowed-partner-apex package=\"com.android.apex1\" />\n"
+ + " <allowed-vendor-apex package=\"com.android.apex1\" />\n"
+ "</config>";
final File folder = createTempSubfolder("folder");
- createTempFile(folder, "partner-apex-allowlist.xml", contents);
+ createTempFile(folder, "vendor-apex-allowlist.xml", contents);
- mSysConfig.readPermissions(folder, /* Grant all but ALLOW_APP_CONFIGS flag */ ~0x08);
+ mSysConfig.readPermissions(folder, /* Grant all but ALLOW_VENDOR_APEX flag */ ~0x400);
- assertThat(mSysConfig.getAllowedPartnerApexes()).isEmpty();
+ assertThat(mSysConfig.getAllowedVendorApexes()).isEmpty();
}
/**
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/StepToRampAdapterTest.java b/services/tests/servicestests/src/com/android/server/vibrator/StepToRampAdapterTest.java
index f4eb2de..32988ef 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/StepToRampAdapterTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/StepToRampAdapterTest.java
@@ -68,6 +68,38 @@
}
@Test
+ public void testRampSegments_withPwleDurationLimit_splitsLongRamps() {
+ List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+ new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude*/ 0.5f,
+ /* startFrequency= */ -1, /* endFrequency= */ -1, /* duration= */ 10),
+ new RampSegment(/* startAmplitude= */ 0, /* endAmplitude= */ 1,
+ /* startFrequency= */ 0, /* endFrequency= */ -1, /* duration= */ 25),
+ new RampSegment(/* startAmplitude= */ 1, /* endAmplitude*/ 1,
+ /* startFrequency= */ 0, /* endFrequency= */ 1, /* duration= */ 5)));
+ List<VibrationEffectSegment> expectedSegments = Arrays.asList(
+ new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude*/ 0.5f,
+ /* startFrequency= */ -1, /* endFrequency= */ -1, /* duration= */ 10),
+ new RampSegment(/* startAmplitude= */ 0, /* endAmplitude= */ 0.32f,
+ /* startFrequency= */ 0, /* endFrequency= */ -0.32f, /* duration= */ 8),
+ new RampSegment(/* startAmplitude= */ 0.32f, /* endAmplitude= */ 0.64f,
+ /* startFrequency= */ -0.32f, /* endFrequency= */ -0.64f,
+ /* duration= */ 8),
+ new RampSegment(/* startAmplitude= */ 0.64f, /* endAmplitude= */ 1,
+ /* startFrequency= */ -0.64f, /* endFrequency= */ -1, /* duration= */ 9),
+ new RampSegment(/* startAmplitude= */ 1, /* endAmplitude*/ 1,
+ /* startFrequency= */ 0, /* endFrequency= */ 1, /* duration= */ 5));
+
+ VibratorInfo vibratorInfo = new VibratorInfo.Builder(0)
+ .setCapabilities(IVibrator.CAP_COMPOSE_PWLE_EFFECTS)
+ .setPwlePrimitiveDurationMax(10)
+ .build();
+
+ // Update repeat index to skip the ramp splits.
+ assertEquals(4, mAdapter.apply(segments, 2, vibratorInfo));
+ assertEquals(expectedSegments, segments);
+ }
+
+ @Test
public void testStepAndRampSegments_withoutPwleCapability_keepsListUnchanged() {
mAdapter = new StepToRampAdapter(50);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 3862d75..71c05b5 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -48,6 +48,7 @@
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
+import android.app.KeyguardManager;
import android.app.Notification;
import android.app.Notification.Builder;
import android.app.NotificationChannel;
@@ -111,6 +112,8 @@
NotificationUsageStats mUsageStats;
@Mock
IAccessibilityManager mAccessibilityService;
+ @Mock
+ KeyguardManager mKeyguardManager;
NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake();
private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake(
1 << 30);
@@ -153,6 +156,7 @@
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
when(mUsageStats.isAlertRateLimited(any())).thenReturn(false);
when(mVibrator.hasFrequencyControl()).thenReturn(false);
+ when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(false);
long serviceReturnValue = IntPair.of(
AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED,
@@ -174,6 +178,7 @@
mService.setScreenOn(false);
mService.setUsageStats(mUsageStats);
mService.setAccessibilityManager(accessibilityManager);
+ mService.setKeyguardManager(mKeyguardManager);
mService.mScreenOn = false;
mService.mInCallStateOffHook = false;
mService.mNotificationPulseEnabled = true;
@@ -496,6 +501,94 @@
}
@Test
+ public void testLockedPrivateA11yRedaction() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ r.setPackageVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE);
+ r.getNotification().visibility = Notification.VISIBILITY_PRIVATE;
+ when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(true);
+ AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class);
+ when(accessibilityManager.isEnabled()).thenReturn(true);
+ mService.setAccessibilityManager(accessibilityManager);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ ArgumentCaptor<AccessibilityEvent> eventCaptor =
+ ArgumentCaptor.forClass(AccessibilityEvent.class);
+
+ verify(accessibilityManager, times(1))
+ .sendAccessibilityEvent(eventCaptor.capture());
+
+ AccessibilityEvent event = eventCaptor.getValue();
+ assertEquals(r.getNotification().publicVersion, event.getParcelableData());
+ }
+
+ @Test
+ public void testLockedOverridePrivateA11yRedaction() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ r.setPackageVisibilityOverride(Notification.VISIBILITY_PRIVATE);
+ r.getNotification().visibility = Notification.VISIBILITY_PUBLIC;
+ when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(true);
+ AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class);
+ when(accessibilityManager.isEnabled()).thenReturn(true);
+ mService.setAccessibilityManager(accessibilityManager);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ ArgumentCaptor<AccessibilityEvent> eventCaptor =
+ ArgumentCaptor.forClass(AccessibilityEvent.class);
+
+ verify(accessibilityManager, times(1))
+ .sendAccessibilityEvent(eventCaptor.capture());
+
+ AccessibilityEvent event = eventCaptor.getValue();
+ assertEquals(r.getNotification().publicVersion, event.getParcelableData());
+ }
+
+ @Test
+ public void testLockedPublicA11yNoRedaction() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ r.setPackageVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE);
+ r.getNotification().visibility = Notification.VISIBILITY_PUBLIC;
+ when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(true);
+ AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class);
+ when(accessibilityManager.isEnabled()).thenReturn(true);
+ mService.setAccessibilityManager(accessibilityManager);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ ArgumentCaptor<AccessibilityEvent> eventCaptor =
+ ArgumentCaptor.forClass(AccessibilityEvent.class);
+
+ verify(accessibilityManager, times(1))
+ .sendAccessibilityEvent(eventCaptor.capture());
+
+ AccessibilityEvent event = eventCaptor.getValue();
+ assertEquals(r.getNotification(), event.getParcelableData());
+ }
+
+ @Test
+ public void testUnlockedPrivateA11yNoRedaction() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ r.setPackageVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE);
+ r.getNotification().visibility = Notification.VISIBILITY_PRIVATE;
+ when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(false);
+ AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class);
+ when(accessibilityManager.isEnabled()).thenReturn(true);
+ mService.setAccessibilityManager(accessibilityManager);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ ArgumentCaptor<AccessibilityEvent> eventCaptor =
+ ArgumentCaptor.forClass(AccessibilityEvent.class);
+
+ verify(accessibilityManager, times(1))
+ .sendAccessibilityEvent(eventCaptor.capture());
+
+ AccessibilityEvent event = eventCaptor.getValue();
+ assertEquals(r.getNotification(), event.getParcelableData());
+ }
+
+ @Test
public void testBeepInsistently() throws Exception {
NotificationRecord r = getInsistentBeepyNotification();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index a522b5c..1f543a1 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -94,6 +94,7 @@
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
@@ -2425,6 +2426,8 @@
when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(),
eq(mTestNotificationChannel.getId()), anyBoolean()))
.thenReturn(mTestNotificationChannel);
+ when(mPreferencesHelper.deleteNotificationChannel(eq(PKG), anyInt(),
+ eq(mTestNotificationChannel.getId()))).thenReturn(true);
reset(mListeners);
mBinderService.deleteNotificationChannel(PKG, mTestNotificationChannel.getId());
verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(PKG),
@@ -2433,6 +2436,22 @@
}
@Test
+ public void testDeleteChannelOnlyDoExtraWorkIfExisted() throws Exception {
+ List<String> associations = new ArrayList<>();
+ associations.add("a");
+ when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+ .thenReturn(associations);
+ mService.setPreferencesHelper(mPreferencesHelper);
+ when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(),
+ eq(mTestNotificationChannel.getId()), anyBoolean()))
+ .thenReturn(null);
+ reset(mListeners);
+ mBinderService.deleteNotificationChannel(PKG, mTestNotificationChannel.getId());
+ verifyNoMoreInteractions(mListeners);
+ verifyNoMoreInteractions(mHistoryManager);
+ }
+
+ @Test
public void testDeleteChannelGroupNotifyListener() throws Exception {
List<String> associations = new ArrayList<>();
associations.add("a");
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 3a51ff2..23da02c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -3333,6 +3333,17 @@
}
@Test
+ public void testDeleted_twice() throws Exception {
+ mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
+ mAppOpsManager, mStatsEventBuilderFactory);
+
+ mHelper.createNotificationChannel(
+ PKG_P, UID_P, createNotificationChannel("id", "id", 2), true, false);
+ assertTrue(mHelper.deleteNotificationChannel(PKG_P, UID_P, "id"));
+ assertFalse(mHelper.deleteNotificationChannel(PKG_P, UID_P, "id"));
+ }
+
+ @Test
public void testDeleted_recentTime() throws Exception {
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
mAppOpsManager, mStatsEventBuilderFactory);
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 4e261de..4872ec5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -401,6 +401,7 @@
assertFitted();
final Rect currentBounds = mActivity.getWindowConfiguration().getBounds();
+ final Rect currentAppBounds = mActivity.getWindowConfiguration().getAppBounds();
final Rect originalBounds = new Rect(mActivity.getWindowConfiguration().getBounds());
final int notchHeight = 100;
@@ -428,8 +429,8 @@
// Because the display cannot rotate, the portrait activity will fit the short side of
// display with keeping portrait bounds [200, 0 - 700, 1000] in center.
assertEquals(newDisplayBounds.height(), currentBounds.height());
- assertEquals(currentBounds.height() * newDisplayBounds.height() / newDisplayBounds.width(),
- currentBounds.width());
+ assertEquals(currentAppBounds.height() * newDisplayBounds.height()
+ / newDisplayBounds.width(), currentAppBounds.width());
assertFitted();
// The appBounds should be [200, 100 - 700, 1000].
final Rect appBounds = mActivity.getWindowConfiguration().getAppBounds();
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 128602d..1b84927 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -2226,7 +2226,14 @@
}
@Override
- public long getLastTimeAnyComponentUsed(String packageName) {
+ public long getLastTimeAnyComponentUsed(String packageName, String callingPackage) {
+ if (!hasPermissions(
+ callingPackage, android.Manifest.permission.INTERACT_ACROSS_USERS)) {
+ throw new SecurityException("Caller doesn't have INTERACT_ACROSS_USERS permission");
+ }
+ if (!hasPermission(callingPackage)) {
+ throw new SecurityException("Don't have permission to query usage stats");
+ }
synchronized (mLock) {
// Truncate the returned milliseconds to the boundary of the last day before exact
// time for privacy reasons.
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index eac21b4..5183e5b 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -863,7 +863,12 @@
}
private void enforceCallingPermission(String permission) {
- PermissionUtil.checkPermissionForPreflight(mContext, mOriginatorIdentity, permission);
+ if (PermissionUtil.checkPermissionForPreflight(mContext, mOriginatorIdentity,
+ permission) != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException(
+ "Identity " + mOriginatorIdentity + " does not have permission "
+ + permission);
+ }
}
private void enforceDetectionPermissions(ComponentName detectionService) {
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 1953af4..e000265 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1018,6 +1018,16 @@
// this magic number is a bug ID
public static final long ENABLE_GET_CALL_STATE_PERMISSION_PROTECTION = 157233955L;
+ /**
+ * Enable READ_PHONE_NUMBERS or READ_PRIVILEGED_PHONE_STATE protections on
+ * {@link TelecomManager#getPhoneAccount(PhoneAccountHandle)}.
+ * @hide
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
+ // bug ID
+ public static final long ENABLE_GET_PHONE_ACCOUNT_PERMISSION_PROTECTION = 183407956L;
+
private static final String TAG = "TelecomManager";
@@ -1351,6 +1361,9 @@
* Return the {@link PhoneAccount} for a specified {@link PhoneAccountHandle}. Object includes
* resources which can be used in a user interface.
*
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_NUMBERS} for applications targeting API
+ * level 31+.
* @param account The {@link PhoneAccountHandle}.
* @return The {@link PhoneAccount} object.
*/
@@ -1358,7 +1371,7 @@
ITelecomService service = getTelecomService();
if (service != null) {
try {
- return service.getPhoneAccount(account);
+ return service.getPhoneAccount(account, mContext.getPackageName());
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#getPhoneAccount", e);
}
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 18afde7..6f286d9 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -79,7 +79,7 @@
/**
* @see TelecomManager#getPhoneAccount
*/
- PhoneAccount getPhoneAccount(in PhoneAccountHandle account);
+ PhoneAccount getPhoneAccount(in PhoneAccountHandle account, String callingPackage);
/**
* @see TelecomManager#getAllPhoneAccountsCount
diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp
index c679d04..c563e06 100644
--- a/tests/StagedInstallTest/Android.bp
+++ b/tests/StagedInstallTest/Android.bp
@@ -52,6 +52,7 @@
data: [
":com.android.apex.apkrollback.test_v1",
":com.android.apex.cts.shim.v2_prebuilt",
+ ":StagedInstallTestApexV2_WrongSha",
":TestAppAv1",
],
test_suites: ["general-tests"],
diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
index e633c87..6a62304 100644
--- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
@@ -179,6 +179,26 @@
assertThat(info.isStagedSessionFailed()).isTrue();
}
+ @Test
+ public void testApexActivationFailureIsCapturedInSession_Commit() throws Exception {
+ int sessionId = Install.single(TestApp.Apex1).setStaged().commit();
+ assertSessionReady(sessionId);
+ storeSessionId(sessionId);
+ }
+
+ @Test
+ public void testApexActivationFailureIsCapturedInSession_Verify() throws Exception {
+ int sessionId = retrieveLastSessionId();
+ assertSessionFailedWithMessage(sessionId, "has unexpected SHA512 hash");
+ }
+
+ private static void assertSessionFailedWithMessage(int sessionId, String msg) {
+ assertSessionState(sessionId, (session) -> {
+ assertThat(session.isStagedSessionFailed()).isTrue();
+ assertThat(session.getStagedSessionErrorMessage()).contains(msg);
+ });
+ }
+
private static void assertSessionReady(int sessionId) {
assertSessionState(sessionId,
(session) -> assertThat(session.isStagedSessionReady()).isTrue());
diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
index ccd63f9..5d7fdd1 100644
--- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
@@ -56,6 +56,7 @@
@Rule
public AbandonSessionsRule mHostTestRule = new AbandonSessionsRule(this);
private static final String SHIM_V2 = "com.android.apex.cts.shim.v2.apex";
+ private static final String APEX_WRONG_SHA = "com.android.apex.cts.shim.v2_wrong_sha.apex";
private static final String APK_A = "TestAppAv1.apk";
private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test";
@@ -322,6 +323,27 @@
runPhase("testFailStagedSessionIfStagingDirectoryDeleted_Verify");
}
+ @Test
+ public void testApexActivationFailureIsCapturedInSession() throws Exception {
+ // We initiate staging a normal apex update which passes pre-reboot verification.
+ // Then we replace the valid apex waiting in /data/app-staging with something
+ // that cannot be activated and reboot. The apex should fail to activate, which
+ // is what we want for this test.
+ runPhase("testApexActivationFailureIsCapturedInSession_Commit");
+ final String sessionId = getDevice().executeShellCommand(
+ "pm get-stagedsessions --only-ready --only-parent --only-sessionid").trim();
+ assertThat(sessionId).isNotEmpty();
+ // Now replace the valid staged apex with something invalid
+ getDevice().enableAdbRoot();
+ getDevice().executeShellCommand("rm /data/app-staging/session_" + sessionId + "/*");
+ final File invalidApexFile = mHostUtils.getTestFile(APEX_WRONG_SHA);
+ getDevice().pushFile(invalidApexFile,
+ "/data/app-staging/session_" + sessionId + "/base.apex");
+ getDevice().reboot();
+
+ runPhase("testApexActivationFailureIsCapturedInSession_Verify");
+ }
+
private List<String> getStagingDirectories() throws DeviceNotAvailableException {
String baseDir = "/data/app-staging";
try {
diff --git a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
index 4ce78aa..dc338ae 100644
--- a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
@@ -20,6 +20,8 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -70,6 +72,14 @@
public static final String GATEWAY_CONNECTION_NAME_PREFIX = "gatewayConnectionName-";
private static int sGatewayConnectionConfigCount = 0;
+ private static VcnGatewayConnectionConfig buildTestConfig(
+ String gatewayConnectionName, IkeTunnelConnectionParams tunnelConnectionParams) {
+ return buildTestConfigWithExposedCaps(
+ new VcnGatewayConnectionConfig.Builder(
+ gatewayConnectionName, tunnelConnectionParams),
+ EXPOSED_CAPS);
+ }
+
// Public for use in VcnGatewayConnectionTest
public static VcnGatewayConnectionConfig buildTestConfig() {
return buildTestConfigWithExposedCaps(EXPOSED_CAPS);
@@ -83,10 +93,9 @@
TUNNEL_CONNECTION_PARAMS);
}
- // Public for use in VcnGatewayConnectionTest
- public static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps(int... exposedCaps) {
- final VcnGatewayConnectionConfig.Builder builder =
- newBuilder().setRetryIntervalsMillis(RETRY_INTERVALS_MS).setMaxMtu(MAX_MTU);
+ private static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps(
+ VcnGatewayConnectionConfig.Builder builder, int... exposedCaps) {
+ builder.setRetryIntervalsMillis(RETRY_INTERVALS_MS).setMaxMtu(MAX_MTU);
for (int caps : exposedCaps) {
builder.addExposedCapability(caps);
@@ -95,6 +104,11 @@
return builder.build();
}
+ // Public for use in VcnGatewayConnectionTest
+ public static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps(int... exposedCaps) {
+ return buildTestConfigWithExposedCaps(newBuilder(), exposedCaps);
+ }
+
@Test
public void testBuilderRequiresNonNullGatewayConnectionName() {
try {
@@ -193,4 +207,46 @@
assertEquals(config, new VcnGatewayConnectionConfig(config.toPersistableBundle()));
}
+
+ private static IkeTunnelConnectionParams buildTunnelConnectionParams(String ikePsk) {
+ final IkeSessionParams ikeParams =
+ IkeSessionParamsUtilsTest.createBuilderMinimum()
+ .setAuthPsk(ikePsk.getBytes())
+ .build();
+ return TunnelConnectionParamsUtilsTest.buildTestParams(ikeParams);
+ }
+
+ @Test
+ public void testTunnelConnectionParamsEquals() throws Exception {
+ final String connectionName = "testTunnelConnectionParamsEquals.connectionName";
+ final String psk = "testTunnelConnectionParamsEquals.psk";
+
+ final IkeTunnelConnectionParams tunnelParams = buildTunnelConnectionParams(psk);
+ final VcnGatewayConnectionConfig config = buildTestConfig(connectionName, tunnelParams);
+
+ final IkeTunnelConnectionParams anotherTunnelParams = buildTunnelConnectionParams(psk);
+ final VcnGatewayConnectionConfig anotherConfig =
+ buildTestConfig(connectionName, anotherTunnelParams);
+
+ assertNotSame(tunnelParams, anotherTunnelParams);
+ assertEquals(tunnelParams, anotherTunnelParams);
+ assertEquals(config, anotherConfig);
+ }
+
+ @Test
+ public void testTunnelConnectionParamsNotEquals() throws Exception {
+ final String connectionName = "testTunnelConnectionParamsNotEquals.connectionName";
+
+ final IkeTunnelConnectionParams tunnelParams =
+ buildTunnelConnectionParams("testTunnelConnectionParamsNotEquals.pskA");
+ final VcnGatewayConnectionConfig config = buildTestConfig(connectionName, tunnelParams);
+
+ final IkeTunnelConnectionParams anotherTunnelParams =
+ buildTunnelConnectionParams("testTunnelConnectionParamsNotEquals.pskB");
+ final VcnGatewayConnectionConfig anotherConfig =
+ buildTestConfig(connectionName, anotherTunnelParams);
+
+ assertNotEquals(tunnelParams, anotherTunnelParams);
+ assertNotEquals(config, anotherConfig);
+ }
}