Merge "Adding verbose check on handleSendEvent logs to avoid spamming logcat" 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/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index f28c760..e469b1f 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -42,10 +42,10 @@
import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.util.Log;
-import android.util.Pair;
import android.util.Slog;
import android.view.Display;
import android.view.DisplayAdjustments;
+import android.view.DisplayInfo;
import android.window.WindowContext;
import com.android.internal.annotations.VisibleForTesting;
@@ -56,7 +56,6 @@
import java.io.PrintWriter;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
-import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
@@ -251,12 +250,6 @@
new WeakHashMap<>();
/**
- * A cache of DisplayId, DisplayAdjustments to Display.
- */
- private final ArrayMap<Pair<Integer, DisplayAdjustments>, SoftReference<Display>>
- mAdjustedDisplays = new ArrayMap<>();
-
- /**
* Callback implementation for handling updates to Resources objects.
*/
private final UpdateHandler mUpdateCallbacks = new UpdateHandler();
@@ -331,10 +324,12 @@
*/
@VisibleForTesting
protected @NonNull DisplayMetrics getDisplayMetrics(int displayId, DisplayAdjustments da) {
- DisplayMetrics dm = new DisplayMetrics();
- final Display display = getAdjustedDisplay(displayId, da);
- if (display != null) {
- display.getMetrics(dm);
+ final DisplayManagerGlobal displayManagerGlobal = DisplayManagerGlobal.getInstance();
+ final DisplayMetrics dm = new DisplayMetrics();
+ final DisplayInfo displayInfo = displayManagerGlobal != null
+ ? displayManagerGlobal.getDisplayInfo(displayId) : null;
+ if (displayInfo != null) {
+ displayInfo.getAppMetrics(dm, da);
} else {
dm.setToDefaults();
}
@@ -376,45 +371,6 @@
/**
* Returns an adjusted {@link Display} object based on the inputs or null if display isn't
- * available. This method is only used within {@link ResourcesManager} to calculate display
- * metrics based on a set {@link DisplayAdjustments}. All other usages should instead call
- * {@link ResourcesManager#getAdjustedDisplay(int, Resources)}.
- *
- * @param displayId display Id.
- * @param displayAdjustments display adjustments.
- */
- private Display getAdjustedDisplay(final int displayId,
- @Nullable DisplayAdjustments displayAdjustments) {
- final DisplayAdjustments displayAdjustmentsCopy = (displayAdjustments != null)
- ? new DisplayAdjustments(displayAdjustments) : new DisplayAdjustments();
- final Pair<Integer, DisplayAdjustments> key =
- Pair.create(displayId, displayAdjustmentsCopy);
- SoftReference<Display> sd;
- synchronized (mLock) {
- sd = mAdjustedDisplays.get(key);
- }
- if (sd != null) {
- final Display display = sd.get();
- if (display != null) {
- return display;
- }
- }
- final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
- if (dm == null) {
- // may be null early in system startup
- return null;
- }
- final Display display = dm.getCompatibleDisplay(displayId, key.second);
- if (display != null) {
- synchronized (mLock) {
- mAdjustedDisplays.put(key, new SoftReference<>(display));
- }
- }
- return display;
- }
-
- /**
- * Returns an adjusted {@link Display} object based on the inputs or null if display isn't
* available.
*
* @param displayId display Id.
@@ -1332,9 +1288,6 @@
return false;
}
- // Things might have changed in display manager, so clear the cached displays.
- mAdjustedDisplays.clear();
-
int changes = mResConfiguration.updateFrom(config);
if (compat != null && (mResCompatibilityInfo == null
|| !mResCompatibilityInfo.equals(compat))) {
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/content/pm/parsing/component/ParsedIntentInfo.java b/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java
index 6b797bc..463a181 100644
--- a/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java
+++ b/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java
@@ -19,7 +19,6 @@
import android.annotation.Nullable;
import android.content.IntentFilter;
import android.os.Parcel;
-import android.os.Parcelable;
import android.util.Pair;
import com.android.internal.util.Parcelling;
@@ -167,19 +166,6 @@
+ '}';
}
- public static final Parcelable.Creator<ParsedIntentInfo> CREATOR =
- new Parcelable.Creator<ParsedIntentInfo>() {
- @Override
- public ParsedIntentInfo createFromParcel(Parcel source) {
- return new ParsedIntentInfo(source);
- }
-
- @Override
- public ParsedIntentInfo[] newArray(int size) {
- return new ParsedIntentInfo[size];
- }
- };
-
public boolean isHasDefault() {
return hasDefault;
}
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/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/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/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 4e66ceb..c03db6d 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -2610,16 +2610,6 @@
= sRegistry.registerNativeAllocation(this, mNativeObject);
}
- /**
- * Create a transaction object that wraps a native peer.
- * @hide
- */
- Transaction(long nativeObject) {
- mNativeObject = nativeObject;
- mFreeNativeResources =
- sRegistry.registerNativeAllocation(this, mNativeObject);
- }
-
private Transaction(Parcel in) {
readFromParcel(in);
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 573ae99..5a248af 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1371,8 +1371,12 @@
HardwareRenderer.ASurfaceTransactionCallback callback = (nativeTransactionObj,
nativeSurfaceControlObj,
frameNr) -> {
- Transaction t = new Transaction(nativeTransactionObj);
- mergeWithNextTransaction(t, frameNr);
+ if (mBlastBufferQueue == null) {
+ return false;
+ } else {
+ mBlastBufferQueue.mergeWithNextTransaction(nativeTransactionObj, frameNr);
+ return true;
+ }
};
mAttachInfo.mThreadedRenderer.setASurfaceTransactionCallback(callback);
}
@@ -5290,7 +5294,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 +8149,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 35200dc..e0a7bf2 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -370,7 +370,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/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 08db74f..7000ed7 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -464,8 +464,8 @@
private static final int SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED = 5;
private static final int LIST_VIEW_UPDATE_MESSAGE = 6;
- private static final int WATCHDOG_TIMEOUT_MAX_MILLIS = 10000;
- private static final int WATCHDOG_TIMEOUT_MIN_MILLIS = 3000;
+ private static final int WATCHDOG_TIMEOUT_MAX_MILLIS = 1000;
+ private static final int WATCHDOG_TIMEOUT_MIN_MILLIS = 300;
private boolean mMinTimeoutPassed = false;
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/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/drawable/chooser_direct_share_icon_placeholder.xml b/core/res/res/drawable/chooser_direct_share_icon_placeholder.xml
index 838cb49..bd8dba8 100644
--- a/core/res/res/drawable/chooser_direct_share_icon_placeholder.xml
+++ b/core/res/res/drawable/chooser_direct_share_icon_placeholder.xml
@@ -26,7 +26,7 @@
<group android:name="background">
<path android:pathData="M0,0 L 64,0 64,64 0,64 z"
- android:fillColor="@color/chooser_gradient_background"/>
+ android:fillColor="@android:color/transparent"/>
</group>
<!-- Gradient starts offscreen so it is not visible in the first frame before start -->
@@ -44,7 +44,7 @@
android:color="@android:color/transparent"
android:offset="0.0" />
<item
- android:color="@color/chooser_gradient_highlight"
+ android:color="@android:color/transparent"
android:offset="0.5" />
<item
android:color="@android:color/transparent"
@@ -58,7 +58,7 @@
shadow. Using clip-path is a more elegant solution but leaves awful jaggies around
the path's shape. -->
<group android:name="cover">
- <path android:fillColor="?attr/colorBackgroundFloating"
+ <path android:fillColor="@android:color/transparent"
android:pathData="M0,0 L64,0 L64,64 L0,64 L0,0 Z M59.0587325,42.453601 C60.3124932,39.2104785 61,35.6855272 61,32 C61,15.9837423 48.0162577,3 32,3 C15.9837423,3 3,15.9837423 3,32 C3,48.0162577 15.9837423,61 32,61 C35.6855272,61 39.2104785,60.3124932 42.453601,59.0587325 C44.3362195,60.2864794 46.5847839,61 49,61 C55.627417,61 61,55.627417 61,49 C61,46.5847839 60.2864794,44.3362195 59.0587325,42.453601 Z"/>
</group>
</vector>
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 302bd94..bcd121a 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1663,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 5f849b4..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" />
@@ -4018,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 -->
@@ -4404,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/graphics/java/android/graphics/BLASTBufferQueue.java b/graphics/java/android/graphics/BLASTBufferQueue.java
index 4534d36..6c1c2ee 100644
--- a/graphics/java/android/graphics/BLASTBufferQueue.java
+++ b/graphics/java/android/graphics/BLASTBufferQueue.java
@@ -131,4 +131,12 @@
nativeMergeWithNextTransaction(mNativeObject, t.mNativeObject, frameNumber);
}
+ /**
+ * Merge the transaction passed in to the next transaction in BlastBufferQueue.
+ * @param nativeTransaction native handle passed from native c/c++ code.
+ */
+ public void mergeWithNextTransaction(long nativeTransaction, long frameNumber) {
+ nativeMergeWithNextTransaction(mNativeObject, nativeTransaction, frameNumber);
+ }
+
}
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
index e141d51..30d1e0f 100644
--- a/graphics/java/android/graphics/HardwareRenderer.java
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -912,7 +912,7 @@
* @param aSurfaceControlNativeObj ASurfaceControl native object handle
* @param frame The id of the frame being drawn.
*/
- void onMergeTransaction(long aSurfaceTranactionNativeObj,
+ boolean onMergeTransaction(long aSurfaceTranactionNativeObj,
long aSurfaceControlNativeObj, long frame);
}
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 8aba87b..b994ad2 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -184,7 +184,6 @@
private PorterDuffColorFilter mMaskColorFilter;
private PorterDuffColorFilter mFocusColorFilter;
private boolean mHasValidMask;
- private int mComputedRadius = -1;
/** The current ripple. May be actively animating or pending entry. */
private RippleForeground mRipple;
@@ -390,8 +389,6 @@
if (mRipple != null) {
mRipple.onBoundsChange();
}
-
- mComputedRadius = Math.round(computeRadius());
invalidateSelf();
}
@@ -750,7 +747,7 @@
if (mBackground != null) {
mBackground.onHotspotBoundsChanged();
}
- float newRadius = Math.round(computeRadius());
+ float newRadius = Math.round(getComputedRadius());
for (int i = 0; i < mRunningAnimations.size(); i++) {
RippleAnimationSession s = mRunningAnimations.get(i);
s.setRadius(newRadius);
@@ -939,14 +936,13 @@
}
private float computeRadius() {
- Rect b = getDirtyBounds();
- float radius = (float) Math.sqrt(b.width() * b.width() + b.height() * b.height()) / 2;
- return radius;
+ final float halfWidth = mHotspotBounds.width() / 2.0f;
+ final float halfHeight = mHotspotBounds.height() / 2.0f;
+ return (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight);
}
private int getComputedRadius() {
if (mState.mMaxRadius >= 0) return mState.mMaxRadius;
- if (mComputedRadius >= 0) return mComputedRadius;
return (int) computeRadius();
}
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/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index b5c5402..bf75372 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -95,7 +95,6 @@
private final OneHandedTouchHandler mTouchHandler;
private final OneHandedState mState;
private final OneHandedTutorialHandler mTutorialHandler;
- private final OneHandedUiEventLogger mOneHandedUiEventLogger;
private final TaskStackListenerImpl mTaskStackListener;
private final IOverlayManager mOverlayManager;
private final ShellExecutor mMainExecutor;
@@ -105,6 +104,7 @@
private OneHandedEventCallback mEventCallback;
private OneHandedDisplayAreaOrganizer mDisplayAreaOrganizer;
private OneHandedBackgroundPanelOrganizer mBackgroundPanelOrganizer;
+ private OneHandedUiEventLogger mOneHandedUiEventLogger;
/**
* Handle rotation based on OnDisplayChangingListener callback
@@ -115,6 +115,8 @@
return;
}
mDisplayAreaOrganizer.onRotateDisplay(mContext, toRotation, wct);
+ mOneHandedUiEventLogger.writeEvent(
+ OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_ROTATION_OUT);
};
private final DisplayController.OnDisplaysChangedListener mDisplaysChangedListener =
@@ -586,6 +588,10 @@
mContext.getContentResolver(), mUserId);
setSwipeToNotificationEnabled(enabled);
+ mOneHandedUiEventLogger.writeEvent(enabled
+ ? OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_SHOW_NOTIFICATION_ENABLED_ON
+ : OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_SHOW_NOTIFICATION_ENABLED_OFF);
+
// Also checks one handed mode settings since they all need gesture overlay.
setEnabledGesturalOverlay(
enabled || mOneHandedSettingsUtil.getSettingsOneHandedModeEnabled(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedUiEventLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedUiEventLogger.java
index 38ffb07..4e610fa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedUiEventLogger.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedUiEventLogger.java
@@ -50,6 +50,8 @@
public static final int EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_4 = 15;
public static final int EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_8 = 16;
public static final int EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_12 = 17;
+ public static final int EVENT_ONE_HANDED_SETTINGS_SHOW_NOTIFICATION_ENABLED_ON = 18;
+ public static final int EVENT_ONE_HANDED_SETTINGS_SHOW_NOTIFICATION_ENABLED_OFF = 19;
private static final String[] EVENT_TAGS = {
"one_handed_trigger_gesture_in",
@@ -69,7 +71,9 @@
"one_handed_settings_timeout_seconds_never",
"one_handed_settings_timeout_seconds_4",
"one_handed_settings_timeout_seconds_8",
- "one_handed_settings_timeout_seconds_12"
+ "one_handed_settings_timeout_seconds_12",
+ "one_handed_settings_show_notification_enabled_on",
+ "one_handed_settings_show_notification_enabled_off"
};
public OneHandedUiEventLogger(UiEventLogger uiEventLogger) {
@@ -152,7 +156,13 @@
ONE_HANDED_SETTINGS_TOGGLES_TIMEOUT_SECONDS_8(364),
@UiEvent(doc = "One-Handed mode timeout value changed to 12 seconds")
- ONE_HANDED_SETTINGS_TOGGLES_TIMEOUT_SECONDS_12(365);
+ ONE_HANDED_SETTINGS_TOGGLES_TIMEOUT_SECONDS_12(365),
+
+ @UiEvent(doc = "One-Handed mode show notification toggle on")
+ ONE_HANDED_SETTINGS_TOGGLES_SHOW_NOTIFICATION_ENABLED_ON(847),
+
+ @UiEvent(doc = "One-Handed mode show notification toggle off")
+ ONE_HANDED_SETTINGS_TOGGLES_SHOW_NOTIFICATION_ENABLED_OFF(848);
private final int mId;
@@ -247,6 +257,14 @@
mUiEventLogger.log(OneHandedSettingsTogglesEvent
.ONE_HANDED_SETTINGS_TOGGLES_TIMEOUT_SECONDS_12);
break;
+ case EVENT_ONE_HANDED_SETTINGS_SHOW_NOTIFICATION_ENABLED_ON:
+ mUiEventLogger.log(OneHandedSettingsTogglesEvent
+ .ONE_HANDED_SETTINGS_TOGGLES_SHOW_NOTIFICATION_ENABLED_ON);
+ break;
+ case EVENT_ONE_HANDED_SETTINGS_SHOW_NOTIFICATION_ENABLED_OFF:
+ mUiEventLogger.log(OneHandedSettingsTogglesEvent
+ .ONE_HANDED_SETTINGS_TOGGLES_SHOW_NOTIFICATION_ENABLED_OFF);
+ break;
default:
// Do nothing
break;
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/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index 9ff2f46..b2ff38c 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -247,7 +247,7 @@
static void android_view_ThreadedRenderer_deleteProxy(JNIEnv* env, jobject clazz,
jlong proxyPtr) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
- delete proxy;
+ RenderProxy::asyncDelete(proxy);
}
static jboolean android_view_ThreadedRenderer_loadSystemProperties(JNIEnv* env, jobject clazz,
@@ -662,16 +662,18 @@
auto globalCallbackRef =
std::make_shared<JWeakGlobalRefHolder>(vm, aSurfaceTransactionCallback);
proxy->setASurfaceTransactionCallback(
- [globalCallbackRef](int64_t transObj, int64_t scObj, int64_t frameNr) {
+ [globalCallbackRef](int64_t transObj, int64_t scObj, int64_t frameNr) -> bool {
JNIEnv* env = getenv(globalCallbackRef->vm());
jobject localref = env->NewLocalRef(globalCallbackRef->ref());
if (CC_UNLIKELY(!localref)) {
- return;
+ return false;
}
- env->CallVoidMethod(localref, gASurfaceTransactionCallback.onMergeTransaction,
- static_cast<jlong>(transObj), static_cast<jlong>(scObj),
- static_cast<jlong>(frameNr));
+ jboolean ret = env->CallBooleanMethod(
+ localref, gASurfaceTransactionCallback.onMergeTransaction,
+ static_cast<jlong>(transObj), static_cast<jlong>(scObj),
+ static_cast<jlong>(frameNr));
env->DeleteLocalRef(localref);
+ return ret;
});
}
}
@@ -1064,7 +1066,7 @@
jclass aSurfaceTransactionCallbackClass =
FindClassOrDie(env, "android/graphics/HardwareRenderer$ASurfaceTransactionCallback");
gASurfaceTransactionCallback.onMergeTransaction =
- GetMethodIDOrDie(env, aSurfaceTransactionCallbackClass, "onMergeTransaction", "(JJJ)V");
+ GetMethodIDOrDie(env, aSurfaceTransactionCallbackClass, "onMergeTransaction", "(JJJ)Z");
jclass prepareSurfaceControlForWebviewCallbackClass = FindClassOrDie(
env, "android/graphics/HardwareRenderer$PrepareSurfaceControlForWebviewCallback");
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 44d0038..0c9711b 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -910,9 +910,8 @@
bool CanvasContext::mergeTransaction(ASurfaceTransaction* transaction, ASurfaceControl* control) {
if (!mASurfaceTransactionCallback) return false;
- std::invoke(mASurfaceTransactionCallback, reinterpret_cast<int64_t>(transaction),
- reinterpret_cast<int64_t>(control), getFrameNumber());
- return true;
+ return std::invoke(mASurfaceTransactionCallback, reinterpret_cast<int64_t>(transaction),
+ reinterpret_cast<int64_t>(control), getFrameNumber());
}
void CanvasContext::prepareSurfaceControlForWebview() {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index a61c2bf..3279ccb 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -206,7 +206,7 @@
ASurfaceControlStats* stats);
void setASurfaceTransactionCallback(
- const std::function<void(int64_t, int64_t, int64_t)>& callback) {
+ const std::function<bool(int64_t, int64_t, int64_t)>& callback) {
mASurfaceTransactionCallback = callback;
}
@@ -317,7 +317,7 @@
// If set to true, we expect that callbacks into onSurfaceStatsAvailable
bool mExpectSurfaceStats = false;
- std::function<void(int64_t, int64_t, int64_t)> mASurfaceTransactionCallback;
+ std::function<bool(int64_t, int64_t, int64_t)> mASurfaceTransactionCallback;
std::function<void()> mPrepareSurfaceControlForWebviewCallback;
void cleanupResources();
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index c47050c..e538a92 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -26,6 +26,7 @@
#include "renderthread/CanvasContext.h"
#include "renderthread/RenderTask.h"
#include "renderthread/RenderThread.h"
+#include "thread/CommonPool.h"
#include "utils/Macros.h"
#include "utils/TimeUtils.h"
@@ -42,6 +43,17 @@
mDrawFrameTask.setContext(&mRenderThread, mContext, rootRenderNode);
}
+void RenderProxy::asyncDelete(RenderProxy* proxy) {
+ if (!proxy) return;
+
+ if (proxy->mContext) {
+ // Use the common pool because ~RenderProxy blocks on calling into RenderThread
+ CommonPool::post([proxy]() { delete proxy; });
+ } else {
+ delete proxy;
+ }
+}
+
RenderProxy::~RenderProxy() {
destroyContext();
}
@@ -314,7 +326,7 @@
}
void RenderProxy::setASurfaceTransactionCallback(
- const std::function<void(int64_t, int64_t, int64_t)>& callback) {
+ const std::function<bool(int64_t, int64_t, int64_t)>& callback) {
mRenderThread.queue().post(
[this, cb = callback]() { mContext->setASurfaceTransactionCallback(cb); });
}
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index d575aa7..5f6b5cd 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -62,10 +62,14 @@
* references RenderProxy fields. This is safe as RenderProxy cannot
* be deleted if it is blocked inside a call.
*/
-class RenderProxy {
+class RenderProxy final {
public:
RenderProxy(bool opaque, RenderNode* rootNode, IContextFactory* contextFactory);
- virtual ~RenderProxy();
+ ~RenderProxy();
+
+ // Schedules a delete of the RenderProxy at a later date. Avoids blocking the current thread
+ // on destruction which ~RenderProxy does by default.
+ static void asyncDelete(RenderProxy*);
// Won't take effect until next EGLSurface creation
void setSwapBehavior(SwapBehavior swapBehavior);
@@ -123,7 +127,7 @@
void setContentDrawBounds(int left, int top, int right, int bottom);
void setPictureCapturedCallback(const std::function<void(sk_sp<SkPicture>&&)>& callback);
void setASurfaceTransactionCallback(
- const std::function<void(int64_t, int64_t, int64_t)>& callback);
+ const std::function<bool(int64_t, int64_t, int64_t)>& callback);
void setPrepareSurfaceControlForWebviewCallback(const std::function<void()>& callback);
void setFrameCallback(std::function<void(int64_t)>&& callback);
void setFrameCompleteCallback(std::function<void(int64_t)>&& callback);
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/FooterPreference/res/values-gu/strings.xml b/packages/SettingsLib/FooterPreference/res/values-gu/strings.xml
new file mode 100644
index 0000000..54249b8
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/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="settingslib_learn_more_text" msgid="7385478101223578464">"વધુ જાણો"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-te/strings.xml b/packages/SettingsLib/FooterPreference/res/values-te/strings.xml
new file mode 100644
index 0000000..6c8d679
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/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="settingslib_learn_more_text" msgid="7385478101223578464">"మరింత తెలుసుకోండి"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
index 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-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 2d1a362..c7a0b27 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/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-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index c169d76..c5a3101 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Kaldenavn"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Tilføj gæst"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Fjern gæsten"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Nulstil gæstesession"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gæst"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Tag et billede"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Vælg et billede"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 5808b6d..9b7fcc6 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Alias"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Gast hinzufügen"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Gast entfernen"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Gast zurücksetzen"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gast"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Foto machen"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Bild auswählen"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 5d0a61a..d6f7d7c 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Sobrenombre"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Agregar 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 perfil de invitado"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Invitado"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Tomar una foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Elegir una imagen"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 26c7b2c..08cca42 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -507,7 +507,7 @@
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmas y recordatorios"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Permitir la programación de alarmas y recordatorios"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmas y recordatorios"</string>
- <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permite que esta aplicación programe alarmas y otras acciones de carácter temporal. Este permite sirve para que la aplicación siga activa en segundo plano, lo que puede usar más batería.\n\nSi este permiso está desactivados, no funcionarán las alarmas ni los eventos con carácter temporal programados por esta aplicación."</string>
+ <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permite que esta aplicación programe alarmas y otras acciones que se llevan a cabo a una hora determinada. Esto hace que la aplicación siga activa en segundo plano, lo que puede usar más batería.\n\nSi este permiso está desactivado, no funcionarán las alarmas ni los eventos que se activan a una hora determinada que programe esta aplicación."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"programar, alarma, recordatorio, reloj"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Activar"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Activar el modo No molestar"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 194aeaf..a9d21695 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -507,7 +507,7 @@
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmid ja meeldetuletused"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Luba alarmide ja meeldetuletuste määramine"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmid ja meeldetuletused"</string>
- <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Lubage sellel rakendusel määrata äratusi ja ajastada kiire tähtajaga toiminguid. See võimaldab rakendusel töötada taustal, mistõttu võib akukasutus olla suurem.\n\nKui see luba on välja lülitatud, siis olemasolevad äratused ja selle rakenduse ajastatud ajapõhised sündmused ei tööta."</string>
+ <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Lubage sellel rakendusel määrata alarme ja ajastada kiire tähtajaga toiminguid. See võimaldab rakendusel töötada taustal, mistõttu võib akukasutus olla suurem.\n\nKui see luba on välja lülitatud, siis olemasolevad alarmid ja selle rakenduse ajastatud ajapõhised sündmused ei tööta."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"ajakava, äratus, meeldetuletus, kell"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Lülita sisse"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Valiku Mitte segada sisselülitamine"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index eb68f5f..6e42148 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/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-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 551dc36..776e864 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Pseudo"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Ajouter un invité"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Supprimer l\'invité"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Réinitialiser la session Invité"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Invité"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Prendre une photo"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Sélectionner une image"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 5ade70f..753e446 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -461,7 +461,7 @@
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Charge lente"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"En charge sans fil"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Pas en charge"</string>
- <string name="battery_info_status_not_charging" msgid="3371084153747234837">"Connecté, pas en charge"</string>
+ <string name="battery_info_status_not_charging" msgid="3371084153747234837">"Connectée, pas en charge"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Chargée"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Contrôlé par l\'administrateur"</string>
<string name="disabled" msgid="8017887509554714950">"Désactivée"</string>
@@ -507,7 +507,7 @@
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmes et rappels"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Autoriser à définir des alarmes et des rappels"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes et rappels"</string>
- <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Autorisez cette appli à définir des alarmes et à planifier des actions soumises à un délai. Cela lui permet de s\'exécuter en arrière-plan, ce qui peut consommer plus de batterie.\n\nSi cette autorisation est désactivée, les alarmes existantes et les événements basés sur l\'heure planifiés par cette appli ne fonctionneront pas."</string>
+ <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Autorisez cette appli à définir des alarmes et à programmer des actions à certaines heures. Elle s\'exécutera alors en arrière-plan, ce qui peut solliciter davantage la batterie.\n\nSi l\'autorisation est désactivée, les alarmes existantes et les événements programmés par l\'appli ne fonctionneront pas."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"définir, alarme, rappel, horloge"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Activer"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Activer le mode Ne pas déranger"</string>
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Pseudo"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Ajouter un invité"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Supprimer l\'invité"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Réinitialiser la session Invité"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Invité"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Prendre une photo"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Choisir une image"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index b55a5a2..d1ecff8 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -454,7 +454,7 @@
<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_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="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - ચાર્જિંગ હંગામીરૂપે પ્રતિબંધિત કરવામાં આવ્યું છે"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"અજાણ્યું"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ચાર્જ થઈ રહ્યું છે"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ઝડપથી ચાર્જ થાય છે"</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-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index bc74092..8af48e5 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -507,7 +507,7 @@
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"अलार्म और रिमाइंडर"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"अलार्म और रिमाइंडर सेट करने की अनुमति दें"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"अलार्म और रिमाइंडर"</string>
- <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"इस ऐप्लिकेशन को अलार्म और तय समय पर होने वाली कार्रवाइयों के रिमाइंडर सेट करने की अनुमति दें. ऐसा करने से, ऐप्लिकेशन को बैकग्राउंड में चलने की अनुमति मिलती है. इससे, बैटरी ज़्यादा खर्च होती है.\n\nअगर आप यह अनुमति नहीं देते हैं, तो इस ऐप्लिकेशन की मदद से सेट किए गए अलार्म और तय समय पर होने वाली कार्रवाइयों के रिमाइंडर काम नहीं करेंगे."</string>
+ <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"इस ऐप्लिकेशन को अलार्म और तय समय पर होने वाली कार्रवाइयों के रिमाइंडर सेट करने की अनुमति दें. ऐसा करने से, ऐप्लिकेशन को बैकग्राउंड में चलने की अनुमति मिलती है. इससे बैटरी ज़्यादा खर्च होती है.\n\nअगर आप यह अनुमति नहीं देते हैं, तो इस ऐप्लिकेशन की मदद से सेट किए गए अलार्म और तय समय पर होने वाली कार्रवाइयों के रिमाइंडर काम नहीं करेंगे."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"शेड्यूल, अलार्म, रिमाइंडर, घड़ी"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"चालू करें"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"\'परेशान न करें\' चालू करें"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index fcd3c87..130d4cc 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/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-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index f67c068..600dc1a 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Nama panggilan"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Tambahkan tamu"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Hapus tamu"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Reset tamu"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Tamu"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Ambil foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Pilih gambar"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index dc48362..b75f7c1 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/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-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 7e9949f..a10fe1b 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/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-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index eef252a..1322643 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/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-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 5927071..582a3e1 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/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-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 618b7db..a438a40 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/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-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index bf6c2a3..7328072 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/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-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 77006fc..9feb6ac 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Nama panggilan"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Tambah tetamu"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Alih keluar tetamu"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Tetapkan semula tetamu"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Tetamu"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Ambil foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Pilih imej"</string>
diff --git a/packages/SettingsLib/res/values-ne/arrays.xml b/packages/SettingsLib/res/values-ne/arrays.xml
index 1fc6899..3699bf3 100644
--- a/packages/SettingsLib/res/values-ne/arrays.xml
+++ b/packages/SettingsLib/res/values-ne/arrays.xml
@@ -260,7 +260,7 @@
<item msgid="6506681373060736204">"बढीमा ४ प्रक्रियाहरू"</item>
</string-array>
<string-array name="usb_configuration_titles">
- <item msgid="3358668781763928157">"चार्ज हुँदै"</item>
+ <item msgid="3358668781763928157">"चार्ज हुँदै छ"</item>
<item msgid="7804797564616858506">"MTP (मिडिया स्थानान्तरण प्रोटोकल)"</item>
<item msgid="910925519184248772">"PTP (चित्र स्थानान्तरण प्रोटोकल)"</item>
<item msgid="3825132913289380004">"RNDIS (USB इथरनेट)"</item>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index a54fc0c8..a69f552 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -456,8 +456,8 @@
<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>
- <string name="battery_info_status_charging" msgid="4279958015430387405">"चार्ज हुँदै"</string>
- <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"द्रुत गतिमा चार्ज गरिँदै"</string>
+ <string name="battery_info_status_charging" msgid="4279958015430387405">"चार्ज हुँदै छ"</string>
+ <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"द्रुत गतिमा चार्ज गरिँदै छ"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"बिस्तारै चार्ज गरिँदै"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"वायरलेस तरिकाले चार्ज गरिँदै छ"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"चार्ज भइरहेको छैन"</string>
@@ -507,7 +507,7 @@
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"अलार्म र रिमाइन्डरहरू"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"अलार्म तथा रिमाइन्डर सेट गर्न दिइयोस्"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"घडी तथा रिमाइन्डरहरू"</string>
- <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"यो एपलाई अलार्म सेट गर्ने र समयमै पूरा गर्नु पर्ने कारबाहीहरूको रुटिन तय गर्ने अनुमति दिनुहोस्। यो अनुमति दिइएको छ भने यो एप ब्याकग्राउन्डमा यसले चलेर धेरै ब्याट्री खपत गर्न सक्छ।\n\nयो अनुमति दिइएको छैन भने समय तोकिएका अलार्म र यो एपले तय गरेका समयअनुसार चल्ने कार्यक्रमले काम गर्दैन।"</string>
+ <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"यो एपलाई अलार्म सेट गर्ने र समयमै पूरा गर्नु पर्ने कारबाहीहरूको रुटिन बनाउने अनुमति दिनुहोस्। यो अनुमति दिइएको छ भने यो एप ब्याकग्राउन्डमा चल्छ र धेरै ब्याट्री खपत हुन्छ।\n\nयो अनुमति दिइएको छैन भने सेट गरिएका अलार्म बज्दैनन् र यो एपले तय गरेका गतिविधि चल्दैनन्।"</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"समयतालिका, अलार्म, रिमाइन्डर, घडी"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"सक्रिय गर्नुहोस्"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"बाधा नपुऱ्याउनुहोस् नामक मोडलाई सक्रिय गर्नुहोस्"</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-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 6cc3cc5..0085023 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/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-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 0af4990..ff1526e 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -461,7 +461,7 @@
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"ਹੌਲੀ ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ"</string>
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"ਬਿਨਾਂ ਤਾਰ ਤੋਂ ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ਚਾਰਜ ਨਹੀਂ ਹੋ ਰਿਹਾ"</string>
- <string name="battery_info_status_not_charging" msgid="3371084153747234837">"ਕਨੈਕਟ ਹੈ, ਚਾਰਜ ਨਹੀਂ ਹੋ ਰਿਹਾ"</string>
+ <string name="battery_info_status_not_charging" msgid="3371084153747234837">"ਕਨੈਕਟ ਹੈ, ਚਾਰਜ ਨਹੀਂ ਹੋ ਰਹੀ"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"ਚਾਰਜ ਹੋ ਗਈ"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਕੰਟਰੋਲ ਕੀਤੀ ਗਈ"</string>
<string name="disabled" msgid="8017887509554714950">"ਅਯੋਗ ਬਣਾਇਆ"</string>
@@ -507,7 +507,7 @@
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"ਅਲਾਰਮ ਅਤੇ ਰਿਮਾਈਂਡਰ"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"ਅਲਾਰਮ ਅਤੇ ਰਿਮਾਈਂਡਰ ਸੈੱਟ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"ਅਲਾਰਮ ਅਤੇ ਰਿਮਾਈਂਡਰ"</string>
- <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"ਇਸ ਐਪ ਨੂੰ ਅਲਾਰਮ ਸੈੱਟ ਕਰਨ ਜਾਂ ਹੋਰ ਸਮਾਂ-ਸੰਵੇਦਨਸ਼ੀਲ ਕਾਰਵਾਈਆਂ ਨੂੰ ਨਿਯਤ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ। ਇਸ ਨਾਲ ਐਪ ਨੂੰ ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਚਲਾਉਣ ਦੀ ਇਜਾਜ਼ਤ ਮਿਲਦੀ ਹੈ, ਜੋ ਵੱਧ ਬੈਟਰੀ ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦੀ ਹੈ।\n\nਜੇ ਇਹ ਇਜਾਜ਼ਤ ਬੰਦ ਹੈ, ਤਾਂ ਮੌਜੂਦਾ ਅਲਾਰਮ ਅਤੇ ਇਸ ਐਪ ਰਾਹੀਂ ਸਮਾਂ ਨਿਯਤ ਕੀਤੇ ਸਮਾਂ-ਆਧਾਰਿਤ ਇਵੈਂਟਾਂ ਕੰਮ ਨਹੀਂ ਕਰਨਗੇ।"</string>
+ <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"ਇਸ ਐਪ ਨੂੰ ਅਲਾਰਮ ਸੈੱਟ ਕਰਨ ਜਾਂ ਹੋਰ ਸਮਾਂ-ਸੰਵੇਦਨਸ਼ੀਲ ਕਾਰਵਾਈਆਂ ਨੂੰ ਨਿਯਤ ਕਰਨ ਦਿਓ। ਇਸ ਨਾਲ ਐਪ ਨੂੰ ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਚਲਾਉਣ ਦੀ ਇਜਾਜ਼ਤ ਮਿਲਦੀ ਹੈ, ਜਿਸ ਨਾਲ ਬੈਟਰੀ ਦੀ ਵਰਤੋਂ ਵੱਧ ਸਕਦੀ ਹੈ।\n\nਜੇ ਇਹ ਇਜਾਜ਼ਤ ਬੰਦ ਹੈ, ਤਾਂ ਮੌਜੂਦਾ ਅਲਾਰਮ ਅਤੇ ਇਸ ਐਪ ਰਾਹੀਂ ਨਿਯਤ ਕੀਤੇ ਸਮਾਂ-ਆਧਾਰਿਤ ਇਵੈਂਟ ਕੰਮ ਨਹੀਂ ਕਰਨਗੇ।"</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"ਸਮਾਂ-ਸੂਚੀ, ਅਲਾਰਮ, ਰਿਮਾਈਂਡਰ, ਘੜੀ"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"ਚਾਲੂ ਕਰੋ"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"\'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਨੂੰ ਚਾਲੂ ਕਰੋ"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 1e5fce5..9937600 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -559,7 +559,7 @@
<string name="user_new_user_name" msgid="60979820612818840">"Новый пользователь"</string>
<string name="user_new_profile_name" msgid="2405500423304678841">"Новый профиль"</string>
<string name="user_info_settings_title" msgid="6351390762733279907">"Сведения о пользователе"</string>
- <string name="profile_info_settings_title" msgid="105699672534365099">"Информация о профиле"</string>
+ <string name="profile_info_settings_title" msgid="105699672534365099">"Данные профиля"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Чтобы создать профиль с ограниченным доступом, необходимо предварительно настроить блокировку экрана для защиты приложений и личных данных"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Включить блокировку"</string>
<string name="user_switch_to_user" msgid="6975428297154968543">"Сменить пользователя на <xliff:g id="USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index a385055..2fae557 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/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-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index ba744360..a784df9 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Pseudonimi"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Shto të ftuar"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Hiq të ftuarin"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Rivendos vizitorin"</string>
<string name="guest_nickname" msgid="6332276931583337261">"I ftuar"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Bëj një fotografi"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Zgjidh një imazh"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 332cd9d..9424dab 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Jina wakilishi"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Ongeza mgeni"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ondoa mgeni"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Badilisha kipindi cha mgeni"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Mgeni"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Piga picha"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Chagua picha"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 7952a76..0387c92 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -505,8 +505,7 @@
<string name="cancel" msgid="5665114069455378395">"ரத்துசெய்"</string>
<string name="okay" msgid="949938843324579502">"சரி"</string>
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"அலாரங்களும் நினைவூட்டல்களும்"</string>
- <!-- unknown quoting pattern: original -1, translation 1 -->
- <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"அலாரங்கள் &amp; நினைவூட்டல்களை அமைக்க அனுமதித்தல்"</string>
+ <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"அலாரங்கள் & நினைவூட்டல்களை அமைக்க அனுமதித்தல்"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"அலாரங்கள் & நினைவூட்டல்கள்"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"அலாரங்களை அமைக்கவும் குறிப்பிட்ட கால இடைவெளியில் செயல்களைத் திட்டமிடவும் இந்த ஆப்ஸை அனுமதிக்கும். இது ஆப்ஸ் பின்னணியில் இயங்குவதை அனுமதிக்கும், இதற்காக அதிக பேட்டரியைப் பயன்படுத்தக்கூடும்.\n\nஇந்த அனுமதி முடக்கப்பட்டிருந்தால் இந்த ஆப்ஸ் மூலம் திட்டமிடப்பட்ட ஏற்கெனவே அமைத்த அலாரங்களும் நேர அடிப்படையிலான நிகழ்வுகளும் வேலை செய்யாது."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"திட்டமிடல், அலாரம், நினைவூட்டல், கடிகாரம்"</string>
@@ -567,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-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 36144eb..ed90a29 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Takma ad"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Misafir ekle"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Misafir oturumunu kaldır"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Misafir oturumunu sıfırla"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Misafir"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Fotoğraf çek"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Resim seç"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index d0ed2ab..7f9e5fb 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/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-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 0fba1ec..1020383 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Biệt hiệu"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Thêm khách"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Xóa phiên khách"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Đặt lại phiên khách"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Khách"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Chụp ảnh"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Chọn một hình ảnh"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 642dd1d..b2c84a5 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/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-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 1cab0af..c62c84e 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/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/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 8651595..6b840bd 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1426,7 +1426,12 @@
<string name="guest_reset_guest">Reset guest</string>
<!-- Name for the guest user [CHAR LIMIT=35] -->
<string name="guest_nickname">Guest</string>
-
+ <!-- Title of the confirmation dialog to confirm resetting guest. [CHAR LIMIT=NONE] -->
+ <string name="guest_reset_guest_dialog_title">Reset guest?</string>
+ <!-- Label for button in confirmation dialog when resetting guest user [CHAR LIMIT=35] -->
+ <string name="guest_reset_guest_confirm_button">Reset</string>
+ <!-- Status message indicating the device is in the process of resetting the guest user. [CHAR_LIMIT=NONE] -->
+ <string name="guest_resetting">Resetting guest\u2026</string>
<!-- An option in a photo selection dialog to take a new photo [CHAR LIMIT=50] -->
<string name="user_image_take_photo">Take a photo</string>
<!-- An option in a photo selection dialog to choose a pre-existing image [CHAR LIMIT=50] -->
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 959b5ca..f7123c1 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -419,6 +419,9 @@
<!-- Permission required for running networking unit tests -->
<uses-permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS" />
+ <!-- Permission required for CTS test - CtsHostsideNetworkTests -->
+ <uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY" />
+
<!-- Permissions required for CTS test - TunerTest -->
<uses-permission android:name="android.permission.ACCESS_TV_DESCRAMBLER" />
<uses-permission android:name="android.permission.ACCESS_TV_TUNER" />
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..5ab0f49 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1148,18 +1148,12 @@
<!-- Title of the confirmation dialog when exiting guest session [CHAR LIMIT=NONE] -->
<string name="guest_exit_guest_dialog_title">Remove guest?</string>
- <!-- Title of the confirmation dialog when resetting guest session [CHAR LIMIT=NONE] -->
- <string name="guest_reset_guest_dialog_title">Reset guest?</string>
-
<!-- Message of the confirmation dialog when exiting guest session [CHAR LIMIT=NONE] -->
<string name="guest_exit_guest_dialog_message">All apps and data in this session will be deleted.</string>
<!-- Label for button in confirmation dialog when exiting guest session [CHAR LIMIT=35] -->
<string name="guest_exit_guest_dialog_remove">Remove</string>
- <!-- Label for button in confirmation dialog when resetting guest session [CHAR LIMIT=35] -->
- <string name="guest_reset_guest_dialog_remove">Reset</string>
-
<!-- Title of the notification when resuming an existing guest session [CHAR LIMIT=NONE] -->
<string name="guest_wipe_session_title">Welcome back, guest!</string>
@@ -2952,6 +2946,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/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index bb44b09..bc4ced4 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -71,7 +71,6 @@
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
import com.android.systemui.plugins.GlobalActionsPanelPlugin;
-import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -103,7 +102,6 @@
private final LockPatternUtils mLockPatternUtils;
private final KeyguardStateController mKeyguardStateController;
- private final NotificationShadeDepthController mDepthController;
private final SysUiState mSysUiState;
private final ActivityStarter mActivityStarter;
private final SysuiColorExtractor mSysuiColorExtractor;
@@ -164,7 +162,6 @@
IActivityManager iActivityManager,
@Nullable TelecomManager telecomManager,
MetricsLogger metricsLogger,
- NotificationShadeDepthController depthController,
SysuiColorExtractor colorExtractor,
IStatusBarService statusBarService,
NotificationShadeWindowController notificationShadeWindowController,
@@ -196,7 +193,6 @@
iActivityManager,
telecomManager,
metricsLogger,
- depthController,
colorExtractor,
statusBarService,
notificationShadeWindowController,
@@ -212,7 +208,6 @@
mLockPatternUtils = lockPatternUtils;
mKeyguardStateController = keyguardStateController;
- mDepthController = depthController;
mSysuiColorExtractor = colorExtractor;
mStatusBarService = statusBarService;
mNotificationShadeWindowController = notificationShadeWindowController;
@@ -267,9 +262,8 @@
protected ActionsDialogLite createDialog() {
initDialogItems();
- mDepthController.setShowingHomeControls(true);
ActionsDialog dialog = new ActionsDialog(getContext(), mAdapter, mOverflowAdapter,
- this::getWalletViewController, mDepthController, mSysuiColorExtractor,
+ this::getWalletViewController, mSysuiColorExtractor,
mStatusBarService, mNotificationShadeWindowController,
mSysUiState, this::onRotate, isKeyguardShowing(), mPowerAdapter, getEventLogger(),
getStatusBar());
@@ -336,16 +330,15 @@
ActionsDialog(Context context, MyAdapter adapter, MyOverflowAdapter overflowAdapter,
Provider<GlobalActionsPanelPlugin.PanelViewController> walletFactory,
- NotificationShadeDepthController depthController,
SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService,
NotificationShadeWindowController notificationShadeWindowController,
SysUiState sysuiState, Runnable onRotateCallback, boolean keyguardShowing,
MyPowerOptionsAdapter powerAdapter, UiEventLogger uiEventLogger,
StatusBar statusBar) {
super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions,
- adapter, overflowAdapter, depthController, sysuiColorExtractor,
- statusBarService, notificationShadeWindowController, sysuiState,
- onRotateCallback, keyguardShowing, powerAdapter, uiEventLogger, null,
+ adapter, overflowAdapter, sysuiColorExtractor, statusBarService,
+ notificationShadeWindowController, sysuiState, onRotateCallback,
+ keyguardShowing, powerAdapter, uiEventLogger, null,
statusBar);
mWalletFactory = walletFactory;
@@ -494,8 +487,6 @@
float animatedValue = animation.getAnimatedFraction();
int alpha = (int) (animatedValue * mScrimAlpha * 255);
mBackgroundDrawable.setAlpha(alpha);
- mDepthController.updateGlobalDialogVisibility(animatedValue,
- mGlobalActionsLayout);
});
ObjectAnimator xAnimator =
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index f30d6b1..5acb303 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -119,7 +119,6 @@
import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
import com.android.systemui.plugins.GlobalActionsPanelPlugin;
import com.android.systemui.scrim.ScrimDrawable;
-import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -190,7 +189,6 @@
private final TelecomManager mTelecomManager;
private final MetricsLogger mMetricsLogger;
private final UiEventLogger mUiEventLogger;
- private final NotificationShadeDepthController mDepthController;
private final SysUiState mSysUiState;
private final GlobalActionsInfoProvider mInfoProvider;
@@ -329,7 +327,6 @@
IActivityManager iActivityManager,
@Nullable TelecomManager telecomManager,
MetricsLogger metricsLogger,
- NotificationShadeDepthController depthController,
SysuiColorExtractor colorExtractor,
IStatusBarService statusBarService,
NotificationShadeWindowController notificationShadeWindowController,
@@ -362,7 +359,6 @@
mMetricsLogger = metricsLogger;
mUiEventLogger = uiEventLogger;
mInfoProvider = infoProvider;
- mDepthController = depthController;
mSysuiColorExtractor = colorExtractor;
mStatusBarService = statusBarService;
mNotificationShadeWindowController = notificationShadeWindowController;
@@ -652,11 +648,9 @@
protected ActionsDialogLite createDialog() {
initDialogItems();
- mDepthController.setShowingHomeControls(false);
ActionsDialogLite dialog = new ActionsDialogLite(mContext,
com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActionsLite,
- mAdapter, mOverflowAdapter,
- mDepthController, mSysuiColorExtractor,
+ mAdapter, mOverflowAdapter, mSysuiColorExtractor,
mStatusBarService, mNotificationShadeWindowController,
mSysUiState, this::onRotate, mKeyguardShowing, mPowerAdapter, mUiEventLogger,
mInfoProvider, mStatusBar);
@@ -2125,7 +2119,6 @@
protected boolean mShowing;
protected float mScrimAlpha;
protected final NotificationShadeWindowController mNotificationShadeWindowController;
- protected final NotificationShadeDepthController mDepthController;
protected final SysUiState mSysUiState;
private ListPopupWindow mOverflowPopup;
private Dialog mPowerOptionsDialog;
@@ -2181,7 +2174,6 @@
ActionsDialogLite(Context context, int themeRes, MyAdapter adapter,
MyOverflowAdapter overflowAdapter,
- NotificationShadeDepthController depthController,
SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService,
NotificationShadeWindowController notificationShadeWindowController,
SysUiState sysuiState, Runnable onRotateCallback, boolean keyguardShowing,
@@ -2192,7 +2184,6 @@
mAdapter = adapter;
mOverflowAdapter = overflowAdapter;
mPowerOptionsAdapter = powerAdapter;
- mDepthController = depthController;
mColorExtractor = sysuiColorExtractor;
mStatusBarService = statusBarService;
mNotificationShadeWindowController = notificationShadeWindowController;
@@ -2409,7 +2400,6 @@
float animatedValue = animation.getAnimatedFraction();
int alpha = (int) (animatedValue * mScrimAlpha * 255);
mBackgroundDrawable.setAlpha(alpha);
- mDepthController.updateGlobalDialogVisibility(animatedValue, mGlobalActionsLayout);
});
ObjectAnimator xAnimator =
@@ -2439,7 +2429,6 @@
float animatedValue = 1f - animation.getAnimatedFraction();
int alpha = (int) (animatedValue * mScrimAlpha * 255);
mBackgroundDrawable.setAlpha(alpha);
- mDepthController.updateGlobalDialogVisibility(animatedValue, mGlobalActionsLayout);
});
float xOffset = mGlobalActionsLayout.getAnimationOffsetX();
@@ -2476,7 +2465,6 @@
dismissOverflow(true);
dismissPowerOptions(true);
mNotificationShadeWindowController.setRequestTopUi(false, TAG);
- mDepthController.updateGlobalDialogVisibility(0, null /* view */);
mSysUiState.setFlag(SYSUI_STATE_GLOBAL_ACTIONS_SHOWING, false)
.commitUpdate(mContext.getDisplayId());
super.dismiss();
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/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
index aa51771..1d791f5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -57,6 +57,12 @@
private static final String TAG = "TileLifecycleManager";
+ private static final int META_DATA_QUERY_FLAGS =
+ PackageManager.GET_META_DATA
+ | PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE;
+
private static final int MSG_ON_ADDED = 0;
private static final int MSG_ON_REMOVED = 1;
private static final int MSG_ON_CLICK = 2;
@@ -130,7 +136,7 @@
public boolean isActiveTile() {
try {
ServiceInfo info = mPackageManagerAdapter.getServiceInfo(mIntent.getComponent(),
- PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_META_DATA);
+ META_DATA_QUERY_FLAGS);
return info.metaData != null
&& info.metaData.getBoolean(TileService.META_DATA_ACTIVE_TILE, false);
} catch (PackageManager.NameNotFoundException e) {
@@ -148,7 +154,7 @@
public boolean isToggleableTile() {
try {
ServiceInfo info = mPackageManagerAdapter.getServiceInfo(mIntent.getComponent(),
- PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_META_DATA);
+ META_DATA_QUERY_FLAGS);
return info.metaData != null
&& info.metaData.getBoolean(TileService.META_DATA_TOGGLEABLE_TILE, false);
} catch (PackageManager.NameNotFoundException e) {
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/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
index ec648ad..5d8bed5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
@@ -51,7 +51,7 @@
private const val OVAL_INITIAL_WIDTH_PERCENT = 0.5f
/** The initial top value of the light oval, in percent of scrim height. */
- private const val OVAL_INITIAL_TOP_PERCENT = 1.05f
+ private const val OVAL_INITIAL_TOP_PERCENT = 1.1f
/** The initial bottom value of the light oval, in percent of scrim height. */
private const val OVAL_INITIAL_BOTTOM_PERCENT = 1.2f
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..e5c3b82 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -93,8 +93,13 @@
var shadeAnimation = DepthAnimation()
@VisibleForTesting
- var globalActionsSpring = DepthAnimation()
- var showingHomeControls: Boolean = false
+ 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) {
@@ -177,22 +182,19 @@
}
}
- // Home controls have black background, this means that we should not have blur when they
- // are fully visible, otherwise we'll enter Client Composition unnecessarily.
- var globalActionsRadius = globalActionsSpring.radius
- if (showingHomeControls) {
- globalActionsRadius = 0
- }
- var blur = max(shadeRadius.toInt(), globalActionsRadius)
+ var blur = shadeRadius.toInt()
// 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)
@@ -259,7 +261,7 @@
if (isDozing) {
shadeSpring.finishIfRunning()
shadeAnimation.finishIfRunning()
- globalActionsSpring.finishIfRunning()
+ brightnessMirrorSpring.finishIfRunning()
}
}
@@ -414,17 +416,13 @@
!keyguardStateController.isKeyguardFadingAway
}
- fun updateGlobalDialogVisibility(visibility: Float, dialogView: View?) {
- globalActionsSpring.animateTo(blurUtils.blurRadiusOfRatio(visibility), dialogView)
- }
-
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
IndentingPrintWriter(pw, " ").let {
it.println("StatusBarWindowBlurController:")
it.increaseIndent()
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 fe75739..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;
@@ -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);
}
@@ -2032,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) {
@@ -2061,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) {
@@ -2464,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) {
@@ -3081,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/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 1ebb9dd..14190d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -1012,15 +1012,16 @@
public ExitGuestDialog(Context context, int guestId, int targetId) {
super(context);
- setTitle(mGuestUserAutoCreated ? R.string.guest_reset_guest_dialog_title
+ setTitle(mGuestUserAutoCreated
+ ? com.android.settingslib.R.string.guest_reset_guest_dialog_title
: R.string.guest_exit_guest_dialog_title);
setMessage(context.getString(R.string.guest_exit_guest_dialog_message));
setButton(DialogInterface.BUTTON_NEGATIVE,
context.getString(android.R.string.cancel), this);
setButton(DialogInterface.BUTTON_POSITIVE,
- context.getString(
- mGuestUserAutoCreated ? R.string.guest_reset_guest_dialog_remove
- : R.string.guest_exit_guest_dialog_remove), this);
+ context.getString(mGuestUserAutoCreated
+ ? com.android.settingslib.R.string.guest_reset_guest_confirm_button
+ : R.string.guest_exit_guest_dialog_remove), this);
SystemUIDialog.setWindowOnTop(this);
setCanceledOnTouchOutside(false);
mGuestId = guestId;
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/globalactions/GlobalActionsDialogLiteTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
index adc8ffc..578c2d9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
@@ -57,7 +57,6 @@
import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.GlobalActions;
import com.android.systemui.settings.UserContextProvider;
-import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -99,7 +98,6 @@
@Mock private TrustManager mTrustManager;
@Mock private IActivityManager mActivityManager;
@Mock private MetricsLogger mMetricsLogger;
- @Mock private NotificationShadeDepthController mDepthController;
@Mock private SysuiColorExtractor mColorExtractor;
@Mock private IStatusBarService mStatusBarService;
@Mock private NotificationShadeWindowController mNotificationShadeWindowController;
@@ -147,7 +145,6 @@
mActivityManager,
null,
mMetricsLogger,
- mDepthController,
mColorExtractor,
mStatusBarService,
mNotificationShadeWindowController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
index e5c104e..2fa67cc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
@@ -64,7 +64,6 @@
import com.android.systemui.plugins.GlobalActions;
import com.android.systemui.plugins.GlobalActionsPanelPlugin;
import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -111,7 +110,6 @@
@Mock private TrustManager mTrustManager;
@Mock private IActivityManager mActivityManager;
@Mock private MetricsLogger mMetricsLogger;
- @Mock private NotificationShadeDepthController mDepthController;
@Mock private SysuiColorExtractor mColorExtractor;
@Mock private IStatusBarService mStatusBarService;
@Mock private NotificationShadeWindowController mNotificationShadeWindowController;
@@ -161,7 +159,6 @@
mActivityManager,
null,
mMetricsLogger,
- mDepthController,
mColorExtractor,
mStatusBarService,
mNotificationShadeWindowController,
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..d9f1426 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
@@ -70,7 +71,7 @@
@Mock private lateinit var windowToken: IBinder
@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 +91,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,7 +104,7 @@
notificationShadeWindowController, dozeParameters, dumpManager)
notificationShadeDepthController.shadeSpring = shadeSpring
notificationShadeDepthController.shadeAnimation = shadeAnimation
- notificationShadeDepthController.globalActionsSpring = globalActionsSpring
+ notificationShadeDepthController.brightnessMirrorSpring = brightnessSpring
notificationShadeDepthController.root = root
val captor = ArgumentCaptor.forClass(StatusBarStateController.StateListener::class.java)
@@ -191,22 +196,9 @@
}
@Test
- fun updateGlobalDialogVisibility_animatesBlur() {
- notificationShadeDepthController.updateGlobalDialogVisibility(0.5f, root)
- verify(globalActionsSpring).animateTo(eq(maxBlur / 2), eq(root))
- }
-
- @Test
- fun updateGlobalDialogVisibility_appliesBlur_withoutHomeControls() {
- `when`(globalActionsSpring.radius).thenReturn(maxBlur)
- notificationShadeDepthController.updateBlurCallback.doFrame(0)
- verify(blurUtils).applyBlur(any(), eq(maxBlur), eq(false))
- }
-
- @Test
- fun updateGlobalDialogVisibility_appliesBlur_unlessHomeControls() {
- notificationShadeDepthController.showingHomeControls = true
- `when`(globalActionsSpring.radius).thenReturn(maxBlur)
+ fun setFullShadeTransition_appliesBlur_onlyIfSupported() {
+ reset(blurUtils)
+ notificationShadeDepthController.transitionToFullShadeProgress = 1f
notificationShadeDepthController.updateBlurCallback.doFrame(0)
verify(blurUtils).applyBlur(any(), eq(0), eq(false))
}
@@ -267,6 +259,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/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 0f9a6fa..fcd049f 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -676,7 +676,7 @@
final UUID errorId;
if (mTraceErrorLogger.isAddErrorIdEnabled()) {
errorId = mTraceErrorLogger.generateErrorId();
- mTraceErrorLogger.addErrorIdToTrace(errorId);
+ mTraceErrorLogger.addErrorIdToTrace("system_server", errorId);
} else {
errorId = null;
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 5e388d9..89781d3 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1976,7 +1976,7 @@
r.foregroundId = 0;
r.foregroundNoti = null;
} else if (r.appInfo.targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
- r.stripForegroundServiceFlagFromNotification();
+ dropFgsNotificationStateLocked(r);
if ((flags & Service.STOP_FOREGROUND_DETACH) != 0) {
r.foregroundId = 0;
r.foregroundNoti = null;
@@ -4225,9 +4225,10 @@
}
r.isForeground = false;
+ r.mFgsNotificationWasDeferred = false;
+ dropFgsNotificationStateLocked(r);
r.foregroundId = 0;
r.foregroundNoti = null;
- r.mFgsNotificationWasDeferred = false;
resetFgsRestrictionLocked(r);
// Clear start entries.
@@ -4291,6 +4292,35 @@
smap.ensureNotStartingBackgroundLocked(r);
}
+ private void dropFgsNotificationStateLocked(ServiceRecord r) {
+ // If this is the only FGS using this notification, clear its FGS flag
+ boolean shared = false;
+ final ServiceMap smap = mServiceMap.get(r.userId);
+ if (smap != null) {
+ // Is any other FGS using this notification?
+ final int numServices = smap.mServicesByInstanceName.size();
+ for (int i = 0; i < numServices; i++) {
+ final ServiceRecord sr = smap.mServicesByInstanceName.valueAt(i);
+ if (sr == r) {
+ continue;
+ }
+ if (sr.isForeground
+ && r.foregroundId == sr.foregroundId
+ && r.appInfo.packageName.equals(sr.appInfo.packageName)) {
+ shared = true;
+ break;
+ }
+ }
+ } else {
+ Slog.wtf(TAG, "FGS " + r + " not found!");
+ }
+
+ // No other FGS is sharing this notification, so we're done with it
+ if (!shared) {
+ r.stripForegroundServiceFlagFromNotification();
+ }
+ }
+
void removeConnectionLocked(ConnectionRecord c, ProcessRecord skipApp,
ActivityServiceConnectionsHolder skipAct, boolean enqueueOomAdj) {
IBinder binder = c.conn.asBinder();
@@ -6165,8 +6195,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/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
index b2266f6..4455fd0 100644
--- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
@@ -267,7 +267,7 @@
if (mService.mTraceErrorLogger.isAddErrorIdEnabled()) {
errorId = mService.mTraceErrorLogger.generateErrorId();
- mService.mTraceErrorLogger.addErrorIdToTrace(errorId);
+ mService.mTraceErrorLogger.addErrorIdToTrace(mApp.processName, errorId);
} else {
errorId = null;
}
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 141f081..804e442 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -20,6 +20,7 @@
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
import static android.os.PowerExemptionManager.REASON_DENIED;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOREGROUND_SERVICE;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -928,13 +929,17 @@
public void postNotification() {
final int appUid = appInfo.uid;
final int appPid = app.getPid();
- if (foregroundId != 0 && foregroundNoti != null) {
+ if (isForeground && foregroundNoti != null) {
// Do asynchronous communication with notification manager to
// avoid deadlocks.
final String localPackageName = packageName;
final int localForegroundId = foregroundId;
final Notification _foregroundNoti = foregroundNoti;
final ServiceRecord record = this;
+ if (DEBUG_FOREGROUND_SERVICE) {
+ Slog.d(TAG, "Posting notification " + _foregroundNoti
+ + " for foreground service " + this);
+ }
ams.mHandler.post(new Runnable() {
public void run() {
NotificationManagerInternal nm = LocalServices.getService(
@@ -1066,10 +1071,6 @@
}
public void stripForegroundServiceFlagFromNotification() {
- if (foregroundId == 0) {
- return;
- }
-
final int localForegroundId = foregroundId;
final int localUserId = userId;
final String localPackageName = packageName;
diff --git a/services/core/java/com/android/server/am/TraceErrorLogger.java b/services/core/java/com/android/server/am/TraceErrorLogger.java
index 55f5715..c658100 100644
--- a/services/core/java/com/android/server/am/TraceErrorLogger.java
+++ b/services/core/java/com/android/server/am/TraceErrorLogger.java
@@ -46,10 +46,12 @@
* can be uniquely identified. We also add the same id to the dropbox entry of the error, so
* that we can join the trace and the error server-side.
*
- * @param errorId The unique id with which to tag the trace.
+ * @param processName The process name to include in the error id.
+ * @param errorId The unique id with which to tag the trace.
*/
- public void addErrorIdToTrace(UUID errorId) {
- Trace.traceCounter(Trace.TRACE_TAG_ACTIVITY_MANAGER, COUNTER_PREFIX + errorId.toString(),
+ public void addErrorIdToTrace(String processName, UUID errorId) {
+ Trace.traceCounter(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+ COUNTER_PREFIX + processName + "#" + errorId.toString(),
PLACEHOLDER_VALUE);
}
}
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/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index 3c9d802..85995a5 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -178,6 +178,9 @@
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
}
+
+ UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
+ mCallback.onClientFinished(this, false /* success */);
}
@Override
@@ -192,5 +195,8 @@
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
}
+
+ UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
+ mCallback.onClientFinished(this, false /* success */);
}
}
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 b0a662b..2419873 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -28148,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/tracing/TracingServiceProxy.java b/services/core/java/com/android/server/tracing/TracingServiceProxy.java
index 8f22748..ff2f08b 100644
--- a/services/core/java/com/android/server/tracing/TracingServiceProxy.java
+++ b/services/core/java/com/android/server/tracing/TracingServiceProxy.java
@@ -20,6 +20,7 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Binder;
import android.os.UserHandle;
import android.tracing.ITracingServiceProxy;
import android.util.Log;
@@ -30,6 +31,8 @@
* TracingServiceProxy is the system_server intermediary between the Perfetto tracing daemon and the
* system tracing app Traceur.
*
+ * Access to this service is restricted via SELinux. Normal apps do not have access.
+ *
* @hide
*/
public class TracingServiceProxy extends SystemService {
@@ -87,11 +90,15 @@
intent.setAction(INTENT_ACTION_NOTIFY_SESSION_STOPPED);
}
+ final long identity = Binder.clearCallingIdentity();
try {
mContext.startForegroundServiceAsUser(intent, UserHandle.SYSTEM);
} catch (RuntimeException e) {
Log.e(TAG, "Failed to notifyTraceSessionEnded", e);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
+
} catch (NameNotFoundException e) {
Log.e(TAG, "Failed to locate Traceur", e);
}
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/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index c7cf4b0..3dbc517 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -5492,6 +5492,14 @@
}
boolean updateDisplayOverrideConfigurationLocked() {
+ // Preemptively cancel the running recents animation -- SysUI can't currently handle this
+ // case properly since the signals it receives all happen post-change
+ final RecentsAnimationController recentsAnimationController =
+ mWmService.getRecentsAnimationController();
+ if (recentsAnimationController != null) {
+ recentsAnimationController.cancelAnimationForDisplayChange();
+ }
+
Configuration values = new Configuration();
computeScreenConfiguration(values);
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index c8f2777..73d6cec 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -480,6 +480,16 @@
return false;
}
+ // Preemptively cancel the running recents animation -- SysUI can't currently handle this
+ // case properly since the signals it receives all happen post-change. We do this earlier
+ // in the rotation flow, since DisplayContent.updateDisplayOverrideConfigurationLocked seems
+ // to happen too late.
+ final RecentsAnimationController recentsAnimationController =
+ mService.getRecentsAnimationController();
+ if (recentsAnimationController != null) {
+ recentsAnimationController.cancelAnimationForDisplayChange();
+ }
+
final Transition t = (useShellTransitions
&& !mService.mAtmService.getTransitionController().isCollecting())
? mService.mAtmService.getTransitionController().createTransition(TRANSIT_CHANGE)
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 5362771..a7e6335 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -221,7 +221,7 @@
final ArraySet<Task> tasks = Sets.newArraySet(task);
snapshotController.snapshotTasks(tasks);
snapshotController.addSkipClosingAppSnapshotTasks(tasks);
- return snapshotController.getSnapshot(taskId, 0 /* userId */,
+ return snapshotController.getSnapshot(taskId, task.mUserId,
false /* restoreFromDisk */, false /* isLowResolution */);
}
}
@@ -353,18 +353,23 @@
@Override
public void cleanupScreenshot() {
- synchronized (mService.mGlobalLock) {
- if (mRecentScreenshotAnimator != null) {
- mRecentScreenshotAnimator.cancelAnimation();
- mRecentScreenshotAnimator = null;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mService.mGlobalLock) {
+ if (mRecentScreenshotAnimator != null) {
+ mRecentScreenshotAnimator.cancelAnimation();
+ mRecentScreenshotAnimator = null;
+ }
}
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
}
@Override
public void setWillFinishToHome(boolean willFinishToHome) {
synchronized (mService.getWindowManagerLock()) {
- mWillFinishToHome = willFinishToHome;
+ RecentsAnimationController.this.setWillFinishToHome(willFinishToHome);
}
}
@@ -513,7 +518,6 @@
|| config.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
}
-
@VisibleForTesting
AnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible) {
return addAnimation(task, isRecentTaskInvisible, false /* hidden */,
@@ -816,6 +820,18 @@
cancelAnimation(REORDER_KEEP_IN_PLACE, screenshot, "rootTaskOrderChanged");
}
+ /**
+ * If there is a recents animation running, we need to cancel the animation and snapshot the
+ * tasks before the change (to ensure they are captured at the right configuration)
+ */
+ public void cancelAnimationForDisplayChange() {
+ if (mCanceled) {
+ return;
+ }
+ cancelAnimation(mWillFinishToHome ? REORDER_MOVE_TO_TOP : REORDER_MOVE_TO_ORIGINAL_POSITION,
+ true /* screenshot */, "cancelAnimationForDisplayChange");
+ }
+
private void cancelAnimation(@ReorderMode int reorderMode, boolean screenshot, String reason) {
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "cancelAnimation(): reason=%s", reason);
synchronized (mService.getWindowManagerLock()) {
@@ -826,7 +842,7 @@
mService.mH.removeCallbacks(mFailsafeRunnable);
mCanceled = true;
- if (screenshot) {
+ if (screenshot && !mPendingAnimations.isEmpty()) {
// Screen shot previous task when next task starts transition and notify the runner.
// We will actually finish the animation once the runner calls cleanUpScreenshot().
final Task task = mPendingAnimations.get(0).mTask;
@@ -853,6 +869,11 @@
}
}
+ @VisibleForTesting
+ void setWillFinishToHome(boolean willFinishToHome) {
+ mWillFinishToHome = willFinishToHome;
+ }
+
/**
* Cancel recents animation when the next app transition starts.
* <p>
@@ -905,7 +926,8 @@
return null;
}
- final TaskScreenshotAnimatable animatable = new TaskScreenshotAnimatable(mService.mSurfaceControlFactory, task,
+ final TaskScreenshotAnimatable animatable = new TaskScreenshotAnimatable(
+ mService.mSurfaceControlFactory, task,
new SurfaceControl.ScreenshotHardwareBuffer(taskSnapshot.getHardwareBuffer(),
taskSnapshot.getColorSpace(), false /* containsSecureLayers */));
mRecentScreenshotAnimator = new SurfaceAnimator(
@@ -1006,7 +1028,16 @@
@Override
public void binderDied() {
- cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "binderDied");
+ if (!mCanceled) {
+ cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "binderDied");
+ } else {
+ synchronized (mService.getWindowManagerLock()) {
+ if (mRecentScreenshotAnimator != null) {
+ mRecentScreenshotAnimator.cancelAnimation();
+ mRecentScreenshotAnimator = null;
+ }
+ }
+ }
synchronized (mService.getWindowManagerLock()) {
// Clear associated input consumers on runner death
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..bf0ed71 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -90,7 +90,7 @@
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.provider.Settings;
+import android.os.UserManager;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
import android.service.notification.ConversationChannelWrapper;
@@ -137,6 +137,7 @@
@RunWith(AndroidJUnit4.class)
public class PreferencesHelperTest extends UiServiceTestCase {
private static final int UID_N_MR1 = 0;
+ private static final int UID_HEADLESS = 1000000;
private static final UserHandle USER = UserHandle.of(0);
private static final int UID_O = 1111;
private static final int UID_P = 2222;
@@ -1495,11 +1496,13 @@
@Test
public void testCreateAndDeleteCanChannelsBypassDnd() throws Exception {
+ int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1;
+
// create notification channel that can't bypass dnd
// expected result: areChannelsBypassingDnd = false
// setNotificationPolicy isn't called since areChannelsBypassingDnd was already false
NotificationChannel channel = new NotificationChannel("id1", "name1", IMPORTANCE_LOW);
- mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
+ mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false);
assertFalse(mHelper.areChannelsBypassingDnd());
verify(mMockZenModeHelper, never()).setNotificationPolicy(any());
resetZenModeHelper();
@@ -1508,18 +1511,18 @@
// expected result: areChannelsBypassingDnd = true
NotificationChannel channel2 = new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
channel2.setBypassDnd(true);
- mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, true);
+ mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true);
assertTrue(mHelper.areChannelsBypassingDnd());
verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any());
resetZenModeHelper();
// delete channels
- mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId());
+ mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel.getId());
assertTrue(mHelper.areChannelsBypassingDnd()); // channel2 can still bypass DND
verify(mMockZenModeHelper, never()).setNotificationPolicy(any());
resetZenModeHelper();
- mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId());
+ mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel2.getId());
assertFalse(mHelper.areChannelsBypassingDnd());
verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any());
resetZenModeHelper();
@@ -1527,11 +1530,13 @@
@Test
public void testUpdateCanChannelsBypassDnd() throws Exception {
+ int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1;
+
// create notification channel that can't bypass dnd
// expected result: areChannelsBypassingDnd = false
// setNotificationPolicy isn't called since areChannelsBypassingDnd was already false
NotificationChannel channel = new NotificationChannel("id1", "name1", IMPORTANCE_LOW);
- mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
+ mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false);
assertFalse(mHelper.areChannelsBypassingDnd());
verify(mMockZenModeHelper, never()).setNotificationPolicy(any());
resetZenModeHelper();
@@ -1539,7 +1544,7 @@
// update channel so it CAN bypass dnd:
// expected result: areChannelsBypassingDnd = true
channel.setBypassDnd(true);
- mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true);
+ mHelper.updateNotificationChannel(PKG_N_MR1, uid, channel, true);
assertTrue(mHelper.areChannelsBypassingDnd());
verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any());
resetZenModeHelper();
@@ -1547,7 +1552,7 @@
// update channel so it can't bypass dnd:
// expected result: areChannelsBypassingDnd = false
channel.setBypassDnd(false);
- mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true);
+ mHelper.updateNotificationChannel(PKG_N_MR1, uid, channel, true);
assertFalse(mHelper.areChannelsBypassingDnd());
verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any());
resetZenModeHelper();
@@ -3333,6 +3338,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/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 39a59c9..afd0ecf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -655,6 +655,36 @@
assertFalse(win1.mHasSurface);
}
+ @Test
+ public void testCancelForRotation_ReorderToTop() throws Exception {
+ mWm.setRecentsAnimationController(mController);
+ final ActivityRecord activity = createActivityRecord(mDefaultDisplay);
+ final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, activity, "win1");
+ activity.addWindow(win1);
+
+ mController.addAnimation(activity.getTask(), false /* isRecentTaskInvisible */);
+ mController.setWillFinishToHome(true);
+ mController.cancelAnimationForDisplayChange();
+
+ verify(mMockRunner).onAnimationCanceled(any());
+ verify(mAnimationCallbacks).onAnimationFinished(REORDER_MOVE_TO_TOP, false);
+ }
+
+ @Test
+ public void testCancelForRotation_ReorderToOriginalPosition() throws Exception {
+ mWm.setRecentsAnimationController(mController);
+ final ActivityRecord activity = createActivityRecord(mDefaultDisplay);
+ final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, activity, "win1");
+ activity.addWindow(win1);
+
+ mController.addAnimation(activity.getTask(), false /* isRecentTaskInvisible */);
+ mController.setWillFinishToHome(false);
+ mController.cancelAnimationForDisplayChange();
+
+ verify(mMockRunner).onAnimationCanceled(any());
+ verify(mAnimationCallbacks).onAnimationFinished(REORDER_MOVE_TO_ORIGINAL_POSITION, false);
+ }
+
private ActivityRecord createHomeActivity() {
final ActivityRecord homeActivity = new ActivityBuilder(mWm.mAtmService)
.setParentTask(mRootHomeTask)
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);
+ }
}